blob: b1c042aff146a3d1a0c63ba822e3ff9383179cf8 [file] [log] [blame]
# -*- coding: utf-8 -*-
# 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.
"""Unittests for simpler builders."""
from __future__ import print_function
import copy
import os
from chromite.cbuildbot import cbuildbot_run
from chromite.cbuildbot.builders import generic_builders
from chromite.cbuildbot.builders import simple_builders
from chromite.cbuildbot.stages import generic_stages
from chromite.cbuildbot.stages import tast_test_stages
from chromite.cbuildbot.stages import vm_test_stages
from chromite.lib import config_lib
from chromite.lib import constants
from chromite.lib import cros_test_lib
from chromite.lib import failures_lib
from chromite.lib import osutils
from chromite.lib import parallel
from chromite.lib.buildstore import FakeBuildStore
from chromite.scripts import cbuildbot
# pylint: disable=protected-access
class SimpleBuilderTest(cros_test_lib.MockTempDirTestCase):
"""Tests for the main code paths in simple_builders.SimpleBuilder"""
def setUp(self):
# List of all stages that would have been called as part of this run.
self.called_stages = []
# Map from stage class to exception to be raised when stage is run.
self.stage_exceptions = {}
# VM test stages that are run by SimpleBuilder._RunVMTests.
self.all_vm_test_stages = [vm_test_stages.VMTestStage,
tast_test_stages.TastVMTestStage]
self.buildstore = FakeBuildStore()
# Simple new function that redirects RunStage to record all stages to be
# run rather than mock them completely. These can be used in a test to
# assert something has been called.
def run_stage(_class_instance, stage_name, *args, **_kwargs):
# It's more useful to record the actual stage that's wrapped within
# RepeatStage or RetryStage.
if stage_name in [generic_stages.RepeatStage, generic_stages.RetryStage]:
stage_name = args[1]
self.called_stages.append(stage_name)
if stage_name in self.stage_exceptions:
raise self.stage_exceptions[stage_name]
# Parallel version.
def run_parallel_stages(_class_instance, *_args):
# Since parallel stages are forked processes, we can't actually
# update anything here unless we want to do interprocesses comms.
pass
self.buildroot = os.path.join(self.tempdir, 'buildroot')
chroot_path = os.path.join(self.buildroot, constants.DEFAULT_CHROOT_DIR)
osutils.SafeMakedirs(os.path.join(chroot_path, 'tmp'))
self.PatchObject(generic_builders.Builder, '_RunStage',
new=run_stage)
self.PatchObject(simple_builders.SimpleBuilder, '_RunParallelStages',
new=run_parallel_stages)
self.PatchObject(cbuildbot_run._BuilderRunBase, 'GetVersion',
return_value='R32-1234.0.0')
self._manager = parallel.Manager()
# Pylint-1.9 has a false positive on this for some reason.
self._manager.__enter__() # pylint: disable=no-value-for-parameter
def tearDown(self):
# Mimic exiting a 'with' statement.
self._manager.__exit__(None, None, None)
def _initConfig(
self, bot_id, master=False, extra_argv=None, override_hw_test_config=None,
models=None):
"""Return normal options/build_config for |bot_id|"""
site_config = config_lib.GetConfig()
build_config = copy.deepcopy(site_config[bot_id])
build_config['master'] = master
build_config['important'] = False
if models:
build_config['models'] = models
# Use the cbuildbot parser to create properties and populate default values.
parser = cbuildbot._CreateParser()
argv = (['-r', self.buildroot, '--buildbot', '--debug', '--nochromesdk'] +
(extra_argv if extra_argv else []) + [bot_id])
options = cbuildbot.ParseCommandLine(parser, argv)
# Yikes.
options.managed_chrome = build_config['sync_chrome']
# Iterate through override and update HWTestConfig attributes.
if override_hw_test_config:
for key, val in override_hw_test_config.items():
for hw_test in build_config.hw_tests:
setattr(hw_test, key, val)
return cbuildbot_run.BuilderRun(
options, site_config, build_config, self._manager)
def _RunVMTests(self):
"""Helper method that runs VM tests and returns exceptions.
Returns:
List of exception classes in CompoundFailure.
"""
board = 'betty-release'
builder_run = self._initConfig(board)
exception_types = []
try:
simple_builders.SimpleBuilder(builder_run, self.buildstore)._RunVMTests(
builder_run, board)
except failures_lib.CompoundFailure as f:
exception_types = [e.type for e in f.exc_infos]
return exception_types
def testRunStagesChrootBuilder(self):
"""Verify RunStages for CHROOT_BUILDER_TYPE builders"""
builder_run = self._initConfig('chromiumos-sdk')
simple_builders.SimpleBuilder(builder_run, self.buildstore).RunStages()
def testRunStagesDefaultBuild(self):
"""Verify RunStages for standard board builders"""
builder_run = self._initConfig('amd64-generic-full')
builder_run.attrs.chrome_version = 'TheChromeVersion'
simple_builders.SimpleBuilder(builder_run, self.buildstore).RunStages()
def testRunStagesDefaultBuildCompileCheck(self):
"""Verify RunStages for standard board builders (compile only)"""
extra_argv = ['--compilecheck']
builder_run = self._initConfig('amd64-generic-full', extra_argv=extra_argv)
builder_run.attrs.chrome_version = 'TheChromeVersion'
simple_builders.SimpleBuilder(builder_run, self.buildstore).RunStages()
def testRunStagesDefaultBuildHwTests(self):
"""Verify RunStages for boards w/hwtests"""
extra_argv = ['--hwtest']
builder_run = self._initConfig('eve-release', extra_argv=extra_argv)
builder_run.attrs.chrome_version = 'TheChromeVersion'
simple_builders.SimpleBuilder(builder_run, self.buildstore).RunStages()
def testThatWeScheduleHWTestsRegardlessOfBlocking(self):
"""Verify RunStages for boards w/hwtests (blocking).
Make sure the same stages get scheduled regardless of whether their hwtest
suites are marked blocking or not.
"""
extra_argv = ['--hwtest']
builder_run_without_blocking = self._initConfig(
'eve-release', extra_argv=extra_argv,
override_hw_test_config=dict(blocking=False))
builder_run_with_blocking = self._initConfig(
'eve-release', extra_argv=extra_argv,
override_hw_test_config=dict(blocking=True))
builder_run_without_blocking.attrs.chrome_version = 'TheChromeVersion'
builder_run_with_blocking.attrs.chrome_version = 'TheChromeVersion'
simple_builders.SimpleBuilder(builder_run_without_blocking,
self.buildstore).RunStages()
without_blocking_stages = list(self.called_stages)
self.called_stages = []
simple_builders.SimpleBuilder(builder_run_with_blocking,
self.buildstore).RunStages()
self.assertEqual(without_blocking_stages, self.called_stages)
def testUnifiedBuildsRunHwTestsForAllModels(self):
"""Verify hwtests run for model fanout with unified builds"""
extra_argv = ['--hwtest']
unified_build = self._initConfig(
'eve-release',
extra_argv=extra_argv,
models=[config_lib.ModelTestConfig('model1', 'model1'),
config_lib.ModelTestConfig(
'model2', 'model2', ['sanity', 'bvt-inline'])])
unified_build.attrs.chrome_version = 'TheChromeVersion'
simple_builders.SimpleBuilder(unified_build, self.buildstore).RunStages()
def testAllVMTestStagesSucceed(self):
"""Verify all VM test stages are run."""
self.assertEqual([], self._RunVMTests())
self.assertEqual(self.all_vm_test_stages, self.called_stages)
def testAllVMTestStagesFail(self):
"""Verify failures are reported when all VM test stages fail."""
self.stage_exceptions = {
vm_test_stages.VMTestStage: failures_lib.InfrastructureFailure(),
tast_test_stages.TastVMTestStage: failures_lib.TestFailure(),
}
self.assertEqual(
[failures_lib.InfrastructureFailure, failures_lib.TestFailure],
self._RunVMTests())
self.assertEqual(self.all_vm_test_stages, self.called_stages)
def testVMTestStageFails(self):
"""Verify TastVMTestStage is still run when VMTestStage fails."""
self.stage_exceptions = {
vm_test_stages.VMTestStage: failures_lib.TestFailure(),
}
self.assertEqual([failures_lib.TestFailure], self._RunVMTests())
self.assertEqual(self.all_vm_test_stages, self.called_stages)
def testTastVMTestStageFails(self):
"""Verify VMTestStage is still run when TastVMTestStage fails."""
self.stage_exceptions = {
tast_test_stages.TastVMTestStage: failures_lib.TestFailure(),
}
self.assertEqual([failures_lib.TestFailure], self._RunVMTests())
self.assertEqual(self.all_vm_test_stages, self.called_stages)