| #!/usr/bin/python |
| # Copyright (c) 2012 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. |
| |
| """Unittests for build stages.""" |
| |
| import contextlib |
| import os |
| import sys |
| |
| sys.path.insert(0, os.path.abspath('%s/../../..' % os.path.dirname(__file__))) |
| from chromite.cbuildbot import cbuildbot_config as config |
| from chromite.cbuildbot import cbuildbot_commands as commands |
| from chromite.cbuildbot import constants |
| from chromite.cbuildbot.stages import build_stages |
| from chromite.cbuildbot.stages import generic_stages_unittest |
| from chromite.lib import cros_build_lib |
| from chromite.lib import cros_build_lib_unittest |
| from chromite.lib import cros_test_lib |
| from chromite.lib import git |
| from chromite.lib import parallel |
| from chromite.lib import parallel_unittest |
| from chromite.lib import partial_mock |
| |
| from chromite.cbuildbot.stages.generic_stages_unittest import patch |
| from chromite.cbuildbot.stages.generic_stages_unittest import patches |
| from chromite.cbuildbot.stages.generic_stages_unittest import BuilderRunMock |
| |
| |
| # pylint: disable=W0212,R0901 |
| class InitSDKTest(generic_stages_unittest.RunCommandAbstractStageTest): |
| """Test building the SDK""" |
| |
| def setUp(self): |
| self.PatchObject(cros_build_lib, 'GetChrootVersion', return_value='12') |
| |
| def ConstructStage(self): |
| return build_stages.InitSDKStage(self._run) |
| |
| def testFullBuildWithExistingChroot(self): |
| """Tests whether we create chroots for full builds.""" |
| self._PrepareFull() |
| self._Run(dir_exists=True) |
| self.assertCommandContains(['cros_sdk']) |
| |
| def testBinBuildWithMissingChroot(self): |
| """Tests whether we create chroots when needed.""" |
| self._PrepareBin() |
| # Do not force chroot replacement in build config. |
| self._run._config.chroot_replace = False |
| self._Run(dir_exists=False) |
| self.assertCommandContains(['cros_sdk']) |
| |
| def testFullBuildWithMissingChroot(self): |
| """Tests whether we create chroots when needed.""" |
| self._PrepareFull() |
| self._Run(dir_exists=True) |
| self.assertCommandContains(['cros_sdk']) |
| |
| def testFullBuildWithNoSDK(self): |
| """Tests whether the --nosdk option works.""" |
| self._PrepareFull(extra_cmd_args=['--nosdk']) |
| self._Run(dir_exists=False) |
| self.assertCommandContains(['cros_sdk', '--bootstrap']) |
| |
| def testBinBuildWithExistingChroot(self): |
| """Tests whether the --nosdk option works.""" |
| self._PrepareFull(extra_cmd_args=['--nosdk']) |
| # Do not force chroot replacement in build config. |
| self._run._config.chroot_replace = False |
| self._Run(dir_exists=True) |
| self.assertCommandContains(['cros_sdk'], expected=False) |
| |
| |
| class SetupBoardTest(generic_stages_unittest.RunCommandAbstractStageTest): |
| """Test building the board""" |
| |
| def ConstructStage(self): |
| return build_stages.SetupBoardStage(self._run, self._current_board) |
| |
| def _RunFull(self, dir_exists=False): |
| """Helper for testing a full builder.""" |
| self._Run(dir_exists) |
| cmd = ['./setup_board', '--board=%s' % self._current_board, '--nousepkg'] |
| self.assertCommandContains(cmd, expected=not dir_exists) |
| cmd = ['./setup_board', '--skip_chroot_upgrade'] |
| self.assertCommandContains(cmd, expected=False) |
| |
| def testFullBuildWithProfile(self): |
| """Tests whether full builds add profile flag when requested.""" |
| self._PrepareFull(extra_config={'profile': 'foo'}) |
| self._RunFull(dir_exists=False) |
| self.assertCommandContains(['./setup_board', '--profile=foo']) |
| |
| def testFullBuildWithOverriddenProfile(self): |
| """Tests whether full builds add overridden profile flag when requested.""" |
| self._PrepareFull(extra_cmd_args=['--profile', 'smock']) |
| self._RunFull(dir_exists=False) |
| self.assertCommandContains(['./setup_board', '--profile=smock']) |
| |
| def testFullBuildWithLatestToolchain(self): |
| """Tests whether we use --nousepkg for creating the board""" |
| self._PrepareFull() |
| self._RunFull(dir_exists=False) |
| |
| def _RunBin(self, dir_exists): |
| """Helper for testing a binary builder.""" |
| self._Run(dir_exists) |
| self.assertCommandContains(['./setup_board']) |
| cmd = ['./setup_board', '--nousepkg'] |
| self.assertCommandContains(cmd, expected=self._run.options.latest_toolchain) |
| cmd = ['./setup_board', '--skip_chroot_upgrade'] |
| self.assertCommandContains(cmd, expected=False) |
| |
| def testBinBuildWithBoard(self): |
| """Tests whether we don't create the board when it's there.""" |
| self._PrepareBin() |
| self._RunBin(dir_exists=True) |
| |
| def testBinBuildWithMissingBoard(self): |
| """Tests whether we create the board when it's missing.""" |
| self._PrepareBin() |
| self._RunBin(dir_exists=False) |
| |
| def testBinBuildWithLatestToolchain(self): |
| """Tests whether we use --nousepkg for creating the board.""" |
| self._PrepareBin() |
| self._RunBin(dir_exists=False) |
| |
| def testSDKBuild(self): |
| """Tests whether we use --skip_chroot_upgrade for SDK builds.""" |
| extra_config = {'build_type': constants.CHROOT_BUILDER_TYPE} |
| self._PrepareFull(extra_config=extra_config) |
| self._Run(dir_exists=False) |
| self.assertCommandContains(['./setup_board', '--skip_chroot_upgrade']) |
| |
| |
| class UprevStageTest(generic_stages_unittest.AbstractStageTest): |
| """Tests for the UprevStage class.""" |
| |
| def setUp(self): |
| self.mox.StubOutWithMock(commands, 'UprevPackages') |
| |
| self._Prepare() |
| |
| def ConstructStage(self): |
| return build_stages.UprevStage(self._run) |
| |
| def testBuildRev(self): |
| """Uprevving the build without uprevving chrome.""" |
| self._run.config['uprev'] = True |
| commands.UprevPackages(self.build_root, self._boards, [], enter_chroot=True) |
| self.mox.ReplayAll() |
| self.RunStage() |
| self.mox.VerifyAll() |
| |
| def testNoRev(self): |
| """No paths are enabled.""" |
| self._run.config['uprev'] = False |
| self.mox.ReplayAll() |
| self.RunStage() |
| self.mox.VerifyAll() |
| |
| |
| class BuildPackagesStageTest(generic_stages_unittest.AbstractStageTest): |
| """Tests BuildPackagesStage.""" |
| |
| def setUp(self): |
| self._release_tag = None |
| |
| self.StartPatcher(BuilderRunMock()) |
| |
| def ConstructStage(self): |
| self._run.attrs.release_tag = self._release_tag |
| return build_stages.BuildPackagesStage(self._run, self._current_board) |
| |
| @contextlib.contextmanager |
| def RunStageWithConfig(self): |
| """Run the given config""" |
| try: |
| with cros_build_lib_unittest.RunCommandMock() as rc: |
| rc.SetDefaultCmdResult() |
| with cros_test_lib.OutputCapturer(): |
| with cros_test_lib.LoggingCapturer(): |
| self.RunStage() |
| |
| yield rc |
| |
| except AssertionError as ex: |
| msg = '%s failed the following test:\n%s' % (self._bot_id, ex) |
| raise AssertionError(msg) |
| |
| def RunTestsWithBotId(self, bot_id, options_tests=True): |
| """Test with the config for the specified bot_id.""" |
| self._Prepare(bot_id) |
| self._run.options.tests = options_tests |
| |
| with self.RunStageWithConfig() as rc: |
| cfg = self._run.config |
| rc.assertCommandContains(['./build_packages']) |
| rc.assertCommandContains(['./build_packages', '--skip_chroot_upgrade']) |
| rc.assertCommandContains(['./build_packages', '--nousepkg'], |
| expected=not cfg['usepkg_build_packages']) |
| build_tests = cfg['build_tests'] and self._run.options.tests |
| rc.assertCommandContains(['./build_packages', '--nowithautotest'], |
| expected=not build_tests) |
| |
| def testAllConfigs(self): |
| """Test all major configurations""" |
| task = self.RunTestsWithBotId |
| with parallel.BackgroundTaskRunner(task) as queue: |
| # Loop through all major configuration types and pick one from each. |
| for bot_type in config.CONFIG_TYPE_DUMP_ORDER: |
| for bot_id in config.config: |
| if bot_id.endswith(bot_type): |
| # Skip any config without a board, since those configs do not |
| # build packages. |
| cfg = config.config[bot_id] |
| if cfg.boards: |
| queue.put([bot_id]) |
| break |
| |
| def testNoTests(self): |
| """Test that self.options.tests = False works.""" |
| self.RunTestsWithBotId('x86-generic-paladin', options_tests=False) |
| |
| |
| class BuildImageStageMock(partial_mock.PartialMock): |
| """Partial mock for BuildImageStage.""" |
| |
| TARGET = 'chromite.cbuildbot.stages.build_stages.BuildImageStage' |
| ATTRS = ('_BuildImages', '_GenerateAuZip') |
| |
| def _BuildImages(self, *args, **kwargs): |
| with patches( |
| patch(os, 'symlink'), |
| patch(os, 'readlink', return_value='foo.txt')): |
| self.backup['_BuildImages'](*args, **kwargs) |
| |
| def _GenerateAuZip(self, *args, **kwargs): |
| with patch(git, 'ReinterpretPathForChroot', return_value='/chroot/path'): |
| self.backup['_GenerateAuZip'](*args, **kwargs) |
| |
| |
| class BuildImageStageTest(BuildPackagesStageTest): |
| """Tests BuildImageStage.""" |
| |
| def setUp(self): |
| self.StartPatcher(BuildImageStageMock()) |
| |
| def ConstructStage(self): |
| return build_stages.BuildImageStage(self._run, self._current_board) |
| |
| def RunTestsWithReleaseConfig(self, release_tag): |
| self._release_tag = release_tag |
| |
| with parallel_unittest.ParallelMock(): |
| with self.RunStageWithConfig() as rc: |
| cfg = self._run.config |
| cmd = ['./build_image', '--version=%s' % (self._release_tag or '')] |
| rc.assertCommandContains(cmd, expected=cfg['images']) |
| rc.assertCommandContains(['./image_to_vm.sh'], |
| expected=cfg['vm_tests']) |
| cmd = ['./build_library/generate_au_zip.py', '-o', '/chroot/path'] |
| rc.assertCommandContains(cmd, expected=cfg['images']) |
| |
| def RunTestsWithBotId(self, bot_id, options_tests=True): |
| """Test with the config for the specified bot_id.""" |
| release_tag = '0.0.1' |
| self._Prepare(bot_id) |
| self._run.options.tests = options_tests |
| self._run.attrs.release_tag = release_tag |
| |
| task = self.RunTestsWithReleaseConfig |
| steps = [lambda: task(tag) for tag in (None, release_tag)] |
| parallel.RunParallelSteps(steps) |
| |
| |
| if __name__ == '__main__': |
| cros_test_lib.main() |