summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBertrand SIMONNET <bsimonnet@chromium.org>2015-05-08 15:23:10 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-05-22 01:22:41 +0000
commitbd26dcd846f53f42cbc5fe5870d2930dcf3d5a1a (patch)
tree7ad8320dcda49e213647c4aafef85623ffd62b2c
parent59996671e175ba87c68425e9f0bdbcd1ce335495 (diff)
downloadchromite-bd26dcd846f53f42cbc5fe5870d2930dcf3d5a1a.tar.gz
brillo test: Tool to run unittests.
BUG=brillo:1011 TEST=unittest. TEST=manual: `brillo test blueprints/helloworld_base.json helloworld` works. Change-Id: I41cb80bd61de56fc83f64c6d3173af42e366f1f8 Reviewed-on: https://chromium-review.googlesource.com/271831 Tested-by: Bertrand Simonnet <bsimonnet@chromium.org> Reviewed-by: Gilad Arnold <garnold@chromium.org> Commit-Queue: Bertrand Simonnet <bsimonnet@chromium.org>
-rw-r--r--cli/brillo/brillo_test.py85
l---------cli/brillo/brillo_test_unittest1
-rw-r--r--cli/brillo/brillo_test_unittest.py104
-rw-r--r--lib/chroot_util.py14
4 files changed, 199 insertions, 5 deletions
diff --git a/cli/brillo/brillo_test.py b/cli/brillo/brillo_test.py
new file mode 100644
index 000000000..11c78e49c
--- /dev/null
+++ b/cli/brillo/brillo_test.py
@@ -0,0 +1,85 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""brillo test: Run unit tests or integration tests."""
+
+from __future__ import print_function
+
+from chromite.cli import command
+from chromite.lib import blueprint_lib
+from chromite.lib import chroot_util
+from chromite.lib import commandline
+from chromite.lib import cros_build_lib
+from chromite.lib import cros_logging as logging
+from chromite.lib import portage_util
+from chromite.lib import workon_helper
+
+
+_UNITTEST_PREFIX = 'unittest:'
+
+
+@command.CommandDecorator('test')
+class TestCommand(command.CliCommand):
+ """Run tests for a given blueprint."""
+
+ def __init__(self, options):
+ super(TestCommand, self).__init__(options)
+ blueprint = blueprint_lib.Blueprint(self.options.blueprint)
+ self.sysroot = cros_build_lib.GetSysroot(blueprint.FriendlyName())
+
+ @classmethod
+ def AddParser(cls, parser):
+ super(cls, TestCommand).AddParser(parser)
+ parser.add_argument('blueprint', type='blueprint_path',
+ help='Blueprint to test.')
+ parser.add_argument('packages', nargs='+',
+ help='List of packages to test.')
+ parser.add_argument('--verbose', action='store_true',
+ help='Print the test output, even if the tests '
+ 'succeed.')
+
+ def _GetMatchingPackages(self, package_list):
+ """Match |package_list| to packages available on the system.
+
+ Args:
+ package_list: Package strings passed by the user.
+
+ Returns:
+ A tuple containing the set of packages that match an ebuild and the set of
+ packages that do not map to any ebuild.
+ """
+ packages = set(package_list)
+ helper = workon_helper.WorkonHelper(self.sysroot)
+ available_packages = set(helper.ListAtoms(use_all=True))
+ available_packages |= set(a.split('/')[1] for a in available_packages)
+
+ matching = packages & available_packages
+ return matching, packages - matching
+
+ def Run(self):
+ """Run the tests."""
+ self.options.Freeze()
+ commandline.RunInsideChroot(self)
+
+ packages, non_matching = self._GetMatchingPackages(self.options.packages)
+ if non_matching:
+ cros_build_lib.Die('No packages matching: %s', ' '.join(non_matching))
+
+ packages_with_tests = portage_util.PackagesWithTest(self.sysroot, packages)
+ packages_without_tests = packages - packages_with_tests
+ if packages_without_tests:
+ logging.warning('Ignored the following packages because they were '
+ 'missing tests:')
+ for p in packages_without_tests:
+ logging.warning(p)
+
+ if not packages_with_tests:
+ logging.error('Nothing to test.')
+ return
+
+ try:
+ chroot_util.RunUnittests(self.sysroot, packages_with_tests,
+ verbose=self.options.verbose)
+ except cros_build_lib.RunCommandError as e:
+ cros_build_lib.Die('Unit tests failed: %s' % e)
diff --git a/cli/brillo/brillo_test_unittest b/cli/brillo/brillo_test_unittest
new file mode 120000
index 000000000..ef3e37b67
--- /dev/null
+++ b/cli/brillo/brillo_test_unittest
@@ -0,0 +1 @@
+../../scripts/wrapper.py \ No newline at end of file
diff --git a/cli/brillo/brillo_test_unittest.py b/cli/brillo/brillo_test_unittest.py
new file mode 100644
index 000000000..302d71291
--- /dev/null
+++ b/cli/brillo/brillo_test_unittest.py
@@ -0,0 +1,104 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""This module tests the brillo test command."""
+
+from __future__ import print_function
+
+from chromite.cli import command_unittest
+from chromite.cli.brillo import brillo_test
+from chromite.lib import chroot_util
+from chromite.lib import cros_build_lib
+from chromite.lib import cros_test_lib
+from chromite.lib import portage_util
+from chromite.lib import workon_helper
+
+
+class FakeWorkonHelper(object):
+ """Fakes the workon helper module."""
+
+ def __init__(self, packages):
+ self._packages = packages
+
+ def ListAtoms(self, *_args, **_kwargs):
+ """Returns the list of packages available."""
+ return self._packages
+
+
+class MockTestCommand(command_unittest.MockCommand):
+ """Mock out the `brillo test` command."""
+ TARGET = 'chromite.cli.brillo.brillo_test.TestCommand'
+ TARGET_CLASS = brillo_test.TestCommand
+ COMMAND = 'test'
+
+
+class TestCommandTest(cros_test_lib.WorkspaceTestCase):
+ """Test the flow of TestCommand.Run()."""
+
+ _PACKAGES_WITH_TESTS = set(['chromeos-base/shill',
+ 'chromeos-base/metrics'])
+
+ _PACKAGES_WITHOUT_TESTS = set(['brillo-base/foo'])
+
+ def setUp(self):
+ """Patches objects."""
+ self.cmd_mock = None
+ self.run_unittests_mock = None
+ self.CreateWorkspace()
+ self.blueprint = self.CreateBlueprint()
+
+ def SetupCommandMock(self, cmd_args):
+ """Sets up the MockTestCommand."""
+ self.cmd_mock = MockTestCommand(cmd_args)
+ self.StartPatcher(self.cmd_mock)
+ fake_workon = FakeWorkonHelper(
+ list(self._PACKAGES_WITH_TESTS | self._PACKAGES_WITHOUT_TESTS))
+ self.PatchObject(workon_helper, 'WorkonHelper', return_value=fake_workon)
+ self.PatchObject(portage_util, 'PackagesWithTest',
+ side_effect=self._PackagesWithTests)
+ self.run_unittests_mock = self.PatchObject(chroot_util, 'RunUnittests')
+ self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
+
+ def _PackagesWithTests(self, _sysroot, packages):
+ """Fakes portage_util.PackagesWithTests."""
+ return packages & self._PACKAGES_WITH_TESTS
+
+ def RunCommandMock(self, *args, **kwargs):
+ """Sets up and runs the MockTestCommand."""
+ self.SetupCommandMock(*args, **kwargs)
+ self.cmd_mock.inst.Run()
+
+ def testMatchingPackages(self):
+ """Tests that we match the correct packages."""
+ self.SetupCommandMock([self.blueprint.path, 'foo'])
+ # Getting an unknown package.
+ unknown = set(['chromeos-base/bar'])
+ cmd = self.cmd_mock.inst
+ # pylint: disable=protected-access
+ self.assertEqual((set(), unknown),
+ cmd._GetMatchingPackages(unknown))
+
+ # Only the names are specified.
+ name_only = set(['foo', 'metrics'])
+ self.assertEqual((name_only, set()),
+ cmd._GetMatchingPackages(name_only))
+
+ # The full category/package_name is specified.
+ full_name = set(['chromeos-base/shill'])
+ self.assertEqual((full_name, set()),
+ cmd._GetMatchingPackages(full_name))
+
+ # Both known and unknown packages are passed.
+ self.assertEqual((name_only, unknown),
+ cmd._GetMatchingPackages(name_only | unknown))
+
+ def testExistingPackage(self):
+ """Tests that RunUnittests is called when the package is valid."""
+ self.RunCommandMock([self.blueprint.path, 'chromeos-base/shill'])
+ self.assertEqual(1, self.run_unittests_mock.call_count)
+
+ def testUnknownPackage(self):
+ """Tests that we don't do anything when the package is not valid."""
+ self.RunCommandMock([self.blueprint.path, 'brillo-base/foo'])
+ self.assertEqual(0, self.run_unittests_mock.call_count)
diff --git a/lib/chroot_util.py b/lib/chroot_util.py
index 34262aac7..420b98c3e 100644
--- a/lib/chroot_util.py
+++ b/lib/chroot_util.py
@@ -176,7 +176,7 @@ def InitializeSysroots(blueprint):
sysroot.UpdateToolchain()
-def RunUnittests(sysroot, packages, extra_env=None):
+def RunUnittests(sysroot, packages, extra_env=None, verbose=False):
"""Runs the unit tests for |packages|.
Args:
@@ -184,6 +184,7 @@ def RunUnittests(sysroot, packages, extra_env=None):
packages: List of packages to test.
extra_env: Python dictionary containing the extra environment variable to
pass to the build command.
+ verbose: If True, show the output from emerge, even when the tests succeed.
Raises:
RunCommandError if the unit tests failed.
@@ -194,8 +195,11 @@ def RunUnittests(sysroot, packages, extra_env=None):
'PKGDIR': os.path.join(sysroot, 'test-packages'),
})
- command = ([os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge'),
- '--sysroot=%s' % sysroot, '--nodeps', '--buildpkgonly'] +
- list(packages))
+ command = [os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge'),
+ '--sysroot=%s' % sysroot, '--nodeps', '--buildpkgonly']
+ if verbose:
+ command += ['--show-output']
- cros_build_lib.SudoRunCommand(command, extra_env=env)
+ command += list(packages)
+
+ cros_build_lib.SudoRunCommand(command, extra_env=env, mute_output=False)