blob: b1286b9c683ce25af445e96a010c8c8c3a42aea0 [file] [log] [blame]
#!/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 optparse
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
# pylint: disable=W0212,R0904
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.StubOutWithMock(os, 'readlink')
os.readlink(mox.IgnoreArg()).AndReturn('/some/path')
self.mox.ReplayAll()
self.assertFalse('CHROMEOS_OFFICIAL' in os.environ)
cbuildbot.SimpleBuilder(self.bot_id,
self.options,
self.build_config).Run()
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.StubOutWithMock(os, 'readlink')
os.readlink(mox.IgnoreArg()).AndReturn('/some/path')
self.mox.ReplayAll()
self.assertFalse('CHROMEOS_OFFICIAL' in os.environ)
cbuildbot.SimpleBuilder(self.bot_id,
self.options,
self.build_config).Run()
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()
def testBuildBotWithBadChromeRevOption(self):
"""chrome_rev can't be passed an invalid option after chrome_root."""
args = [
'--buildroot=/tmp',
'--chrome_root=.',
'--chrome_rev=%s' % constants.CHROME_REV_TOT,
self._X86_PREFLIGHT]
self.mox.StubOutWithMock(cros_lib, 'Die')
cros_lib.Die(mox.IgnoreArg()).AndRaise(Exception)
self.mox.ReplayAll()
(options, args) = self.parser.parse_args(args=args)
self.assertRaises(Exception, cbuildbot._PostParseCheck, options)
self.mox.VerifyAll()
def testBuildBotWithBadChromeRootOption(self):
"""chrome_root can't get passed after non-local chrome_rev."""
args = [
'--buildroot=/tmp',
'--chrome_rev=%s' % constants.CHROME_REV_TOT,
'--chrome_root=.',
self._X86_PREFLIGHT]
self.mox.StubOutWithMock(cros_lib, 'Die')
cros_lib.Die(mox.IgnoreArg()).AndRaise(Exception)
self.mox.ReplayAll()
(options, args) = self.parser.parse_args(args=args)
self.assertRaises(Exception, cbuildbot._PostParseCheck, options)
self.mox.VerifyAll()
def testBuildBotWithBadChromeRevOptionLocal(self):
"""chrome_rev can't be local without chrome_root."""
args = [
'--buildroot=/tmp',
'--chrome_rev=%s' % constants.CHROME_REV_LOCAL,
self._X86_PREFLIGHT]
self.mox.StubOutWithMock(cros_lib, 'Die')
cros_lib.Die(mox.IgnoreArg()).AndRaise(Exception)
self.mox.ReplayAll()
(options, args) = self.parser.parse_args(args=args)
self.assertRaises(Exception, cbuildbot._PostParseCheck, options)
self.mox.VerifyAll()
def testBuildBotWithGoodChromeRootOption(self):
"""chrome_root can be set without chrome_rev."""
args = [
'--buildroot=/tmp',
'--chrome_root=.',
self._X86_PREFLIGHT]
self.mox.StubOutWithMock(cros_lib, 'Die')
self.mox.ReplayAll()
(options, args) = self.parser.parse_args(args=args)
cbuildbot._PostParseCheck(options)
self.mox.VerifyAll()
self.assertEquals(options.chrome_rev, constants.CHROME_REV_LOCAL)
self.assertNotEquals(options.chrome_root, None)
def testBuildBotWithGoodChromeRevAndRootOption(self):
"""chrome_rev can get reset around chrome_root."""
args = [
'--buildroot=/tmp',
'--chrome_rev=%s' % constants.CHROME_REV_LATEST,
'--chrome_rev=%s' % constants.CHROME_REV_STICKY,
'--chrome_rev=%s' % constants.CHROME_REV_TOT,
'--chrome_rev=%s' % constants.CHROME_REV_TOT,
'--chrome_rev=%s' % constants.CHROME_REV_STICKY,
'--chrome_rev=%s' % constants.CHROME_REV_LATEST,
'--chrome_rev=%s' % constants.CHROME_REV_LOCAL,
'--chrome_root=.',
'--chrome_rev=%s' % constants.CHROME_REV_TOT,
'--chrome_rev=%s' % constants.CHROME_REV_LOCAL,
self._X86_PREFLIGHT]
self.mox.StubOutWithMock(cros_lib, 'Die')
self.mox.ReplayAll()
(options, args) = self.parser.parse_args(args=args)
cbuildbot._PostParseCheck(options)
self.mox.VerifyAll()
self.assertEquals(options.chrome_rev, constants.CHROME_REV_LOCAL)
self.assertNotEquals(options.chrome_root, None)
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()