blob: 0848f55d866aec4a7eaf35f3b9d447080b0e203f [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 os
import shutil
import StringIO
import sys
import tempfile
import unittest
import constants
sys.path.append(constants.SOURCE_ROOT)
import chromite.buildbot.cbuildbot_config as config
import chromite.buildbot.cbuildbot_commands as commands
import chromite.buildbot.cbuildbot_stages as stages
import chromite.buildbot.manifest_version as manifest_version
import chromite.lib.cros_build_lib as cros_lib
class AbstractStageTest(mox.MoxTestBase):
"""Base class for tests that test a particular build stage.
Abstract base class that sets up the build config and options with some
default values for testing BuilderStage and its derivatives.
"""
TRACKING_BRANCH = 'ooga_booga'
def ConstructStage(self):
"""Returns an instance of the stage to be tested.
Implement in subclasses.
"""
raise NotImplementedError, "return an instance of stage to be tested"
def setUp(self):
mox.MoxTestBase.setUp(self)
# 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_root = '/fake_root'
self.url = 'fake_url'
self.build_config['git_url'] = self.url
self.options = self.mox.CreateMockAnything()
self.options.buildroot = self.build_root
self.options.debug = False
self.options.prebuilts = False
self.options.clobber = False
self.options.buildnumber = 1234
self.overlay = os.path.join(self.build_root,
'src/third_party/chromiumos-overlay')
stages.BuilderStage.rev_overlays = [self.overlay]
stages.BuilderStage.push_overlays = [self.overlay]
stages.BuilderStage.SetTrackingBranch(self.TRACKING_BRANCH)
self.mox.StubOutWithMock(os.path, 'isdir')
def RunStage(self):
"""Creates and runs an instance of the stage to be tested.
Requires ConstructStage() to be implemented.
Raises:
NotImplementedError: ConstructStage() was not implemented.
"""
# Stage construction is usually done as late as possible because the tests
# set up the build configuration and options used in constructing the stage.
stage = self.ConstructStage()
stage.Run()
class BuilderStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
def ConstructStage(self):
return stages.BuilderStage(self.bot_id, self.options, self.build_config)
def testGetPortageEnvVar(self):
"""Basic test case for _GetPortageEnvVar function."""
self.mox.StubOutWithMock(cros_lib, 'OldRunCommand')
envvar = 'EXAMPLE'
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
cros_lib.OldRunCommand(mox.And(mox.IsA(list), mox.In(envvar)),
cwd='%s/src/scripts' % self.build_root,
redirect_stdout=True, enter_chroot=True,
error_ok=True).AndReturn('RESULT\n')
self.mox.ReplayAll()
stage = self.ConstructStage()
board = self.build_config['board']
result = stage._GetPortageEnvVar(envvar, board)
self.mox.VerifyAll()
self.assertEqual(result, 'RESULT')
def testResolveOverlays(self):
self.mox.StubOutWithMock(cros_lib, 'RunCommand')
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
for _ in range(3):
output_obj = cros_lib.CommandResult()
output_obj.output = 'public1 public2\n'
cros_lib.RunCommand(
mox.And(mox.IsA(list), mox.In('--noprivate')),
print_cmd=False, redirect_stdout=True).AndReturn(output_obj)
output_obj = cros_lib.CommandResult()
output_obj.output = 'private1 private2\n'
cros_lib.RunCommand(
mox.And(mox.IsA(list), mox.In('--nopublic')),
print_cmd=False, redirect_stdout=True).AndReturn(output_obj)
self.mox.ReplayAll()
stages.OVERLAY_LIST_CMD = '/bin/true'
stage = self.ConstructStage()
public_overlays = ['public1', 'public2', self.overlay]
private_overlays = ['private1', 'private2']
self.assertEqual(stage._ResolveOverlays('public'), public_overlays)
self.assertEqual(stage._ResolveOverlays('private'), private_overlays)
self.assertEqual(stage._ResolveOverlays('both'),
public_overlays + private_overlays)
self.mox.VerifyAll()
class SyncStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
self.mox.StubOutWithMock(commands, 'PreFlightRinse')
def ConstructStage(self):
return stages.SyncStage(self.bot_id, self.options, self.build_config)
def testFullSync(self):
"""Tests whether we can perform a full sync with a missing .repo folder."""
self.mox.StubOutWithMock(commands, 'FullCheckout')
os.path.isdir(self.build_root + '/.repo').AndReturn(False)
os.path.isdir(self.build_root + '/.repo').AndReturn(False)
commands.FullCheckout(self.build_root, self.TRACKING_BRANCH,
url=self.url)
os.path.isdir(self.overlay).AndReturn(True)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testIncrementalSync(self):
"""Tests whether we can perform a standard incremental sync."""
self.mox.StubOutWithMock(commands, 'IncrementalCheckout')
self.mox.StubOutWithMock(stages.BuilderStage, '_GetPortageEnvVar')
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
board = self.build_config['board']
commands.PreFlightRinse(self.build_root, board,
[self.overlay])
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
stages.BuilderStage._GetPortageEnvVar(stages._FULL_BINHOST, board)
commands.IncrementalCheckout(self.build_root)
os.path.isdir(self.overlay).AndReturn(True)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class ManifestVersionedSyncStageTest(AbstractStageTest):
"""Tests the two (heavily related) stages ManifestVersionedSync, and
ManifestVersionedSyncCompleted.
"""
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
self.tmpdir = tempfile.mkdtemp()
self.source_repo = 'ssh://source/repo'
self.manifest_version_url = 'fake manifest url'
self.version_file = 'version-file.sh'
self.branch = 'master'
self.build_name = 'x86-generic'
self.incr_type = 'patch'
self.build_config['manifest_version'] = self.manifest_version_url
self.next_version = 'next_version'
self.manager = manifest_version.BuildSpecsManager(
self.tmpdir, self.source_repo, self.manifest_version_url, self.branch,
self.build_name, self.incr_type, dry_run=True)
def tearDown(self):
if os.path.exists(self.tmpdir): shutil.rmtree(self.tmpdir)
def testManifestVersionedSyncOnePartBranch(self):
"""Tests basic ManifestVersionedSyncStage with branch ooga_booga"""
self.mox.StubOutWithMock(manifest_version.BuildSpecsManager,
'GetNextBuildSpec')
self.mox.StubOutWithMock(commands, 'ManifestCheckout')
os.path.isdir(self.build_root + '/.repo').AndReturn(False)
self.manager.GetNextBuildSpec(stages.VERSION_FILE,
latest=True).AndReturn(self.next_version)
commands.ManifestCheckout(self.build_root,
self.TRACKING_BRANCH,
self.next_version,
url=self.url)
os.path.isdir('/fake_root/.repo').AndReturn(True)
os.path.isdir('/fake_root/src/third_party/'
'chromiumos-overlay').AndReturn(True)
self.mox.ReplayAll()
stage = stages.ManifestVersionedSyncStage(self.bot_id,
self.options,
self.build_config)
stage.Run()
self.mox.VerifyAll()
def testManifestVersionedSyncCompletedSuccess(self):
"""Tests basic ManifestVersionedSyncStageCompleted on success"""
stages.ManifestVersionedSyncStage.manifest_manager = self.manager
self.mox.StubOutWithMock(manifest_version.BuildSpecsManager, 'UpdateStatus')
os.path.isdir(self.build_root + '/.repo').AndReturn(False)
self.manager.UpdateStatus(success=True)
self.mox.ReplayAll()
stage = stages.ManifestVersionedSyncCompletionStage(self.bot_id,
self.options,
self.build_config,
success=True)
stage.Run()
self.mox.VerifyAll()
def testManifestVersionedSyncCompletedFailure(self):
"""Tests basic ManifestVersionedSyncStageCompleted on failure"""
stages.ManifestVersionedSyncStage.manifest_manager = self.manager
self.mox.StubOutWithMock(manifest_version.BuildSpecsManager, 'UpdateStatus')
os.path.isdir(self.build_root + '/.repo').AndReturn(False)
self.manager.UpdateStatus(success=False)
self.mox.ReplayAll()
stage = stages.ManifestVersionedSyncCompletionStage(self.bot_id,
self.options,
self.build_config,
success=False)
stage.Run()
self.mox.VerifyAll()
def testManifestVersionedSyncCompletedIncomplete(self):
"""Tests basic ManifestVersionedSyncStageCompleted on incomplete build."""
stages.ManifestVersionedSyncStage.manifest_manager = None
os.path.isdir(self.build_root + '/.repo').AndReturn(False)
self.mox.ReplayAll()
stage = stages.ManifestVersionedSyncCompletionStage(self.bot_id,
self.options,
self.build_config,
success=False)
stage.Run()
self.mox.VerifyAll()
class BuildBoardTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
def ConstructStage(self):
return stages.BuildBoardStage(self.bot_id, self.options, self.build_config)
def testFullBuild(self):
"""Tests whether correctly run make chroot and setup board for a full."""
self.bot_id = 'x86-generic-full'
self.build_config = config.config[self.bot_id]
self.mox.StubOutWithMock(commands, 'MakeChroot')
self.mox.StubOutWithMock(commands, 'SetupBoard')
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
os.path.isdir(os.path.join(self.build_root, 'chroot')).AndReturn(True)
commands.MakeChroot(buildroot=self.build_root,
fast=True,
replace=True,
usepkg=False)
os.path.isdir(os.path.join(self.build_root, 'chroot/build',
self.build_config['board'])).AndReturn(False)
commands.SetupBoard(self.build_root,
board=self.build_config['board'],
fast=True,
usepkg=False)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testBinBuild(self):
"""Tests whether we skip un-necessary steps for a binary builder."""
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
os.path.isdir(os.path.join(self.build_root, 'chroot')).AndReturn(True)
os.path.isdir(os.path.join(self.build_root, 'chroot/build',
self.build_config['board'])).AndReturn(True)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testBinBuildAfterClobber(self):
"""Tests whether we make chroot and board after a clobber."""
self.mox.StubOutWithMock(commands, 'MakeChroot')
self.mox.StubOutWithMock(commands, 'SetupBoard')
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
os.path.isdir(os.path.join(self.build_root, 'chroot')).AndReturn(False)
commands.MakeChroot(buildroot=self.build_root,
replace=self.build_config['chroot_replace'],
fast=self.build_config['fast'],
usepkg=self.build_config['usepkg_chroot'])
os.path.isdir(os.path.join(self.build_root, 'chroot/build',
self.build_config['board'])).AndReturn(False)
commands.SetupBoard(self.build_root,
board=self.build_config['board'],
fast=self.build_config['fast'],
usepkg=self.build_config['usepkg_setup_board'])
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class TestStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
self.fake_results_dir = '/tmp/fake_results_dir'
def ConstructStage(self):
return stages.TestStage(self.bot_id, self.options, self.build_config)
def testFullTests(self):
"""Tests if full unit and cros_au_test_harness tests are run correctly."""
self.bot_id = 'x86-generic-full'
self.build_config = config.config[self.bot_id].copy()
self.build_config['quick_unit'] = False
self.build_config['quick_vm'] = False
self.mox.StubOutWithMock(cros_lib, 'OldRunCommand')
self.mox.StubOutWithMock(commands, 'RunUnitTests')
self.mox.StubOutWithMock(commands, 'RunTestSuite')
self.mox.StubOutWithMock(commands, 'ArchiveTestResults')
self.mox.StubOutWithMock(stages.TestStage, '_CreateTestRoot')
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
stages.TestStage._CreateTestRoot().AndReturn(self.fake_results_dir)
commands.RunUnitTests(self.build_root, full=True,
nowithdebug=mox.IgnoreArg())
commands.RunTestSuite(self.build_root,
self.build_config['board'],
os.path.join(self.fake_results_dir,
'test_harness'),
full=True)
commands.ArchiveTestResults(self.build_root, self.fake_results_dir)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testQuickTests(self):
"""Tests if quick unit and cros_au_test_harness tests are run correctly."""
self.bot_id = 'x86-generic-full'
self.build_config = config.config[self.bot_id].copy()
self.build_config['quick_unit'] = True
self.build_config['quick_vm'] = True
self.mox.StubOutWithMock(commands, 'RunUnitTests')
self.mox.StubOutWithMock(commands, 'RunTestSuite')
self.mox.StubOutWithMock(commands, 'ArchiveTestResults')
self.mox.StubOutWithMock(stages.TestStage, '_CreateTestRoot')
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
stages.TestStage._CreateTestRoot().AndReturn(self.fake_results_dir)
commands.RunUnitTests(self.build_root, full=False,
nowithdebug=mox.IgnoreArg())
commands.RunTestSuite(self.build_root,
self.build_config['board'],
os.path.join(self.fake_results_dir,
'test_harness'),
full=False)
commands.ArchiveTestResults(self.build_root, self.fake_results_dir)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class UprevStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
# Disable most paths by default and selectively enable in tests
self.options.chrome_rev = None
self.build_config['uprev'] = False
self.mox.StubOutWithMock(commands, 'MarkChromeAsStable')
self.mox.StubOutWithMock(commands, 'UprevPackages')
self.mox.StubOutWithMock(sys, 'exit')
def ConstructStage(self):
return stages.UprevStage(self.bot_id, self.options, self.build_config)
def testChromeRevSuccess(self):
"""Case where MarkChromeAsStable returns an atom. We shouldn't exit."""
self.options.chrome_rev = 'tot'
chrome_atom = 'chromeos-base/chromeos-chrome-12.0.719.0_alpha-r1'
commands.MarkChromeAsStable(
self.build_root,
self.TRACKING_BRANCH,
self.options.chrome_rev,
self.build_config['board']).AndReturn(chrome_atom)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testChromeRevFoundNothing(self):
"""Verify we exit when MarkChromeAsStable doesn't return an atom."""
self.options.chrome_rev = 'tot'
commands.MarkChromeAsStable(
self.build_root,
self.TRACKING_BRANCH,
self.options.chrome_rev,
self.build_config['board'])
sys.exit(0)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testBuildRev(self):
"""Uprevving the build without uprevving chrome."""
self.build_config['uprev'] = True
commands.UprevPackages(
self.build_root,
self.build_config['board'],
[self.overlay])
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testNoRev(self):
"""No paths are enabled."""
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testUprevAll(self):
"""Uprev both Chrome and built packages."""
self.build_config['uprev'] = True
self.options.chrome_rev = 'tot'
# Even if MarkChromeAsStable didn't find anything to rev,
# if we rev the build then we don't exit
commands.MarkChromeAsStable(
self.build_root,
self.TRACKING_BRANCH,
self.options.chrome_rev,
self.build_config['board']).AndReturn(None)
commands.UprevPackages(
self.build_root,
self.build_config['board'],
[self.overlay])
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class BuildTargetStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
# Disable most paths by default and selectively enable in tests
self.build_config['vm_tests'] = False
self.build_config['build_type'] = 'binary'
self.build_config['usepkg_chroot'] = False
self.build_config['fast'] = False
self.options.prebuilts = True
self.options.tests = False
self.mox.StubOutWithMock(commands, 'Build')
self.mox.StubOutWithMock(commands, 'UploadPrebuilts')
self.mox.StubOutWithMock(commands, 'BuildImage')
self.mox.StubOutWithMock(commands, 'BuildVMImageForTesting')
self.mox.StubOutWithMock(stages.BuilderStage, '_GetPortageEnvVar')
def ConstructStage(self):
return stages.BuildTargetStage(self.bot_id,
self.options,
self.build_config)
def testAllConditionalPaths(self):
"""Enable all paths to get line coverage."""
self.build_config['vm_tests'] = True
self.options.tests = True
self.build_config['build_type'] = 'full'
self.build_config['usepkg_chroot'] = True
self.build_config['usepkg_setup_board'] = True
self.build_config['usepkg_build_packages'] = True
self.build_config['fast'] = True
self.build_config['useflags'] = ['ALPHA', 'BRAVO', 'CHARLIE']
self.build_config['nowithdebug'] = False
proper_env = {'USE' : ' '.join(self.build_config['useflags'])}
board = self.build_config['board']
stages.BuilderStage._GetPortageEnvVar('FULL_BINHOST',
board).AndReturn('new.com')
stages.BuilderStage.old_binhost = 'old.com'
commands.Build(self.build_root,
build_autotest=True,
emptytree=True,
usepkg=True,
fast=True,
nowithdebug=False,
extra_env=proper_env)
commands.UploadPrebuilts(
self.build_root, self.build_config['board'],
self.build_config['rev_overlays'], [],
self.build_config['build_type'], None, self.options.buildnumber)
commands.BuildImage(self.build_root, extra_env=proper_env)
commands.BuildVMImageForTesting(self.build_root, extra_env=proper_env)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testFalseBuildArgs1(self):
"""Make sure our logic for Build arguments can toggle to false."""
board = self.build_config['board']
stages.BuilderStage._GetPortageEnvVar('FULL_BINHOST',
board).AndReturn('new.com')
stages.BuilderStage.old_binhost = 'new.com'
self.build_config['useflags'] = None
commands.Build(self.build_root,
build_autotest=mox.IgnoreArg(),
emptytree=mox.IgnoreArg(),
fast=mox.IgnoreArg(),
usepkg=mox.IgnoreArg(),
nowithdebug=mox.IgnoreArg(),
extra_env={})
commands.BuildImage(self.build_root, extra_env={})
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testFalseBuildArgs2(self):
"""Verify emptytree flag is false when there is no old binhost."""
board = self.build_config['board']
stages.BuilderStage._GetPortageEnvVar('FULL_BINHOST',
board).AndReturn('new.com')
stages.BuilderStage.old_binhost = False
self.build_config['useflags'] = ['BAKER']
proper_env = {'USE' : ' '.join(self.build_config['useflags'])}
commands.Build(self.build_root,
build_autotest=mox.IgnoreArg(),
emptytree=False,
fast=mox.IgnoreArg(),
usepkg=mox.IgnoreArg(),
nowithdebug=False,
extra_env=proper_env)
commands.BuildImage(self.build_root, extra_env=proper_env)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class ArchiveStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
self._build_config = self.build_config.copy()
self._build_config['upload_symbols'] = True
self._build_config['push_image'] = True
def ConstructStage(self):
return stages.ArchiveStage(self.bot_id, self.options, self._build_config)
def testArchive(self):
"""Simple did-it-run test."""
self.mox.StubOutWithMock(commands, 'LegacyArchiveBuild')
self.mox.StubOutWithMock(commands, 'UploadSymbols')
self.mox.StubOutWithMock(commands, 'PushImages')
commands.LegacyArchiveBuild(
self.build_root, self.bot_id, self._build_config,
self.options.buildnumber, None,
self.options.debug).AndReturn((None, '/archive/dir'))
commands.UploadSymbols(self.build_root,
board=self._build_config['board'],
official=self._build_config['chromeos_official'])
commands.PushImages(self.build_root,
board=self._build_config['board'],
branch_name='master',
archive_dir='/archive/dir')
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class PushChangesStageTest(AbstractStageTest):
def setUp(self):
mox.MoxTestBase.setUp(self)
AbstractStageTest.setUp(self)
os.path.isdir(self.build_root + '/.repo').AndReturn(True)
# Disable most paths by default and selectively enable in tests
self.build_config['build_type'] = 'full'
self.options.chrome_rev = 'tot'
self.options.prebuilts = True
self.mox.StubOutWithMock(stages.PushChangesStage, '_GetPortageEnvVar')
self.mox.StubOutWithMock(commands, 'UploadPrebuilts')
self.mox.StubOutWithMock(commands, 'UprevPush')
def ConstructStage(self):
return stages.PushChangesStage(self.bot_id,
self.options,
self.build_config)
def ConstructBinhosts(self):
binhosts = []
for board in (self.build_config['board'], None):
binhost = 'http://binhost/?board=' + str(board)
stages.PushChangesStage._GetPortageEnvVar(stages._PORTAGE_BINHOST,
board).AndReturn(binhost)
binhosts.append(binhost)
return binhosts
def testChromePush(self):
"""Test uploading of prebuilts for chrome build."""
self.build_config['build_type'] = 'chrome'
binhosts = self.ConstructBinhosts()
commands.UploadPrebuilts(
self.build_root, self.build_config['board'],
self.build_config['rev_overlays'], binhosts,
self.build_config['build_type'],
self.options.chrome_rev,
self.options.buildnumber)
commands.UprevPush(
self.build_root,
self.build_config['board'],
[self.overlay],
self.options.debug)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testPreflightPush(self):
"""Test uploading of prebuilts for preflight build."""
self.build_config['build_type'] = 'binary'
binhosts = self.ConstructBinhosts()
commands.UploadPrebuilts(
self.build_root, self.build_config['board'],
self.build_config['rev_overlays'], binhosts,
self.build_config['build_type'],
self.options.chrome_rev,
self.options.buildnumber)
commands.UprevPush(
self.build_root,
self.build_config['board'],
[self.overlay],
self.options.debug)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
def testFullPush(self):
"""Shouldn't upload prebuilts for a full build."""
self.build_config['build_type'] = 'full'
commands.UprevPush(
self.build_root,
self.build_config['board'],
[self.overlay],
self.options.debug)
self.mox.ReplayAll()
self.RunStage()
self.mox.VerifyAll()
class BuildStagesResultsTest(unittest.TestCase):
def setUp(self):
unittest.TestCase.setUp(self)
# 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_root = '/fake_root'
self.url = 'fake_url'
# Create a class to hold
class Options:
pass
self.options = Options()
self.options.buildroot = self.build_root
self.options.debug = False
self.options.prebuilts = False
self.options.clobber = False
self.options.url = self.url
self.options.buildnumber = 1234
self.failException = Exception("FailStage needs to fail.")
def _runStages(self):
"""Run a couple of stages so we can capture the results"""
# Save off our self where FailStage._PerformStage can find it.
outer_self = self
class PassStage(stages.BuilderStage):
"""PassStage always works"""
pass
class Pass2Stage(stages.BuilderStage):
"""Pass2Stage always works"""
pass
class FailStage(stages.BuilderStage):
"""FailStage always throws an exception"""
def _PerformStage(self):
"""Throw the exception to make us fail."""
raise outer_self.failException
# Run two pass stages, and one fail stage.
PassStage(self.bot_id, self.options, self.build_config).Run()
Pass2Stage(self.bot_id, self.options, self.build_config).Run()
self.assertRaises(
stages.BuildException,
FailStage(self.bot_id, self.options, self.build_config).Run)
def _verifyRunResults(self, expectedResults):
actualResults = stages.Results.Get()
# Break out the asserts to be per item to make debugging easier
self.assertEqual(len(expectedResults), len(actualResults))
for i in xrange(len(expectedResults)):
name, result, description, runtime = actualResults[i]
if result not in (stages.Results.SUCCESS,
stages.Results.SKIPPED):
self.assertTrue(isinstance(description, str))
# Skipped stages take no time, all other test stages take a little time
if result == stages.Results.SKIPPED:
self.assertEqual(runtime, 0)
else:
self.assertTrue(runtime >= 0 and runtime < 2.0)
self.assertEqual(expectedResults[i], (name, result))
def testRunStages(self):
"""Run some stages and verify the captured results"""
stages.Results.Clear()
self.assertEqual(stages.Results.Get(), [])
self._runStages()
# Verify that the results are what we expect.
expectedResults = [
('Pass', stages.Results.SUCCESS),
('Pass2', stages.Results.SUCCESS),
('Fail', self.failException)]
self._verifyRunResults(expectedResults)
def testSuccessTest(self):
"""Run some stages and verify the captured results"""
stages.Results.Clear()
stages.Results.Record('Pass', stages.Results.SKIPPED)
self.assertTrue(stages.Results.Success())
stages.Results.Record('Fail', self.failException, time=1)
self.assertFalse(stages.Results.Success())
stages.Results.Record('Pass2', stages.Results.SUCCESS)
self.assertFalse(stages.Results.Success())
def testStagesReportSuccess(self):
"""Tests Stage reporting."""
stages.BuilderStage.archive_url = None
stages.ManifestVersionedSyncStage.manifest_manager = None
# Store off a known set of results and generate a report
stages.Results.Clear()
stages.Results.Record('Pass', stages.Results.SKIPPED, time=1)
stages.Results.Record('Pass2', stages.Results.SUCCESS, time=2)
stages.Results.Record('Fail', self.failException, time=3)
stages.Results.Record(
'FailRunCommand',
cros_lib.RunCommandError(
'Command "/bin/false /nosuchdir" failed.\n',
['/bin/false', '/nosuchdir']), time=4)
stages.Results.Record(
'FailOldRunCommand',
cros_lib.RunCommandException(
'Command "[\'/bin/false\', \'/nosuchdir\']" failed.\n',
['/bin/false', '/nosuchdir']), time=5)
results = StringIO.StringIO()
stages.Results.Report(results)
expectedResults = (
"************************************************************\n"
"** Stage Results\n"
"************************************************************\n"
"** Pass previously completed\n"
"************************************************************\n"
"** PASS Pass2 (0:00:02)\n"
"************************************************************\n"
"** FAIL Fail (0:00:03) with Exception\n"
"************************************************************\n"
"** FAIL FailRunCommand (0:00:04) in /bin/false\n"
"************************************************************\n"
"** FAIL FailOldRunCommand (0:00:05) in /bin/false\n"
"************************************************************\n")
expectedLines = expectedResults.split('\n')
actualLines = results.getvalue().split('\n')
# Break out the asserts to be per item to make debugging easier
for i in xrange(len(expectedLines)):
self.assertEqual(expectedLines[i], actualLines[i])
self.assertEqual(len(expectedLines), len(actualLines))
def testStagesReportError(self):
"""Tests Stage reporting with exceptions."""
stages.BuilderStage.archive_url = None
stages.ManifestVersionedSyncStage.manifest_manager = None
# Store off a known set of results and generate a report
stages.Results.Clear()
stages.Results.Record('Pass', stages.Results.SKIPPED, time=1)
stages.Results.Record('Pass2', stages.Results.SUCCESS, time=2)
stages.Results.Record('Fail', self.failException,
'failException Msg\nLine 2', time=3)
stages.Results.Record(
'FailRunCommand',
cros_lib.RunCommandError(
'Command "/bin/false /nosuchdir" failed.\n',
['/bin/false', '/nosuchdir']),
'FailRunCommand msg', time=4)
stages.Results.Record(
'FailOldRunCommand',
cros_lib.RunCommandException(
'Command "[\'/bin/false\', \'/nosuchdir\']" failed.\n',
['/bin/false', '/nosuchdir']),
'FailOldRunCommand msg', time=5)
results = StringIO.StringIO()
stages.Results.Report(results)
expectedResults = (
"************************************************************\n"
"** Stage Results\n"
"************************************************************\n"
"** Pass previously completed\n"
"************************************************************\n"
"** PASS Pass2 (0:00:02)\n"
"************************************************************\n"
"** FAIL Fail (0:00:03) with Exception\n"
"************************************************************\n"
"** FAIL FailRunCommand (0:00:04) in /bin/false\n"
"************************************************************\n"
"** FAIL FailOldRunCommand (0:00:05) in /bin/false\n"
"************************************************************\n"
"\n"
"Build failed with:\n"
"\n"
"failException Msg\n"
"Line 2")
expectedLines = expectedResults.split('\n')
actualLines = results.getvalue().split('\n')
# Break out the asserts to be per item to make debugging easier
for i in xrange(len(expectedLines)):
self.assertEqual(expectedLines[i], actualLines[i])
self.assertEqual(len(expectedLines), len(actualLines))
def testStagesReportReleaseTag(self):
"""Tests Release Tag entry in stages report."""
manifest_manager = mox.MockAnything()
manifest_manager.current_version = "release_tag_string"
stages.ManifestVersionedSyncStage.manifest_manager = manifest_manager
stages.BuilderStage.archive_url = 'result_url'
# Store off a known set of results and generate a report
stages.Results.Clear()
stages.Results.Record('Pass', stages.Results.SUCCESS, time=1)
results = StringIO.StringIO()
stages.Results.Report(results)
expectedResults = (
"************************************************************\n"
"** RELEASE VERSION: release_tag_string\n"
"************************************************************\n"
"** Stage Results\n"
"************************************************************\n"
"** PASS Pass (0:00:01)\n"
"************************************************************\n"
"** BUILD ARTIFACTS FOR THIS BUILD CAN BE FOUND AT:\n"
"** result_url\n"
"************************************************************\n")
expectedLines = expectedResults.split('\n')
actualLines = results.getvalue().split('\n')
# Break out the asserts to be per item to make debugging easier
for i in xrange(len(expectedLines)):
self.assertEqual(expectedLines[i], actualLines[i])
self.assertEqual(len(expectedLines), len(actualLines))
def testSaveCompletedStages(self):
"""Tests that we can save out completed stages."""
# Run this again to make sure we have the expected results stored
stages.Results.Clear()
stages.Results.Record('Pass', stages.Results.SUCCESS)
stages.Results.Record('Fail', self.failException)
stages.Results.Record('Pass2', stages.Results.SUCCESS)
saveFile = StringIO.StringIO()
stages.Results.SaveCompletedStages(saveFile)
self.assertEqual(saveFile.getvalue(), 'Pass\n')
def testRestoreCompletedStages(self):
"""Tests that we can read in completed stages."""
stages.Results.Clear()
stages.Results.RestoreCompletedStages(
StringIO.StringIO('Pass\n'))
self.assertEqual(stages.Results.GetPrevious(), ['Pass'])
def testRunAfterRestore(self):
"""Tests that we skip previously completed stages."""
# Fake stages.Results.RestoreCompletedStages
stages.Results.Clear()
stages.Results.RestoreCompletedStages(
StringIO.StringIO('Pass\n'))
self._runStages()
# Verify that the results are what we expect.
expectedResults = [
('Pass', stages.Results.SKIPPED),
('Pass2', stages.Results.SUCCESS),
('Fail', self.failException)]
self._verifyRunResults(expectedResults)
if __name__ == '__main__':
unittest.main()