| #!/usr/bin/python |
| |
| # Copyright (c) 2011 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 mox |
| import os |
| import shutil |
| import sys |
| import tempfile |
| import unittest |
| |
| import constants |
| sys.path.append(constants.SOURCE_ROOT) |
| import chromite.buildbot.cbuildbot as cbuildbot |
| import chromite.buildbot.cbuildbot_commands as commands |
| import chromite.buildbot.cbuildbot_config as config |
| import chromite.lib.cros_build_lib as cros_lib |
| |
| |
| class TestExitedException(Exception): |
| """Exception used by sys.exit() mock to halt execution.""" |
| pass |
| |
| class TestHaltedException(Exception): |
| """Exception used by mocks to halt execution without indicating failure.""" |
| pass |
| |
| class TestFailedException(Exception): |
| """Exception used by mocks to halt execution and indicate failure.""" |
| pass |
| |
| class RunBuildStagesTest(mox.MoxTestBase): |
| |
| def setUp(self): |
| mox.MoxTestBase.setUp(self) |
| self.buildroot = tempfile.mkdtemp() |
| # Always stub RunCommmand out as we use it in every method. |
| self.bot_id = 'x86-generic-pre-flight-queue' |
| self.build_config = config.config[self.bot_id] |
| self.build_config['master'] = False |
| self.build_config['important'] = False |
| |
| # Use the cbuildbot parser to create properties and populate default values. |
| self.parser = cbuildbot._CreateParser() |
| (self.options, _) = self.parser.parse_args(['-r', self.buildroot, |
| '--buildbot', '--debug']) |
| self.options.clean = False |
| self.options.resume = False |
| self.options.sync = False |
| self.options.build = False |
| self.options.uprev = False |
| self.options.tests = False |
| self.options.archive = False |
| self.options.remote_test_status = False |
| self.options.patches = None |
| self.options.prebuilts = False |
| |
| self.mox.StubOutWithMock(cbuildbot, '_GetChromiteTrackingBranch') |
| cbuildbot._GetChromiteTrackingBranch().AndReturn('master') |
| |
| def tearDown(self): |
| if os.path.exists(self.buildroot): |
| shutil.rmtree(self.buildroot) |
| |
| def testChromeosOfficialSet(self): |
| """Verify that CHROMEOS_OFFICIAL is set correctly.""" |
| |
| self.build_config['chromeos_official'] = True |
| |
| |
| |
| # Clean up before |
| if 'CHROMEOS_OFFICIAL' in os.environ: |
| del os.environ['CHROMEOS_OFFICIAL'] |
| |
| self.mox.ReplayAll() |
| |
| self.assertFalse('CHROMEOS_OFFICIAL' in os.environ) |
| |
| cbuildbot.RunBuildStages(self.bot_id, |
| self.options, |
| self.build_config) |
| |
| self.assertTrue('CHROMEOS_OFFICIAL' in os.environ) |
| |
| self.mox.VerifyAll() |
| |
| # Clean up after the test |
| if 'CHROMEOS_OFFICIAL' in os.environ: |
| del os.environ['CHROMEOS_OFFICIAL'] |
| |
| def testChromeosOfficialNotSet(self): |
| """Verify that CHROMEOS_OFFICIAL is not always set.""" |
| |
| self.build_config['chromeos_official'] = False |
| |
| # Clean up before |
| if 'CHROMEOS_OFFICIAL' in os.environ: |
| del os.environ['CHROMEOS_OFFICIAL'] |
| |
| self.mox.ReplayAll() |
| |
| self.assertFalse('CHROMEOS_OFFICIAL' in os.environ) |
| |
| cbuildbot.RunBuildStages(self.bot_id, |
| self.options, |
| self.build_config) |
| |
| self.assertFalse('CHROMEOS_OFFICIAL' in os.environ) |
| |
| self.mox.VerifyAll() |
| |
| # Clean up after the test |
| if 'CHROMEOS_OFFICIAL' in os.environ: |
| del os.environ['CHROMEOS_OFFICIAL'] |
| |
| |
| class InterfaceTest(mox.MoxTestBase): |
| |
| _X86_PREFLIGHT = 'x86-generic-pre-flight-queue' |
| _BUILD_ROOT = '/b/test_build1' |
| def setUp(self): |
| mox.MoxTestBase.setUp(self) |
| self.parser = cbuildbot._CreateParser() |
| |
| def testDebugBuildBotSetByDefault(self): |
| """Test that debug and buildbot flags are set by default.""" |
| args = ['-r', self._BUILD_ROOT, self._X86_PREFLIGHT] |
| (options, args) = self.parser.parse_args(args=args) |
| self.assertEquals(options.debug, True) |
| self.assertEquals(options.buildbot, False) |
| |
| def testBuildBotOption(self): |
| """Test that --buildbot option unsets debug flag.""" |
| args = ['-r', self._BUILD_ROOT, '--buildbot', self._X86_PREFLIGHT] |
| (options, args) = self.parser.parse_args(args=args) |
| self.assertEquals(options.debug, False) |
| self.assertEquals(options.buildbot, True) |
| |
| def testBuildBotWithDebugOption(self): |
| """Test that --debug option overrides --buildbot option.""" |
| args = ['-r', self._BUILD_ROOT, '--buildbot', '--debug', |
| self._X86_PREFLIGHT] |
| (options, args) = self.parser.parse_args(args=args) |
| self.assertEquals(options.debug, True) |
| self.assertEquals(options.buildbot, True) |
| |
| def testBuildBotWithoutProfileOption(self): |
| """Test that no --profile option gets defaulted.""" |
| args = ['--buildbot', self._X86_PREFLIGHT] |
| (options, args) = self.parser.parse_args(args=args) |
| self.assertEquals(options.profile, None) |
| |
| def testBuildBotWithProfileOption(self): |
| """Test that --profile option gets parsed.""" |
| args = ['--buildbot', '--profile', 'carp', self._X86_PREFLIGHT] |
| (options, args) = self.parser.parse_args(args=args) |
| self.assertEquals(options.profile, 'carp') |
| |
| def testValidateClobberUserDeclines_1(self): |
| """Test case where user declines in prompt.""" |
| self.mox.StubOutWithMock(os.path, 'exists') |
| self.mox.StubOutWithMock(commands, 'GetInput') |
| |
| os.path.exists(self._BUILD_ROOT).AndReturn(True) |
| commands.GetInput(mox.IgnoreArg()).AndReturn('No') |
| |
| self.mox.ReplayAll() |
| self.assertFalse(commands.ValidateClobber(self._BUILD_ROOT)) |
| self.mox.VerifyAll() |
| |
| def testValidateClobberUserDeclines_2(self): |
| """Test case where user does not enter the full 'yes' pattern.""" |
| self.mox.StubOutWithMock(os.path, 'exists') |
| self.mox.StubOutWithMock(commands, 'GetInput') |
| |
| os.path.exists(self._BUILD_ROOT).AndReturn(True) |
| commands.GetInput(mox.IgnoreArg()).AndReturn('y') |
| |
| self.mox.ReplayAll() |
| self.assertFalse(commands.ValidateClobber(self._BUILD_ROOT)) |
| self.mox.VerifyAll() |
| |
| def testValidateClobberProtectRunningChromite(self): |
| """User should not be clobbering our own source.""" |
| self.mox.StubOutWithMock(cros_lib, 'Die') |
| cwd = os.path.dirname(os.path.realpath(__file__)) |
| buildroot = os.path.dirname(cwd) |
| cros_lib.Die(mox.IgnoreArg()).AndRaise(Exception) |
| self.mox.ReplayAll() |
| self.assertRaises(Exception, commands.ValidateClobber, buildroot) |
| self.mox.VerifyAll() |
| |
| |
| class FullInterfaceTest(unittest.TestCase): |
| """Tests that run the cbuildbot.main() function directly. |
| |
| Don't inherit from MoxTestBase since it runs VerifyAll() at the end of every |
| test which we don't want. |
| """ |
| _BUILD_ROOT = '/b/test_build1' |
| |
| def setUp(self): |
| def fake_real_path(path): |
| """Used to mock out os.path.realpath""" |
| if path == FullInterfaceTest._BUILD_ROOT: |
| return path |
| else: |
| raise TestFailedException('Unexpected os.path.realpath(%s) call' % path) |
| |
| self.mox = mox.Mox() |
| |
| # Create the parser before we stub out os.path.exists() - which the parser |
| # creation code actually uses. |
| parser = cbuildbot._CreateParser() |
| |
| # Stub out all relevant methods regardless of whether they are called in the |
| # specific test case. We can do this because we don't run VerifyAll() at |
| # the end of every test. |
| self.mox.StubOutWithMock(parser, 'error') |
| self.mox.StubOutWithMock(cbuildbot.os.path, 'exists') |
| self.mox.StubOutWithMock(cros_lib, 'IsInsideChroot') |
| self.mox.StubOutWithMock(cbuildbot, '_CreateParser') |
| self.mox.StubOutWithMock(sys, 'exit') |
| self.mox.StubOutWithMock(commands, 'GetInput') |
| self.mox.StubOutWithMock(cros_lib, 'FindRepoDir') |
| self.mox.StubOutWithMock(cbuildbot, '_RunBuildStagesWrapper') |
| self.mox.StubOutWithMock(cbuildbot, '_RunBuildStagesWithSudoProcess') |
| self.mox.StubOutWithMock(cbuildbot.os.path, 'realpath') |
| |
| cbuildbot.os.path.realpath = fake_real_path |
| parser.error(mox.IgnoreArg()).InAnyOrder().AndRaise(TestExitedException()) |
| cros_lib.IsInsideChroot().InAnyOrder().AndReturn(False) |
| cbuildbot._CreateParser().InAnyOrder().AndReturn(parser) |
| sys.exit(mox.IgnoreArg()).InAnyOrder().AndRaise(TestExitedException()) |
| cros_lib.FindRepoDir().InAnyOrder().AndReturn('/b/test_build1/.repo') |
| cbuildbot._RunBuildStagesWrapper( |
| mox.IgnoreArg(), |
| mox.IgnoreArg(), |
| mox.IgnoreArg()).InAnyOrder().AndReturn(True) |
| cbuildbot._RunBuildStagesWithSudoProcess( |
| mox.IgnoreArg(), |
| mox.IgnoreArg(), |
| mox.IgnoreArg()).InAnyOrder().AndReturn(True) |
| |
| self.external_marker = ('/b/trybot/.trybot') |
| self.internal_marker = ('/b/trybot-internal/.trybot') |
| |
| def tearDown(self): |
| self.mox.UnsetStubs() |
| |
| def testDontInferBuildrootForBuildBotRuns(self): |
| """Test that we don't infer buildroot if run with --buildbot option.""" |
| self.mox.ReplayAll() |
| self.assertRaises(TestExitedException, cbuildbot.main, |
| ['--buildbot', 'x86-generic-pre-flight-queue']) |
| |
| def testInferExternalBuildRoot(self): |
| """Test that we default to correct buildroot for external config.""" |
| self.mox.StubOutWithMock(cbuildbot, '_ConfirmBuildRoot') |
| (cbuildbot._ConfirmBuildRoot(mox.IgnoreArg()).InAnyOrder() |
| .AndRaise(TestHaltedException())) |
| os.path.exists(self.external_marker).InAnyOrder().AndReturn(False) |
| |
| self.mox.ReplayAll() |
| self.assertRaises(TestHaltedException, cbuildbot.main, |
| ['x86-generic-pre-flight-queue']) |
| |
| def testInferInternalBuildRoot(self): |
| """Test that we default to correct buildroot for internal config.""" |
| self.mox.StubOutWithMock(cbuildbot, '_ConfirmBuildRoot') |
| (cbuildbot._ConfirmBuildRoot(mox.IgnoreArg()).InAnyOrder() |
| .AndRaise(TestHaltedException())) |
| os.path.exists(self.internal_marker).InAnyOrder().AndReturn(False) |
| |
| self.mox.ReplayAll() |
| self.assertRaises(TestHaltedException, cbuildbot.main, |
| ['x86-mario-pre-flight-queue']) |
| |
| def testInferBuildRootPromptNo(self): |
| """Test that a 'no' answer on the prompt halts execution.""" |
| os.path.exists(self.external_marker).InAnyOrder().AndReturn(False) |
| commands.GetInput(mox.IgnoreArg()).InAnyOrder().AndReturn('no') |
| |
| self.mox.ReplayAll() |
| self.assertRaises(TestExitedException, cbuildbot.main, |
| ['x86-generic-pre-flight-queue']) |
| |
| def testInferBuildRootExists(self): |
| """Test that we don't prompt the user if buildroot already exists.""" |
| os.path.exists(self.external_marker).InAnyOrder().AndReturn(True) |
| (commands.GetInput(mox.IgnoreArg()).InAnyOrder() |
| .AndRaise(TestFailedException())) |
| |
| self.mox.ReplayAll() |
| cbuildbot.main(['x86-generic-pre-flight-queue']) |
| |
| def testValidateClobberForClobberOption(self): |
| """Test that we ask for clobber confirmation for trybot runs.""" |
| self.mox.StubOutWithMock(commands, 'ValidateClobber') |
| commands.ValidateClobber(self._BUILD_ROOT) |
| self.mox.ReplayAll() |
| cbuildbot.main(['-r', self._BUILD_ROOT, '--clobber', |
| 'x86-generic-pre-flight-queue']) |
| |
| def testNoClobberConfirmationForBuildBotBuilds(self): |
| """Test that we don't ask for clobber confirmation for --buildbot runs.""" |
| self.mox.StubOutWithMock(commands, 'ValidateClobber') |
| self.mox.ReplayAll() |
| cbuildbot.main(['-r', self._BUILD_ROOT, '--clobber', '--buildbot', |
| 'x86-generic-pre-flight-queue']) |
| |
| def testBuildbotDiesInChroot(self): |
| """Buildbot should quit if run inside a chroot.""" |
| # Need to do this since a cros_lib.IsInsideChroot() call is already queued |
| # up in setup() and we can't Reset() an individual mock. |
| new_is_inside_chroot = self.mox.CreateMockAnything() |
| new_is_inside_chroot().InAnyOrder().AndReturn(True) |
| cros_lib.IsInsideChroot = new_is_inside_chroot |
| self.mox.ReplayAll() |
| self.assertRaises(TestExitedException, cbuildbot.main, |
| ['-r', self._BUILD_ROOT, 'x86-generic-pre-flight-queue']) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |