Reland "AndroidService/MarkStable: Refactor commands.py function to service."

This is a reland of e355c1c23c8ac209d91885ef31a6dcc38fbc3cfd

Fixed some errors in the commands.py implementation of the endpoint
and added a test for the method to sanity check it.

BUG=chromium:956244
TEST=run_tests

Original change's description:
> AndroidService/MarkStable: Refactor commands.py function to service.
>
> BUG=chromium:956244
> TEST=run_tests
>
> Change-Id: I3333e5cf5fa22cb290bb0cccb7bead98ce673ded
> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1682327
> Tested-by: Alex Klein <saklein@chromium.org>
> Reviewed-by: David Burger <dburger@chromium.org>
> Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
> Commit-Queue: Alex Klein <saklein@chromium.org>

Bug: chromium:956244
Change-Id: I3404f1f91ae148fc81549ef8e8cd6501958aa733
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1685412
Tested-by: Alex Klein <saklein@chromium.org>
Auto-Submit: Alex Klein <saklein@chromium.org>
Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
Commit-Queue: Alex Klein <saklein@chromium.org>
diff --git a/api/controller/android.py b/api/controller/android.py
index cdbb9aa..ced3dcc 100644
--- a/api/controller/android.py
+++ b/api/controller/android.py
@@ -10,12 +10,13 @@
 import os
 
 from chromite.api import validate
+from chromite.api.controller import controller_util
 from chromite.api.gen.chromite.api import android_pb2
-# TODO(crbug/904939): implement service/android.
-from chromite.cbuildbot import commands
+from chromite.lib import build_target_util
 from chromite.lib import constants
 from chromite.lib import osutils
 from chromite.lib import portage_util
