diff options
author | Bertrand SIMONNET <bsimonnet@chromium.org> | 2015-05-08 15:23:10 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-05-22 01:22:41 +0000 |
commit | bd26dcd846f53f42cbc5fe5870d2930dcf3d5a1a (patch) | |
tree | 7ad8320dcda49e213647c4aafef85623ffd62b2c | |
parent | 59996671e175ba87c68425e9f0bdbcd1ce335495 (diff) | |
download | chromite-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.py | 85 | ||||
l--------- | cli/brillo/brillo_test_unittest | 1 | ||||
-rw-r--r-- | cli/brillo/brillo_test_unittest.py | 104 | ||||
-rw-r--r-- | lib/chroot_util.py | 14 |
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) |