Build API: Add UnitTest endpoint.
BUG=chromium:905030, b:130745732
TEST=manual, run_tests
CQ-DEPEND=CL:1577651
Change-Id: I420bb6a202cea2301e94aef440edf0330eaf617b
Reviewed-on: https://chromium-review.googlesource.com/1576063
Commit-Ready: Alex Klein <saklein@chromium.org>
Tested-by: Alex Klein <saklein@chromium.org>
Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
diff --git a/api/controller/test.py b/api/controller/test.py
index 04b1aaf..d38e10d 100644
--- a/api/controller/test.py
+++ b/api/controller/test.py
@@ -10,7 +10,15 @@
from __future__ import print_function
+import os
+
+from chromite.api.controller import controller_util
+from chromite.cbuildbot import commands
+from chromite.lib import constants
from chromite.lib import cros_build_lib
+from chromite.lib import failures_lib
+from chromite.lib import osutils
+from chromite.lib import portage_util
from chromite.lib import sysroot_lib
from chromite.service import test
@@ -33,3 +41,76 @@
cros_build_lib.Die('The provided sysroot does not exist.')
return 0 if test.DebugInfoTest(sysroot_path) else 1
+
+
+def BuildTargetUnitTest(input_proto, output_proto):
+ """Run a build target's ebuild unit tests."""
+ # Required args.
+ board = input_proto.build_target.name
+ result_path = input_proto.result_path
+
+ if not board:
+ cros_build_lib.Die('build_target.name is required.')
+ if not result_path:
+ cros_build_lib.Die('result_path is required.')
+
+ # Chroot handling.
+ chroot = input_proto.chroot.path
+ cache_dir = input_proto.chroot.cache_dir
+
+ chroot_args = []
+ if chroot:
+ chroot_args.extend(['--chroot', chroot])
+ else:
+ chroot = constants.DEFAULT_CHROOT_PATH
+
+ if cache_dir:
+ chroot_args.extend(['--cache_dir', cache_dir])
+
+ # TODO(crbug.com/954609) Service implementation.
+ extra_env = {'USE': 'chrome_internal'}
+ base_dir = os.path.join(chroot, 'tmp')
+ # The called code also sets the status file in some cases, but the hacky
+ # call makes it not always work, so set up our own just in case.
+ with osutils.TempDir(base_dir=base_dir) as tempdir:
+ full_sf_path = os.path.join(tempdir, 'status_file')
+ chroot_sf_path = full_sf_path.replace(chroot, '')
+ extra_env[constants.PARALLEL_EMERGE_STATUS_FILE_ENVVAR] = chroot_sf_path
+
+ try:
+ commands.RunUnitTests(constants.SOURCE_ROOT, board, extra_env=extra_env,
+ chroot_args=chroot_args)
+ except failures_lib.PackageBuildFailure as e:
+ # Add the failed packages.
+ for pkg in e.failed_packages:
+ cpv = portage_util.SplitCPV(pkg, strict=False)
+ package_info = output_proto.failed_packages.add()
+ controller_util.CPVToPackageInfo(cpv, package_info)
+
+ return 1
+ except failures_lib.BuildScriptFailure:
+ # Check our status file for failed packages in case the calling code's
+ # file didn't get set.
+ for cpv in portage_util.ParseParallelEmergeStatusFile(full_sf_path):
+ package_info = output_proto.failed_packages.add()
+ controller_util.CPVToPackageInfo(cpv, package_info)
+
+ return 1
+
+ tarball = _BuildUnittestTarball(chroot, board, result_path)
+ if tarball:
+ output_proto.tarball_path = tarball
+
+
+def _BuildUnittestTarball(chroot, board, result_path):
+ """Build the unittest tarball."""
+ tarball = 'unit_tests.tar'
+ tarball_path = os.path.join(result_path, tarball)
+
+ cwd = os.path.join(chroot, 'build', board, constants.UNITTEST_PKG_PATH)
+
+ result = cros_build_lib.CreateTarball(tarball_path, cwd, chroot=chroot,
+ compression=cros_build_lib.COMP_NONE,
+ error_code_ok=True)
+
+ return tarball_path if result.returncode == 0 else None