+from chromite.service import packages
 
 
 ANDROIDPIN_MASK_PATH = os.path.join(constants.SOURCE_ROOT,
@@ -35,30 +36,31 @@
 
   Args:
     input_proto (MarkStableRequest): The input proto.
-    output_proto (MarkStableReSponse): The output proto.
+    output_proto (MarkStableResponse): The output proto.
   """
+  chroot = controller_util.ParseChroot(input_proto.chroot)
   tracking_branch = input_proto.tracking_branch
   package_name = input_proto.package_name
   android_build_branch = input_proto.android_build_branch
   android_version = input_proto.android_version
   android_gts_build_branch = input_proto.android_gts_build_branch
-  boards = input_proto.boards
-  buildroot = input_proto.buildroot
+
+  build_targets = []
+  for build_target in input_proto.build_targets:
+    build_targets.append(build_target_util.BuildTarget(build_target.name))
 
   # Assume success.
   output_proto.status = android_pb2.MARK_STABLE_STATUS_SUCCESS
-  # TODO(crbug/904939): This should move to service/android.py and the port
-  # should be finished.
   try:
-    android_atom_to_build = commands.MarkAndroidAsStable(
-        buildroot=buildroot,
+    android_atom_to_build = packages.uprev_android(
         tracking_branch=tracking_branch,
         android_package=package_name,
         android_build_branch=android_build_branch,
-        boards=boards,
+        chroot=chroot,
+        build_targets=build_targets,
         android_version=android_version,
         android_gts_build_branch=android_gts_build_branch)
-  except commands.AndroidIsPinnedUprevError as e:
+  except packages.AndroidIsPinnedUprevError as e:
     # If the uprev failed due to a pin, CI needs to unpin and retry.
     android_atom_to_build = e.new_android_atom
     output_proto.status = android_pb2.MARK_STABLE_STATUS_PINNED
@@ -81,5 +83,4 @@
     _input_proto (UnpinVersionRequest): The input proto. (not used.)
     _output_proto (google.protobuf.Empty): The output proto. (not used.)
   """
-
   osutils.SafeUnlink(ANDROIDPIN_MASK_PATH)
diff --git a/api/controller/android_unittest.py b/api/controller/android_unittest.py
index a67e26c..ea9ec7a 100644
--- a/api/controller/android_unittest.py
+++ b/api/controller/android_unittest.py
@@ -7,29 +7,31 @@
 
 from __future__ import print_function
 
+import mock
+
 from chromite.api.controller import android
 from chromite.api.gen.chromite.api import android_pb2
 from chromite.api.gen.chromiumos import common_pb2
-# TODO(crbug/904939): implement service/android.py
-from chromite.cbuildbot import commands
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
 from chromite.lib import osutils
+from chromite.service import packages as packages_service
+
 
 class MarkStableTest(cros_test_lib.MockTestCase):
   """Unittests for MarkStable."""
 
   def setUp(self):
-    self.command = self.PatchObject(commands, 'MarkAndroidAsStable')
+    self.uprev = self.PatchObject(packages_service, 'uprev_android')
 
     self.input_proto = android_pb2.MarkStableRequest()
     self.input_proto.tracking_branch = 'tracking-branch'
     self.input_proto.package_name = 'android-package-name'
     self.input_proto.android_build_branch = 'android_build_branch'
-    self.board1 = self.input_proto.boards.add()
+    self.board1 = self.input_proto.build_targets.add()
     self.board1.name = 'board1'
-    self.board2 = self.input_proto.boards.add()
+    self.board2 = self.input_proto.build_targets.add()
     self.board2.name = 'board2'
 
   def testFailsIfTrackingBranchMissing(self):
@@ -38,7 +40,7 @@
     output_proto = android_pb2.MarkStableResponse()
     with self.assertRaises(cros_build_lib.DieSystemExit):
       android.MarkStable(self.input_proto, output_proto)
-    self.command.assert_not_called()
+    self.uprev.assert_not_called()
 
   def testFailsIfPackageNameMissing(self):
     """Fails if package_name is missing."""
@@ -46,7 +48,7 @@
     output_proto = android_pb2.MarkStableResponse()
     with self.assertRaises(cros_build_lib.DieSystemExit):
       android.MarkStable(self.input_proto, output_proto)
-    self.command.assert_not_called()
+    self.uprev.assert_not_called()
 
   def testFailsIfAndroidBuildBranchMissing(self):
     """Fails if android_build_branch is missing."""
@@ -54,25 +56,25 @@
     output_proto = android_pb2.MarkStableResponse()
     with self.assertRaises(cros_build_lib.DieSystemExit):
       android.MarkStable(self.input_proto, output_proto)
-    self.command.assert_not_called()
+    self.uprev.assert_not_called()
 
   def testCallsCommandCorrectly(self):
     """Test that commands.MarkAndroidAsStable is called correctly."""
     output_proto = android_pb2.MarkStableResponse()
     self.input_proto.android_version = 'android-version'
     self.input_proto.android_gts_build_branch = 'gts-branch'
-    self.command.return_value = 'cat/android-1.2.3'
+    self.uprev.return_value = 'cat/android-1.2.3'
     atom = common_pb2.PackageInfo()
     atom.category = 'cat'
     atom.package_name = 'android'
     atom.version = '1.2.3'
     android.MarkStable(self.input_proto, output_proto)
-    self.command.assert_called_once_with(
-        buildroot=self.input_proto.buildroot,
+    self.uprev.assert_called_once_with(
         tracking_branch=self.input_proto.tracking_branch,
         android_package=self.input_proto.package_name,
         android_build_branch=self.input_proto.android_build_branch,
-        boards=self.input_proto.boards,
+        chroot=mock.ANY,
+        build_targets=mock.ANY,
         android_version=self.input_proto.android_version,
         android_gts_build_branch=self.input_proto.android_gts_build_branch)
     self.assertEqual(output_proto.android_atom, atom)
@@ -84,14 +86,14 @@
     output_proto = android_pb2.MarkStableResponse()
     self.input_proto.android_version = 'android-version'
     self.input_proto.android_gts_build_branch = 'gts-branch'
-    self.command.return_value = ''
+    self.uprev.return_value = ''
     android.MarkStable(self.input_proto, output_proto)
-    self.command.assert_called_once_with(
-        buildroot=self.input_proto.buildroot,
+    self.uprev.assert_called_once_with(
         tracking_branch=self.input_proto.tracking_branch,
         android_package=self.input_proto.package_name,
         android_build_branch=self.input_proto.android_build_branch,
-        boards=self.input_proto.boards,
+        chroot=mock.ANY,
+        build_targets=mock.ANY,
         android_version=self.input_proto.android_version,
         android_gts_build_branch=self.input_proto.android_gts_build_branch)
     self.assertEqual(output_proto.status,
@@ -102,18 +104,19 @@
     output_proto = android_pb2.MarkStableResponse()
     self.input_proto.android_version = 'android-version'
     self.input_proto.android_gts_build_branch = 'gts-branch'
-    self.command.side_effect = commands.AndroidIsPinnedUprevError('pin/xx-1.1')
+    self.uprev.side_effect = packages_service.AndroidIsPinnedUprevError(
+        'pin/xx-1.1')
     atom = common_pb2.PackageInfo()
     atom.category = 'pin'
     atom.package_name = 'xx'
     atom.version = '1.1'
     android.MarkStable(self.input_proto, output_proto)
-    self.command.assert_called_once_with(
-        buildroot=self.input_proto.buildroot,
+    self.uprev.assert_called_once_with(
         tracking_branch=self.input_proto.tracking_branch,
         android_package=self.input_proto.package_name,
         android_build_branch=self.input_proto.android_build_branch,
-        boards=self.input_proto.boards,
+        chroot=mock.ANY,
+        build_targets=mock.ANY,
         android_version=self.input_proto.android_version,
         android_gts_build_branch=self.input_proto.android_gts_build_branch)
     self.assertEqual(output_proto.android_atom, atom)