diff options
author | Don Garrett <dgarrett@google.com> | 2015-05-04 17:38:17 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-05-08 06:13:12 +0000 |
commit | bf808553f8da8a477bce5d5bb80a8af8939e6e73 (patch) | |
tree | f92a685984b808564622dcfad43dcb1254c0e17b /cbuildbot/cbuildbot_config_unittest.py | |
parent | dc14ed98e4568b074a64562a29e71852368005a4 (diff) | |
download | chromite-bf808553f8da8a477bce5d5bb80a8af8939e6e73.tar.gz |
cbuildbot_config: Rename to generate_chromeos_config.
Create minimal cbuildbot_config that imports symbols from
gen_cbuildbot_config. This is done to clearly show what external
symbols are needed from cbuildbot_config.
Eventually cbuildbot_config will read a json file to populate itself,
but we need to fully understand the interface to know all of the
constraints.
BUG=chromium:483566
TEST=run_tests + linting
Change-Id: I71cb9d541df2a63efb7342f465418678bd515dc9
Reviewed-on: https://chromium-review.googlesource.com/269953
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Commit-Queue: Don Garrett <dgarrett@chromium.org>
Tested-by: Don Garrett <dgarrett@chromium.org>
Diffstat (limited to 'cbuildbot/cbuildbot_config_unittest.py')
-rw-r--r-- | cbuildbot/cbuildbot_config_unittest.py | 949 |
1 files changed, 2 insertions, 947 deletions
diff --git a/cbuildbot/cbuildbot_config_unittest.py b/cbuildbot/cbuildbot_config_unittest.py index d0a1f83f9..af63989b5 100644 --- a/cbuildbot/cbuildbot_config_unittest.py +++ b/cbuildbot/cbuildbot_config_unittest.py @@ -6,952 +6,7 @@ from __future__ import print_function -import copy -import mock -import os -import re -import cPickle - -from chromite.cbuildbot import builders -from chromite.cbuildbot import cbuildbot_config -from chromite.cbuildbot import constants -from chromite.cbuildbot.builders import generic_builders -from chromite.lib import cros_build_lib from chromite.lib import cros_test_lib -from chromite.lib import git -from chromite.lib import osutils - - -CHROMIUM_WATCHING_URL = ( - 'http://src.chromium.org/chrome/trunk/tools/build/masters/' - 'master.chromium.chromiumos/master_chromiumos_cros_cfg.py' -) - - -class ConfigDumpTest(cros_test_lib.TestCase): - """Tests related to config_dump.json & cbuildbot_config.py""" - - def testDump(self): - """Make sure the json & config are kept in sync""" - cmd = [os.path.join(constants.CHROMITE_BIN_DIR, 'cbuildbot_view_config'), - '-d', '-s', '--pretty'] - dump_file_path = os.path.join(constants.CHROMITE_DIR, 'cbuildbot', - 'config_dump.json') - new_dump = cros_build_lib.RunCommand(cmd, capture_output=True).output - old_dump = osutils.ReadFile(dump_file_path) - self.assertTrue( - new_dump == old_dump, 'config_dump.json does not match the ' - 'configs defined in cbuildbot_config.py. Run ' - 'bin/cbuildbot_view_config -d -s --pretty > cbuildbot/config_dump.json') - - -class ConfigPickleTest(cros_test_lib.TestCase): - """Test that a config object is pickleable.""" - - def testPickle(self): - bc1 = cbuildbot_config.GetConfig()['x86-mario-paladin'] - bc2 = cPickle.loads(cPickle.dumps(bc1)) - - self.assertEquals(bc1.boards, bc2.boards) - self.assertEquals(bc1.name, bc2.name) - - -class _CustomObject(object): - """Simple object. For testing deepcopy.""" - - def __init__(self, x): - self.x = x - - def __eq__(self, other): - return self.x == other.x - - -class _CustomObjectWithSlots(object): - """Simple object with slots. For testing deepcopy.""" - - __slots__ = ['x'] - - def __init__(self, x): - self.x = x - - def __eq__(self, other): - return self.x == other.x - - -class ConfigClassTest(cros_test_lib.TestCase): - """Tests of the config class itself.""" - - def testValueAccess(self): - cfg = cbuildbot_config.GetConfig()['x86-mario-paladin'] - - self.assertTrue(cfg.name) - self.assertEqual(cfg.name, cfg['name']) - - self.assertRaises(AttributeError, getattr, cfg, 'foobar') - - # pylint: disable=protected-access - def testDeleteKey(self): - base_config = cbuildbot_config.BuildConfig(foo='bar') - inherited_config = base_config.derive(foo=cbuildbot_config.delete_key()) - self.assertTrue('foo' in base_config) - self.assertFalse('foo' in inherited_config) - - def testDeleteKeys(self): - base_config = cbuildbot_config.BuildConfig(foo='bar', baz='bak') - inherited_config_1 = base_config.derive(qzr='flp') - inherited_config_2 = inherited_config_1.derive( - cbuildbot_config.delete_keys(base_config)) - self.assertEqual(inherited_config_2, {'qzr': 'flp'}) - - def testCallableOverrides(self): - append_foo = lambda x: x + 'foo' if x else 'foo' - base_config = cbuildbot_config.BuildConfig() - inherited_config_1 = base_config.derive(foo=append_foo) - inherited_config_2 = inherited_config_1.derive(foo=append_foo) - self.assertEqual(inherited_config_1, {'foo': 'foo'}) - self.assertEqual(inherited_config_2, {'foo': 'foofoo'}) - - def testAppendUseflags(self): - base_config = cbuildbot_config.BuildConfig() - inherited_config_1 = base_config.derive( - useflags=cbuildbot_config.append_useflags(['foo', 'bar', '-baz'])) - inherited_config_2 = inherited_config_1.derive( - useflags=cbuildbot_config.append_useflags(['-bar', 'baz'])) - self.assertEqual(inherited_config_1.useflags, ['-baz', 'bar', 'foo']) - self.assertEqual(inherited_config_2.useflags, ['-bar', 'baz', 'foo']) - - def AssertDeepCopy(self, obj1, obj2, obj3): - """Assert that |obj3| is a deep copy of |obj1|. - - Args: - obj1: Object that was copied. - obj2: A true deep copy of obj1 (produced using copy.deepcopy). - obj3: The purported deep copy of obj1. - """ - # Check whether the item was copied by deepcopy. If so, then it - # must have been copied by our algorithm as well. - if obj1 is not obj2: - self.assertIsNot(obj1, obj3) - - # Assert the three items are all equal. - self.assertEqual(obj1, obj2) - self.assertEqual(obj1, obj3) - - if isinstance(obj1, (tuple, list)): - # Copy tuples and lists item by item. - for i in range(len(obj1)): - self.AssertDeepCopy(obj1[i], obj2[i], obj3[i]) - elif isinstance(obj1, set): - # Compare sorted versions of the set. - self.AssertDeepCopy(list(sorted(obj1)), list(sorted(obj2)), - list(sorted(obj3))) - elif isinstance(obj1, dict): - # Copy dicts item by item. - for k in obj1: - self.AssertDeepCopy(obj1[k], obj2[k], obj3[k]) - elif hasattr(obj1, '__dict__'): - # Make sure the dicts are copied. - self.AssertDeepCopy(obj1.__dict__, obj2.__dict__, obj3.__dict__) - elif hasattr(obj1, '__slots__'): - # Make sure the slots are copied. - for attr in obj1.__slots__: - self.AssertDeepCopy(getattr(obj1, attr), getattr(obj2, attr), - getattr(obj3, attr)) - else: - # This should be an object that copy.deepcopy didn't copy (probably an - # immutable object.) If not, the test needs to be updated to handle this - # kind of object. - self.assertIs(obj1, obj2) - - def testDeepCopy(self): - """Test that we deep copy correctly.""" - for cfg in cbuildbot_config.GetConfig().itervalues(): - self.AssertDeepCopy(cfg, copy.deepcopy(cfg), cfg.deepcopy()) - - def testAssertDeepCopy(self): - """Test that we test deep copy correctly.""" - test1 = ['foo', 'bar', ['hey']] - tests = [test1, - set([tuple(x) for x in test1]), - dict(zip([tuple(x) for x in test1], test1)), - _CustomObject(test1), - _CustomObjectWithSlots(test1)] - - for x in tests + [[tests]]: - copy_x = copy.deepcopy(x) - self.AssertDeepCopy(x, copy_x, copy.deepcopy(x)) - self.AssertDeepCopy(x, copy_x, cPickle.loads(cPickle.dumps(x, -1))) - self.assertRaises(AssertionError, self.AssertDeepCopy, x, - copy_x, x) - if not isinstance(x, set): - self.assertRaises(AssertionError, self.AssertDeepCopy, x, - copy_x, copy.copy(x)) - - -class CBuildBotTest(cros_test_lib.TestCase): - """General tests of cbuildbot_config with respect to cbuildbot.""" - - def testConfigsKeysMismatch(self): - """Verify that all configs contain exactly the default keys. - - This checks for mispelled keys, or keys that are somehow removed. - """ - expected_keys = set(cbuildbot_config.GetDefault().keys()) - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - config_keys = set(config.keys()) - - extra_keys = config_keys.difference(expected_keys) - self.assertFalse(extra_keys, ('Config %s has extra values %s' % - (build_name, list(extra_keys)))) - - missing_keys = expected_keys.difference(config_keys) - self.assertFalse(missing_keys, ('Config %s is missing values %s' % - (build_name, list(missing_keys)))) - - def testConfigsHaveName(self): - """Configs must have names set.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - self.assertTrue(build_name == config['name']) - - def testConfigUseflags(self): - """Useflags must be lists. - - Strings are interpreted as arrays of characters for this, which is not - useful. - """ - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - useflags = config.get('useflags') - if not useflags is None: - self.assertTrue( - isinstance(useflags, list), - 'Config %s: useflags should be a list.' % build_name) - - def testBoards(self): - """Verify 'boards' is explicitly set for every config.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - self.assertTrue(isinstance(config['boards'], (tuple, list)), - "Config %s doesn't have a list of boards." % build_name) - self.assertEqual(len(set(config['boards'])), len(config['boards']), - 'Config %s has duplicate boards.' % build_name) - self.assertTrue(config['boards'] is not None, - 'Config %s defines a list of boards.' % build_name) - - def testOverlaySettings(self): - """Verify overlays and push_overlays have legal values.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - overlays = config['overlays'] - push_overlays = config['push_overlays'] - - self.assertTrue(overlays in [None, 'public', 'private', 'both'], - 'Config %s: has unexpected overlays value.' % build_name) - self.assertTrue( - push_overlays in [None, 'public', 'private', 'both'], - 'Config %s: has unexpected push_overlays value.' % build_name) - - if overlays == None: - subset = [None] - elif overlays == 'public': - subset = [None, 'public'] - elif overlays == 'private': - subset = [None, 'private'] - elif overlays == 'both': - subset = [None, 'public', 'private', 'both'] - - self.assertTrue( - push_overlays in subset, - ('Config %s: push_overlays should be a subset of overlays.' % - build_name)) - - def testOverlayMaster(self): - """Verify that only one master is pushing uprevs for each overlay.""" - masters = {} - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - overlays = config['overlays'] - push_overlays = config['push_overlays'] - if (overlays and push_overlays and config['uprev'] and config['master'] - and not config['branch']): - other_master = masters.get(push_overlays) - err_msg = 'Found two masters for push_overlays=%s: %s and %s' - self.assertFalse( - other_master, err_msg % (push_overlays, build_name, other_master)) - masters[push_overlays] = build_name - - if 'both' in masters: - self.assertEquals(len(masters), 1, 'Found too many masters.') - - def testChromeRev(self): - """Verify chrome_rev has an expected value""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - self.assertTrue( - config['chrome_rev'] in constants.VALID_CHROME_REVISIONS + [None], - 'Config %s: has unexpected chrome_rev value.' % build_name) - self.assertFalse( - config['chrome_rev'] == constants.CHROME_REV_LOCAL, - 'Config %s: has unexpected chrome_rev_local value.' % build_name) - if config['chrome_rev']: - self.assertTrue( - cbuildbot_config.IsPFQType(config['build_type']), - 'Config %s: has chrome_rev but is not a PFQ.' % build_name) - - def testValidVMTestType(self): - """Verify vm_tests has an expected value""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config['vm_tests'] is None: - continue - for test_type in config['vm_tests']: - self.assertTrue( - test_type in constants.VALID_VM_TEST_TYPES, - 'Config %s: has unexpected vm test type value.' % build_name) - - def testImageTestMustHaveBaseImage(self): - """Verify image_test build is only enabled with 'base' in images.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config.get('image_test', False): - self.assertTrue( - 'base' in config['images'], - 'Build %s runs image_test but does not have base image' % - build_name) - - def testBuildType(self): - """Verifies that all configs use valid build types.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - # For builders that have explicit classes, this check doesn't make sense. - if config['builder_class_name']: - continue - self.assertIn(config['build_type'], constants.VALID_BUILD_TYPES, - 'Config %s: has unexpected build_type value.' % build_name) - - def testGCCGitHash(self): - """Verifies that gcc_githash is not set without setting latest_toolchain.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config['gcc_githash']: - self.assertTrue( - config['latest_toolchain'], - 'Config %s: has gcc_githash but not latest_toolchain.' % build_name) - - def testBuildToRun(self): - """Verify we don't try to run tests without building them.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - self.assertFalse( - isinstance(config['useflags'], list) and - '-build_tests' in config['useflags'] and config['vm_tests'], - 'Config %s: has vm_tests and use -build_tests.' % build_name) - - def testSyncToChromeSdk(self): - """Verify none of the configs build chrome sdk but don't sync chrome.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config['sync_chrome'] is not None and not config['sync_chrome']: - self.assertFalse( - config['chrome_sdk'], - 'Config %s: has chrome_sdk but not sync_chrome.' % build_name) - - def testNoTestSupport(self): - """VM/unit tests shouldn't be enabled for builders without test support.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if not config['tests_supported']: - self.assertFalse( - config['unittests'], - 'Config %s: has tests_supported but unittests=True.' % build_name) - self.assertEqual( - config['vm_tests'], [], - 'Config %s: has test_supported but requests vm_tests.' % build_name) - - def testHWTestsIFFArchivingHWTestArtifacts(self): - """Make sure all configs upload artifacts that need them for hw testing.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config['hw_tests']: - self.assertTrue( - config['upload_hw_test_artifacts'], - "%s is trying to run hw tests without uploading payloads." % - build_name) - - def testValidUnifiedMasterConfig(self): - """Make sure any unified master configurations are valid.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - error = 'Unified config for %s has invalid values' % build_name - # Unified masters must be internal and must rev both overlays. - if config['master']: - self.assertTrue( - config['internal'] and config['manifest_version'], error) - elif not config['master'] and config['manifest_version']: - # Unified slaves can rev either public or both depending on whether - # they are internal or not. - if not config['internal']: - self.assertEqual(config['overlays'], constants.PUBLIC_OVERLAYS, error) - elif cbuildbot_config.IsCQType(config['build_type']): - self.assertEqual(config['overlays'], constants.BOTH_OVERLAYS, error) - - def testGetSlaves(self): - """Make sure every master has a sane list of slaves""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config.master: - configs = cbuildbot_config.GetSlavesForMaster(config) - self.assertEqual( - len(map(repr, configs)), len(set(map(repr, configs))), - 'Duplicate board in slaves of %s will cause upload prebuilts' - ' failures' % build_name) - - # Our logic for calculating what slaves have completed their critical - # stages will break if the master is considered a slave of itself, - # because db.GetSlaveStages(...) doesn't include master stages. - if config.build_type == constants.PALADIN_TYPE: - self.assertEquals( - config.boards, [], - 'Master paladin %s cannot have boards.' % build_name) - self.assertNotIn( - build_name, [x.name for x in configs], - 'Master paladin %s cannot be a slave of itself.' % build_name) - - def testGetSlavesOnTrybot(self): - """Make sure every master has a sane list of slaves""" - mock_options = mock.Mock() - mock_options.remote_trybot = True - for _, config in cbuildbot_config.GetConfig().iteritems(): - if config['master']: - configs = cbuildbot_config.GetSlavesForMaster(config, mock_options) - self.assertEqual([], configs) - - def testFactoryFirmwareValidity(self): - """Ensures that firmware/factory branches have at least 1 valid name.""" - tracking_branch = git.GetChromiteTrackingBranch() - for branch in ['firmware', 'factory']: - if tracking_branch.startswith(branch): - saw_config_for_branch = False - for build_name in cbuildbot_config.GetConfig(): - if build_name.endswith('-%s' % branch): - self.assertFalse('release' in build_name, - 'Factory|Firmware release builders should not ' - 'contain release in their name.') - saw_config_for_branch = True - - self.assertTrue( - saw_config_for_branch, 'No config found for %s branch. ' - 'As this is the %s branch, all release configs that are being used ' - 'must end in %s.' % (branch, tracking_branch, branch)) - - def testBuildTests(self): - """Verify that we don't try to use tests without building them.""" - - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if not config['build_tests']: - for flag in ('factory_toolkit', 'vm_tests', 'hw_tests'): - self.assertFalse( - config[flag], - 'Config %s set %s without build_tests.' % (build_name, flag)) - - def testAFDOInBackground(self): - """Verify that we don't try to build or use AFDO data in the background.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config.build_packages_in_background: - # It is unsupported to use the build_packages_in_background flags with - # the afdo_generate or afdo_generate_min config options. - msg = 'Config %s uses build_packages_in_background with afdo_%s' - self.assertFalse(config.afdo_generate, msg % (build_name, 'generate')) - self.assertFalse(config.afdo_generate_min, msg % (build_name, - 'generate_min')) - - def testReleaseGroupInBackground(self): - """Verify build_packages_in_background settings for release groups. - - For each release group, the first builder should be set to run in the - foreground (to build binary packages), and the remainder of the builders - should be set to run in parallel (to install the binary packages.) - """ - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if build_name.endswith('-release-group'): - msg = 'Config %s should not build_packages_in_background' - self.assertFalse(config.build_packages_in_background, msg % build_name) - - self.assertTrue( - config.child_configs, - 'Config %s should have child configs' % build_name) - first_config = config.child_configs[0] - msg = 'Primary config for %s should not build_packages_in_background' - self.assertFalse(first_config.build_packages_in_background, - msg % build_name) - - msg = 'Child config %s for %s should build_packages_in_background' - for child_config in config.child_configs[1:]: - self.assertTrue(child_config.build_packages_in_background, - msg % (child_config.name, build_name)) - - def testAFDOSameInChildConfigs(self): - """Verify that 'afdo_use' is the same for all children in a group.""" - msg = ('Child config %s for %s should have same value for afdo_use ' - 'as other children') - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if build_name.endswith('-group'): - prev_value = None - self.assertTrue(config.child_configs, - 'Config %s should have child configs' % build_name) - for child_config in config.child_configs: - if prev_value is None: - prev_value = child_config.afdo_use - else: - self.assertEqual(child_config.afdo_use, prev_value, - msg % (child_config.name, build_name)) - - def testReleaseAFDOConfigs(self): - """Verify that <board>-release-afdo config have generate and use children. - - These configs should have a 'generate' and a 'use' child config. Also, - any 'generate' and 'use' configs should be children of a release-afdo - config. - """ - msg = 'Config %s should have %s as a parent' - parent_suffix = cbuildbot_config.CONFIG_TYPE_RELEASE_AFDO - generate_suffix = '%s-generate' % parent_suffix - use_suffix = '%s-use' % parent_suffix - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if build_name.endswith(parent_suffix): - self.assertEqual( - len(config.child_configs), 2, - 'Config %s should have 2 child configs' % build_name) - for child_config in config.child_configs: - child_name = child_config.name - self.assertTrue(child_name.endswith(generate_suffix) or - child_name.endswith(use_suffix), - 'Config %s has wrong %s child' % - (build_name, child_config)) - if build_name.endswith(generate_suffix): - parent_config_name = build_name.replace(generate_suffix, - parent_suffix) - self.assertTrue(parent_config_name in cbuildbot_config.GetConfig(), - msg % (build_name, parent_config_name)) - if build_name.endswith(use_suffix): - parent_config_name = build_name.replace(use_suffix, - parent_suffix) - self.assertTrue(parent_config_name in cbuildbot_config.GetConfig(), - msg % (build_name, parent_config_name)) - - def testNoGrandChildConfigs(self): - """Verify that no child configs have a child config.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - for child_config in config.child_configs: - for grandchild_config in child_config.child_configs: - self.fail('Config %s has grandchild %s' % (build_name, - grandchild_config.name)) - - def testUseChromeLKGMImpliesInternal(self): - """Currently use_chrome_lkgm refers only to internal manifests.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config['use_chrome_lkgm']: - self.assertTrue( - config['internal'], - 'Chrome lkgm currently only works with an internal manifest: %s' % ( - build_name,)) - - def testNonOverlappingConfigTypes(self): - """Test that a config can only match one build suffix.""" - for config_type in cbuildbot_config.CONFIG_TYPE_DUMP_ORDER: - # A longer config_type should never end with a shorter suffix. - my_list = list(cbuildbot_config.CONFIG_TYPE_DUMP_ORDER) - my_list.remove(config_type) - self.assertEquals( - cbuildbot_config.GetDisplayPosition( - config_type, type_order=my_list), - len(my_list)) - - def testCorrectConfigTypeIndex(self): - """Test that the correct build suffix index is returned.""" - type_order = ( - 'type1', - 'donkey-type2', - 'kong-type3') - - for index, config_type in enumerate(type_order): - config = '-'.join(['pre-fix', config_type]) - self.assertEquals( - cbuildbot_config.GetDisplayPosition( - config, type_order=type_order), - index) - - # Verify suffix needs to match up to a '-'. - self.assertEquals( - cbuildbot_config.GetDisplayPosition( - 'pre-fix-sometype1', type_order=type_order), - len(type_order)) - - def testConfigTypesComplete(self): - """Verify CONFIG_TYPE_DUMP_ORDER contains all valid config types.""" - for config_name in cbuildbot_config.GetConfig(): - self.assertNotEqual( - cbuildbot_config.GetDisplayPosition(config_name), - len(cbuildbot_config.CONFIG_TYPE_DUMP_ORDER), - '%s did not match any types in %s' % - (config_name, 'cbuildbot_config.CONFIG_TYPE_DUMP_ORDER')) - - def testCantBeBothTypesOfLKGM(self): - """Using lkgm and chrome_lkgm doesn't make sense.""" - for config in cbuildbot_config.GetConfig().values(): - self.assertFalse(config['use_lkgm'] and config['use_chrome_lkgm']) - - def testNoDuplicateSlavePrebuilts(self): - """Test that no two same-board paladin slaves upload prebuilts.""" - for cfg in cbuildbot_config.GetConfig().values(): - if cfg['build_type'] == constants.PALADIN_TYPE and cfg['master']: - slaves = cbuildbot_config.GetSlavesForMaster(cfg) - prebuilt_slaves = [s for s in slaves if s['prebuilts']] - # Dictionary from board name to builder name that uploads prebuilt - prebuilt_slave_boards = {} - for slave in prebuilt_slaves: - for board in slave['boards']: - self.assertFalse(prebuilt_slave_boards.has_key(board), - 'Configs %s and %s both upload prebuilts for ' - 'board %s.' % (prebuilt_slave_boards.get(board), - slave['name'], - board)) - prebuilt_slave_boards[board] = slave['name'] - - def testNoDuplicateWaterfallNames(self): - """Tests that no two configs specify same waterfall name.""" - waterfall_names = set() - for config in cbuildbot_config.GetConfig().values(): - wn = config['buildbot_waterfall_name'] - if wn is not None: - self.assertNotIn(wn, waterfall_names, - 'Duplicate waterfall name %s.' % wn) - waterfall_names.add(wn) - - def testCantBeBothTypesOfAFDO(self): - """Using afdo_generate and afdo_use together doesn't work.""" - for config in cbuildbot_config.GetConfig().values(): - self.assertFalse(config['afdo_use'] and config['afdo_generate']) - self.assertFalse(config['afdo_use'] and config['afdo_generate_min']) - self.assertFalse(config['afdo_generate'] and config['afdo_generate_min']) - - def testValidPrebuilts(self): - """Verify all builders have valid prebuilt values.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - msg = 'Config %s: has unexpected prebuilts value.' % build_name - valid_values = (False, constants.PRIVATE, constants.PUBLIC) - self.assertTrue(config['prebuilts'] in valid_values, msg) - - def testInternalPrebuilts(self): - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if (config['internal'] and - config['build_type'] != constants.CHROME_PFQ_TYPE): - msg = 'Config %s is internal but has public prebuilts.' % build_name - self.assertNotEqual(config['prebuilts'], constants.PUBLIC, msg) - - def testValidHWTestPriority(self): - """Verify that hw test priority is valid.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - for test_config in config['hw_tests']: - self.assertTrue( - test_config.priority in constants.HWTEST_VALID_PRIORITIES, - '%s has an invalid hwtest priority.' % build_name) - - def testAllBoardsExist(self): - """Verifies that all config boards are in _all_boards.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - for board in config['boards']: - # pylint: disable=protected-access - self.assertIn(board, cbuildbot_config._all_boards, - 'Config %s has unknown board %s.' % - (build_name, board)) - - def testPushImagePaygenDependancies(self): - """Paygen requires PushImage.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - - # paygen can't complete without push_image, except for payloads - # where --channel arguments meet the requirements. - if config['paygen']: - self.assertTrue(config['push_image'] or - config['build_type'] == constants.PAYLOADS_TYPE, - '%s has paygen without push_image' % build_name) - - def testPaygenTestDependancies(self): - """paygen testing requires upload_hw_test_artifacts.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - - # This requirement doesn't apply to payloads builds. Payloads are - # using artifacts from a previous build. - if build_name.endswith('-payloads'): - continue - - if config['paygen'] and not config['paygen_skip_testing']: - self.assertTrue(config['upload_hw_test_artifacts'], - '%s is not upload_hw_test_artifacts, but also not' - ' paygen_skip_testing' % build_name) - - def testBuildPackagesForRecoveryImage(self): - """Tests that we build the packages required for recovery image.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if 'recovery' in config.images: - if not config.packages: - # No packages are specified. Defaults to build all packages. - continue - - self.assertIn('chromeos-base/chromeos-initramfs', - config.packages, - '%s does not build chromeos-initramfs, which is required ' - 'for creating the recovery image' % build_name) - - def testBuildRecoveryImageFlags(self): - """Ensure the right flags are disabled when building the recovery image.""" - incompatible_flags = ['paygen', 'signer_tests'] - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - for flag in incompatible_flags: - if config[flag] and config.build_type != constants.PAYLOADS_TYPE: - self.assertIn('recovery', config.images, - '%s does not build the recovery image, which is ' - 'incompatible with %s=True' % (build_name, flag)) - - def testBuildBaseImageForRecoveryImage(self): - """Tests that we build the packages required for recovery image.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if 'recovery' in config.images: - self.assertIn('base', config.images, - '%s does not build the base image, which is required for ' - 'building the recovery image' % build_name) - - def testChildConfigsNotImportantInReleaseGroup(self): - """Verify that configs in an important group are not important.""" - msg = ('Child config %s for %s should not be important because %s is ' - 'already important') - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if build_name.endswith('-release-group') and config['important']: - for child_config in config.child_configs: - self.assertFalse(child_config.important, - msg % (child_config.name, build_name, build_name)) - - def testFullCQBuilderDoNotRunHWTest(self): - """Full CQ configs should not run HWTest.""" - msg = ('%s should not be a full builder and run HWTest for ' - 'performance reasons') - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if config.build_type == constants.PALADIN_TYPE: - self.assertFalse(config.chrome_binhost_only and config.hw_tests, - msg % build_name) - - def testExternalConfigsDoNotUseInternalFeatures(self): - """External configs should not use chrome_internal, or official.xml.""" - msg = ('%s is not internal, so should not use chrome_internal, or an ' - 'internal manifest') - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - if not config['internal']: - self.assertFalse('chrome_internal' in config['useflags'], - msg % build_name) - self.assertNotEqual(config.get('manifest'), - constants.OFFICIAL_MANIFEST, - msg % build_name) - - def testNoShadowedUseflags(self): - """Configs should not have both useflags x and -x.""" - msg = ('%s contains useflag %s and -%s.') - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - useflag_set = set(config['useflags']) - for flag in useflag_set: - if not flag.startswith('-'): - self.assertFalse('-' + flag in useflag_set, - msg % (build_name, flag, flag)) - - def testHealthCheckEmails(self): - """Configs should only have valid email addresses or aliases""" - msg = ('%s contains an invalid tree alias or email address: %s') - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - health_alert_recipients = config['health_alert_recipients'] - for recipient in health_alert_recipients: - self.assertTrue(re.match(r'[^@]+@[^@]+\.[^@]+', recipient) or - recipient in constants.SHERIFF_TYPE_TO_URL.keys(), - msg % (build_name, recipient)) - - def testCheckBuilderClass(self): - """Verify builder_class_name is a valid value.""" - for build_name, config in cbuildbot_config.GetConfig().iteritems(): - builder_class_name = config['builder_class_name'] - if builder_class_name is None: - continue - - cls = builders.GetBuilderClass(builder_class_name) - self.assertTrue(issubclass(cls, generic_builders.Builder), - msg=('config %s has a broken builder_class_name' % - build_name)) - - -class FindFullTest(cros_test_lib.TestCase): - """Test locating of official build for a board.""" - - def _RunTest(self, board, external_expected=None, internal_expected=None): - def check_expected(l, expected): - if expected is not None: - self.assertTrue(expected in [v['name'] for v in l]) - - external, internal = cbuildbot_config.FindFullConfigsForBoard(board) - self.assertFalse( - all(v is None for v in [external_expected, internal_expected])) - check_expected(external, external_expected) - check_expected(internal, internal_expected) - - def _CheckCanonicalConfig(self, board, ending): - self.assertEquals( - '-'.join((board, ending)), - cbuildbot_config.FindCanonicalConfigForBoard(board)['name']) - - def testExternal(self): - """Test finding of a full builder.""" - self._RunTest('amd64-generic', external_expected='amd64-generic-full') - - def testInternal(self): - """Test finding of a release builder.""" - self._RunTest('lumpy', internal_expected='lumpy-release') - - def testBoth(self): - """Both an external and internal config exist for board.""" - self._RunTest('daisy', external_expected='daisy-full', - internal_expected='daisy-release') - - def testExternalCanonicalResolution(self): - """Test an external canonical config.""" - self._CheckCanonicalConfig('x86-generic', 'full') - - def testInternalCanonicalResolution(self): - """Test prefer internal over external when both exist.""" - self._CheckCanonicalConfig('daisy', 'release') - - def testAFDOCanonicalResolution(self): - """Test prefer non-AFDO over AFDO builder.""" - self._CheckCanonicalConfig('lumpy', 'release') - - def testOneFullConfigPerBoard(self): - """There is at most one 'full' config for a board.""" - # Verifies that there is one external 'full' and one internal 'release' - # build per board. This is to ensure that we fail any new configs that - # wrongly have names like *-bla-release or *-bla-full. This case can also - # be caught if the new suffix was added to - # cbuildbot_config.CONFIG_TYPE_DUMP_ORDER - # (see testNonOverlappingConfigTypes), but that's not guaranteed to happen. - def AtMostOneConfig(board, label, configs): - if len(configs) > 1: - self.fail( - 'Found more than one %s config for %s: %r' - % (label, board, [c['name'] for c in configs])) - - boards = set() - for config in cbuildbot_config.GetConfig().itervalues(): - boards.update(config['boards']) - # Sanity check of the boards. - assert boards - - for b in boards: - # TODO(akeshet): Figure out why we have both panther_embedded-minimal - # release and panther_embedded-release, and eliminate one of them. - if b == 'panther_embedded': - continue - external, internal = cbuildbot_config.FindFullConfigsForBoard(b) - AtMostOneConfig(b, 'external', external) - AtMostOneConfig(b, 'internal', internal) - - -class OverrideForTrybotTest(cros_test_lib.TestCase): - """Test config override functionality.""" - - def _testWithOptions(self, **kwargs): - mock_options = mock.Mock() - for k, v in kwargs.iteritems(): - mock_options.setattr(k, v) - - for config in cbuildbot_config.GetConfig().itervalues(): - cbuildbot_config.OverrideConfigForTrybot(config, mock_options) - - def testLocalTrybot(self): - """Override each config for local trybot.""" - self._testWithOptions(remote_trybot=False, hw_test=False) - - def testRemoteTrybot(self): - """Override each config for remote trybot.""" - self._testWithOptions(remote_trybot=True, hw_test=False) - - def testRemoteHWTest(self): - """Override each config for remote trybot + hwtests.""" - self._testWithOptions(remote_trybot=True, hw_test=True) - - def testChromeInternalOverride(self): - """Verify that we are not using official Chrome for local trybots.""" - mock_options = mock.Mock() - mock_options.remote_trybot = False - mock_options.hw_test = False - old = cbuildbot_config.GetConfig()['x86-mario-paladin'] - new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options) - self.assertTrue(constants.USE_CHROME_INTERNAL in old['useflags']) - self.assertFalse(constants.USE_CHROME_INTERNAL in new['useflags']) - - def testVmTestOverride(self): - """Verify that vm_tests override for trybots pay heed to original config.""" - mock_options = mock.Mock() - old = cbuildbot_config.GetConfig()['x86-mario-paladin'] - new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options) - self.assertEquals(new['vm_tests'], [constants.SMOKE_SUITE_TEST_TYPE, - constants.SIMPLE_AU_TEST_TYPE, - constants.CROS_VM_TEST_TYPE]) - - # Don't override vm tests for arm boards. - old = cbuildbot_config.GetConfig()['daisy-paladin'] - new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options) - self.assertEquals(new['vm_tests'], old['vm_tests']) - - # Don't override vm tests for brillo boards. - old = cbuildbot_config.GetConfig()['storm-paladin'] - new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options) - self.assertEquals(new['vm_tests'], old['vm_tests']) - - # pylint: disable=protected-access - def testWaterfallManualConfigIsValid(self): - """Verify the correctness of the manual waterfall configuration.""" - all_build_names = set(cbuildbot_config.GetConfig().iterkeys()) - redundant = set() - seen = set() - for waterfall, names in cbuildbot_config._waterfall_config_map.iteritems(): - for build_name in names: - # Every build in the configuration map must be valid. - self.assertTrue(build_name in all_build_names, - "Invalid build name in manual waterfall config: %s" % ( - build_name,)) - # No build should appear in multiple waterfalls. - self.assertFalse(build_name in seen, - "Duplicate manual config for board: %s" % ( - build_name,)) - seen.add(build_name) - - # The manual configuration must be applied and override any default - # configuration. - config = cbuildbot_config.GetConfig()[build_name] - self.assertEqual(config['active_waterfall'], waterfall, - "Manual waterfall membership is not in the " - "configuration for: %s" % (build_name,)) - - - default_waterfall = cbuildbot_config.GetDefaultWaterfall(config) - if config['active_waterfall'] == default_waterfall: - redundant.add(build_name) - - # No configurations should be redundant with defaults. - self.assertFalse(redundant, - "Manual waterfall configs are automatically included: " - "%s" % (sorted(redundant),)) - - def testNoDuplicateCanaryBuildersOnWaterfall(self): - seen = {} - for config in cbuildbot_config.GetConfig().itervalues(): - waterfall = config['active_waterfall'] - btype = config['build_type'] - if not (waterfall and cbuildbot_config.IsCanaryType(btype)): - continue - - waterfall_seen = seen.setdefault(waterfall, set()) - stack = [config] - while stack: - current_config = stack.pop() - self.assertNotIn(current_config['name'], waterfall_seen, - "Multiple builders for '%s' on '%s' waterfall" % ( - current_config['name'], waterfall)) - waterfall_seen.add(current_config['name']) - stack += current_config['child_configs'] - def testBinhostTest(self): - """Builders with the binhost_test setting shouldn't have boards.""" - for config in cbuildbot_config.GetConfig().values(): - if config.binhost_test: - self.assertEqual(config.boards, []) +class PlaceholderTest(cros_test_lib.TestCase): + """Maintaining this file for future tests!""" |