chromite: Setup pipeline to post-process and upload orderfile.

In ArtifactStage, this patch adds script that call toolchain-utils
script to do post processing on generated orderfile and creates a tarball.
Then it uploads the results to a gs bucket. The changes all have unittests.

This patch only applies to orderfile-generate-toolchain builders, and
is written with the new build api.

BUG=chromium:950627
TEST=Unittests pass and build_api is tested individually.
Whole builder is tested and the log is at
https://ci.chromium.org/p/chromeos/builders/general/Try/b8910544771604484896

Change-Id: I4d42fb8591eaef7e54634dfab31c340dbd074f37
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1583077
Tested-by: Tiancong Wang <tcwang@google.com>
Reviewed-by: Alex Klein <saklein@chromium.org>
Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
Auto-Submit: Tiancong Wang <tcwang@google.com>
Commit-Queue: Tiancong Wang <tcwang@google.com>
diff --git a/api/controller/artifacts_unittest.py b/api/controller/artifacts_unittest.py
index 45df0eb..f0740a1 100644
--- a/api/controller/artifacts_unittest.py
+++ b/api/controller/artifacts_unittest.py
@@ -536,3 +536,94 @@
 
     # Make sure we've seen all of the expected files.
     self.assertFalse(expected_files)
+
+class BundleOrderfileGenerationArtifactsTestCase(BundleTempDirTestCase):
+  """Unittests for BundleOrderfileGenerationArtifacts."""
+
+  def setUp(self):
+    self.chroot_dir = os.path.join(self.tempdir, 'chroot_dir')
+    osutils.SafeMakedirs(self.chroot_dir)
+    temp_dir = os.path.join(self.chroot_dir, 'tmp')
+    osutils.SafeMakedirs(temp_dir)
+    self.output_dir = os.path.join(self.tempdir, 'output_dir')
+    osutils.SafeMakedirs(self.output_dir)
+    self.build_target = 'board'
+    self.chrome_version = 'chromeos-chrome-1.0'
+
+    self.does_not_exist = os.path.join(self.tempdir, 'does_not_exist')
+
+  def _GetRequest(self, chroot=None, build_target=None,
+                  output_dir=None, chrome_version=None):
+    """Helper to create a request message instance.
+
+    Args:
+      chroot (str): The chroot path.
+      build_target (str): The build target name.
+      output_dir (str): The output directory.
+      chrome_version (str): The chromeos-chrome version name.
+    """
+    return artifacts_pb2.BundleChromeOrderfileRequest(
+        build_target={'name': build_target},
+        chroot={'path': chroot},
+        output_dir=output_dir,
+        chrome_version=chrome_version
+    )
+
+  def _GetResponse(self):
+    return artifacts_pb2.BundleResponse()
+
+  def testNoBuildTarget(self):
+    """Test no build target fails."""
+    request = self._GetRequest(chroot=self.chroot_dir,
+                               output_dir=self.output_dir,
+                               chrome_version=self.chrome_version)
+    response = self._GetResponse()
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      artifacts.BundleOrderfileGenerationArtifacts(request, response)
+
+  def testNoChromeVersion(self):
+    """Test no Chrome version fails."""
+    request = self._GetRequest(chroot=self.chroot_dir,
+                               output_dir=self.output_dir,
+                               build_target=self.build_target)
+    response = self._GetResponse()
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      artifacts.BundleOrderfileGenerationArtifacts(request, response)
+
+  def testNoOutputDir(self):
+    """Test no output dir fails."""
+    request = self._GetRequest(chroot=self.chroot_dir,
+                               chrome_version=self.chrome_version,
+                               build_target=self.build_target)
+    response = self._GetResponse()
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      artifacts.BundleOrderfileGenerationArtifacts(request, response)
+
+  def testOutputDirDoesNotExist(self):
+    """Test output directory not existing fails."""
+    request = self._GetRequest(chroot=self.chroot_dir,
+                               chrome_version=self.chrome_version,
+                               build_target=self.build_target,
+                               output_dir=self.does_not_exist)
+    response = self._GetResponse()
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      artifacts.BundleOrderfileGenerationArtifacts(request, response)
+
+  def testOutputHandling(self):
+    """Test response output."""
+    files = [self.chrome_version+'.orderfile.tar.xz',
+             self.chrome_version+'.nm.tar.xz']
+    expected_files = [os.path.join(self.output_dir, f) for f in files]
+    self.PatchObject(artifacts_svc, 'BundleOrderfileGenerationArtifacts',
+                     return_value=expected_files)
+    request = self._GetRequest(chroot=self.chroot_dir,
+                               chrome_version=self.chrome_version,
+                               build_target=self.build_target,
+                               output_dir=self.output_dir)
+
+    response = self._GetResponse()
+
+    artifacts.BundleOrderfileGenerationArtifacts(request, response)
+
+    self.assertTrue(response.artifacts)
+    self.assertItemsEqual(expected_files, [a.path for a in response.artifacts])