b82b860511a9c93db31131a85877597ed297f3b1
[platform/framework/web/crosswalk.git] / src / third_party / chromite / cbuildbot / cbuildbot_config_unittest.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Unittests for config.  Needs to be run inside of chroot for mox."""
7
8 from __future__ import print_function
9
10 import mock
11 import os
12 import cPickle
13 import sys
14
15 import constants
16 sys.path.insert(0, constants.SOURCE_ROOT)
17 from chromite.cbuildbot import cbuildbot_config
18 from chromite.lib import cros_build_lib
19 from chromite.lib import cros_test_lib
20 from chromite.lib import git
21 from chromite.lib import osutils
22
23 CHROMIUM_WATCHING_URL = ('http://src.chromium.org/chrome/trunk/tools/build/'
24     'masters/master.chromium.chromiumos/master_chromiumos_cros_cfg.py')
25
26
27 class ConfigDumpTest(cros_test_lib.TestCase):
28   """Tests related to config_dump.json & cbuildbot_config.py"""
29
30   def testDump(self):
31     """Make sure the json & config are kept in sync"""
32     cmd = [os.path.join(constants.CHROMITE_BIN_DIR, 'cbuildbot_view_config'),
33            '-d', '--pretty']
34     dump_file_path = os.path.join(constants.CHROMITE_DIR, 'cbuildbot',
35                                   'config_dump.json')
36     new_dump = cros_build_lib.RunCommand(cmd, capture_output=True).output
37     old_dump = osutils.ReadFile(dump_file_path)
38     self.assertTrue(
39         new_dump == old_dump, 'config_dump.json does not match the '
40         'configs defined in cbuildbot_config.py. Run '
41         'bin/cbuildbot_view_config -d --pretty > cbuildbot/config_dump.json')
42
43
44 class ConfigPickleTest(cros_test_lib.TestCase):
45   """Test that a config object is pickleable."""
46
47   def testPickle(self):
48     bc1 = cbuildbot_config.config['x86-mario-paladin']
49     bc2 = cPickle.loads(cPickle.dumps(bc1))
50
51     self.assertEquals(bc1.boards, bc2.boards)
52     self.assertEquals(bc1.name, bc2.name)
53
54
55 class ConfigClassTest(cros_test_lib.TestCase):
56   """Tests of the config class itself."""
57
58   def testValueAccess(self):
59     cfg = cbuildbot_config.config['x86-mario-paladin']
60
61     self.assertTrue(cfg.name)
62     self.assertEqual(cfg.name, cfg['name'])
63
64     self.assertRaises(AttributeError, getattr, cfg, 'foobar')
65
66
67 class CBuildBotTest(cros_test_lib.MoxTestCase):
68   """General tests of cbuildbot_config with respect to cbuildbot."""
69
70   def testConfigsKeysMismatch(self):
71     """Verify that all configs contain exactly the default keys.
72
73     This checks for mispelled keys, or keys that are somehow removed.
74     """
75     # pylint: disable=W0212
76     expected_keys = set(cbuildbot_config._default.keys())
77     for build_name, config in cbuildbot_config.config.iteritems():
78       config_keys = set(config.keys())
79
80       extra_keys = config_keys.difference(expected_keys)
81       self.assertFalse(extra_keys, ('Config %s has extra values %s' %
82                                     (build_name, list(extra_keys))))
83
84       missing_keys = expected_keys.difference(config_keys)
85       self.assertFalse(missing_keys, ('Config %s is missing values %s' %
86                                       (build_name, list(missing_keys))))
87
88   def testConfigsHaveName(self):
89     """Configs must have names set."""
90     for build_name, config in cbuildbot_config.config.iteritems():
91       self.assertTrue(build_name == config['name'])
92
93   def testConfigUseflags(self):
94     """Useflags must be lists.
95
96     Strings are interpreted as arrays of characters for this, which is not
97     useful.
98     """
99     for build_name, config in cbuildbot_config.config.iteritems():
100       useflags = config.get('useflags')
101       if not useflags is None:
102         self.assertTrue(
103           isinstance(useflags, list),
104           'Config %s: useflags should be a list.' % build_name)
105
106   def testBoards(self):
107     """Verify 'boards' is explicitly set for every config."""
108     for build_name, config in cbuildbot_config.config.iteritems():
109       self.assertTrue(isinstance(config['boards'], (tuple, list)),
110                       "Config %s doesn't have a list of boards." % build_name)
111       self.assertEqual(len(set(config['boards'])), len(config['boards']),
112                        'Config %s has duplicate boards.' % build_name)
113       self.assertTrue(config['boards'] is not None,
114                       'Config %s defines a list of boards.' % build_name)
115
116   def testOverlaySettings(self):
117     """Verify overlays and push_overlays have legal values."""
118     for build_name, config in cbuildbot_config.config.iteritems():
119       overlays = config['overlays']
120       push_overlays = config['push_overlays']
121
122       self.assertTrue(overlays in [None, 'public', 'private', 'both'],
123                       'Config %s: has unexpected overlays value.' % build_name)
124       self.assertTrue(
125           push_overlays in [None, 'public', 'private', 'both'],
126           'Config %s: has unexpected push_overlays value.' % build_name)
127
128       if overlays == None:
129         subset = [None]
130       elif overlays == 'public':
131         subset = [None, 'public']
132       elif overlays == 'private':
133         subset = [None, 'private']
134       elif overlays == 'both':
135         subset = [None, 'public', 'private', 'both']
136
137       self.assertTrue(
138           push_overlays in subset,
139           'Config %s: push_overlays should be a subset of overlays.' %
140               build_name)
141
142   def testOverlayMaster(self):
143     """Verify that only one master is pushing uprevs for each overlay."""
144     masters = {}
145     for build_name, config in cbuildbot_config.config.iteritems():
146       overlays = config['overlays']
147       push_overlays = config['push_overlays']
148       if (overlays and push_overlays and config['uprev'] and config['master']
149           and not config['branch']):
150         other_master = masters.get(push_overlays)
151         err_msg = 'Found two masters for push_overlays=%s: %s and %s'
152         self.assertFalse(other_master,
153             err_msg % (push_overlays, build_name, other_master))
154         masters[push_overlays] = build_name
155
156     if 'both' in masters:
157       self.assertEquals(len(masters), 1, 'Found too many masters.')
158
159   def testChromeRev(self):
160     """Verify chrome_rev has an expected value"""
161     for build_name, config in cbuildbot_config.config.iteritems():
162       self.assertTrue(
163           config['chrome_rev'] in constants.VALID_CHROME_REVISIONS + [None],
164           'Config %s: has unexpected chrome_rev value.' % build_name)
165       self.assertFalse(
166           config['chrome_rev'] == constants.CHROME_REV_LOCAL,
167           'Config %s: has unexpected chrome_rev_local value.' % build_name)
168       if config['chrome_rev']:
169         self.assertTrue(cbuildbot_config.IsPFQType(config['build_type']),
170           'Config %s: has chrome_rev but is not a PFQ.' % build_name)
171
172   def testValidVMTestType(self):
173     """Verify vm_tests has an expected value"""
174     for build_name, config in cbuildbot_config.config.iteritems():
175       for test_type in config['vm_tests']:
176         self.assertTrue(
177           test_type in constants.VALID_VM_TEST_TYPES,
178           'Config %s: has unexpected vm test type value.' % build_name)
179
180   def testImageTestMustHaveBaseImage(self):
181     """Verify image_test build is only enabled with 'base' in images."""
182     for build_name, config in cbuildbot_config.config.iteritems():
183       if config.get('image_test', False):
184         self.assertTrue('base' in config['images'],
185                         'Build %s runs image_test but does not have base img' %
186                         build_name)
187
188   def testBuildType(self):
189     """Verifies that all configs use valid build types."""
190     for build_name, config in cbuildbot_config.config.iteritems():
191       self.assertTrue(
192           config['build_type'] in constants.VALID_BUILD_TYPES,
193           'Config %s: has unexpected build_type value.' % build_name)
194
195   def testGCCGitHash(self):
196     """Verifies that gcc_githash is not set without setting latest_toolchain."""
197     for build_name, config in cbuildbot_config.config.iteritems():
198       if config['gcc_githash']:
199         self.assertTrue(
200             config['latest_toolchain'],
201             'Config %s: has gcc_githash but not latest_toolchain.' % build_name)
202
203   def testBuildToRun(self):
204     """Verify we don't try to run tests without building them."""
205     for build_name, config in cbuildbot_config.config.iteritems():
206       self.assertFalse(
207           isinstance(config['useflags'], list) and
208           '-build_tests' in config['useflags'] and config['vm_tests'],
209           'Config %s: has vm_tests and use -build_tests.' % build_name)
210
211   def testSyncToChromeSdk(self):
212     """Verify none of the configs build chrome sdk but don't sync chrome."""
213     for build_name, config in cbuildbot_config.config.iteritems():
214       if config['sync_chrome'] is not None and not config['sync_chrome']:
215         self.assertFalse(
216             config['chrome_sdk'],
217             'Config %s: has chrome_sdk but not sync_chrome.' % build_name)
218
219   def testNoTestSupport(self):
220     """VM/unit tests shouldn't be enabled for builders without test support."""
221     for build_name, config in cbuildbot_config.config.iteritems():
222       if not config['tests_supported']:
223         self.assertFalse(
224             config['unittests'],
225             'Config %s: has tests_supported but unittests=True.' % build_name)
226         self.assertEqual(
227             config['vm_tests'], [],
228             'Config %s: has test_supported but requests vm_tests.' % build_name)
229
230   def testHWTestsIFFArchivingHWTestArtifacts(self):
231     """Make sure all configs upload artifacts that need them for hw testing."""
232     for build_name, config in cbuildbot_config.config.iteritems():
233       if config['hw_tests']:
234         self.assertTrue(
235             config['upload_hw_test_artifacts'],
236             "%s is trying to run hw tests without uploading payloads." %
237             build_name)
238
239   def testValidUnifiedMasterConfig(self):
240     """Make sure any unified master configurations are valid."""
241     for build_name, config in cbuildbot_config.config.iteritems():
242       error = 'Unified config for %s has invalid values' % build_name
243       # Unified masters must be internal and must rev both overlays.
244       if config['master']:
245         self.assertTrue(
246             config['internal'] and config['manifest_version'], error)
247       elif not config['master'] and config['manifest_version']:
248         # Unified slaves can rev either public or both depending on whether
249         # they are internal or not.
250         if not config['internal']:
251           self.assertEqual(config['overlays'], constants.PUBLIC_OVERLAYS, error)
252         elif cbuildbot_config.IsCQType(config['build_type']):
253           self.assertEqual(config['overlays'], constants.BOTH_OVERLAYS, error)
254
255   def testGetSlaves(self):
256     """Make sure every master has a sane list of slaves"""
257     for build_name, config in cbuildbot_config.config.iteritems():
258       if config['master']:
259         configs = cbuildbot_config.GetSlavesForMaster(config)
260         self.assertEqual(
261             len(map(repr, configs)), len(set(map(repr, configs))),
262             'Duplicate board in slaves of %s will cause upload prebuilts'
263             ' failures' % build_name)
264
265   def testFactoryFirmwareValidity(self):
266     """Ensures that firmware/factory branches have at least 1 valid name."""
267     tracking_branch = git.GetChromiteTrackingBranch()
268     for branch in ['firmware', 'factory']:
269       if tracking_branch.startswith(branch):
270         saw_config_for_branch = False
271         for build_name in cbuildbot_config.config:
272           if build_name.endswith('-%s' % branch):
273             self.assertFalse('release' in build_name,
274                              'Factory|Firmware release builders should not '
275                              'contain release in their name.')
276             saw_config_for_branch = True
277
278         self.assertTrue(
279             saw_config_for_branch, 'No config found for %s branch. '
280             'As this is the %s branch, all release configs that are being used '
281             'must end in %s.' % (branch, tracking_branch, branch))
282
283   def testBuildTests(self):
284     """Verify that we don't try to use tests without building them."""
285
286     for build_name, config in cbuildbot_config.config.iteritems():
287       if not config['build_tests']:
288         for flag in ('factory_toolkit', 'vm_tests', 'hw_tests'):
289           self.assertFalse(config[flag],
290               'Config %s set %s without build_tests.' % (build_name, flag))
291
292   def testAFDOInBackground(self):
293     """Verify that we don't try to build or use AFDO data in the background."""
294     for build_name, config in cbuildbot_config.config.iteritems():
295       if config.build_packages_in_background:
296         # It is unsupported to use the build_packages_in_background flags with
297         # the afdo_generate or afdo_generate_min config options.
298         msg = 'Config %s uses build_packages_in_background with afdo_%s'
299         self.assertFalse(config.afdo_generate, msg % (build_name, 'generate'))
300         self.assertFalse(config.afdo_generate_min, msg % (build_name,
301                                                           'generate_min'))
302
303   def testReleaseGroupInBackground(self):
304     """Verify build_packages_in_background settings for release groups.
305
306     For each release group, the first builder should be set to run in the
307     foreground (to build binary packages), and the remainder of the builders
308     should be set to run in parallel (to install the binary packages.)
309     """
310     for build_name, config in cbuildbot_config.config.iteritems():
311       if build_name.endswith('-release-group'):
312         msg = 'Config %s should not build_packages_in_background'
313         self.assertFalse(config.build_packages_in_background, msg % build_name)
314
315         self.assertTrue(config.child_configs,
316             'Config %s should have child configs' % build_name)
317         first_config = config.child_configs[0]
318         msg = 'Primary config for %s should not build_packages_in_background'
319         self.assertFalse(first_config.build_packages_in_background,
320             msg % build_name)
321
322         msg = 'Child config %s for %s should build_packages_in_background'
323         for child_config in config.child_configs[1:]:
324           self.assertTrue(child_config.build_packages_in_background,
325               msg % (child_config.name, build_name))
326
327   def testAFDOSameInChildConfigs(self):
328     """Verify that 'afdo_use' is the same for all children in a group."""
329     msg = ('Child config %s for %s should have same value for afdo_use '
330            'as other children')
331     for build_name, config in cbuildbot_config.config.iteritems():
332       if build_name.endswith('-group'):
333         prev_value = None
334         self.assertTrue(config.child_configs,
335             'Config %s should have child configs' % build_name)
336         for child_config in config.child_configs:
337           if prev_value is None:
338             prev_value = child_config.afdo_use
339           else:
340             self.assertEqual(child_config.afdo_use, prev_value,
341                 msg % (child_config.name, build_name))
342
343   def testReleaseAFDOConfigs(self):
344     """Verify that <board>-release-afdo config have generate and use children.
345
346     These configs should have a 'generate' and a 'use' child config. Also,
347     any 'generate' and 'use' configs should be children of a release-afdo
348     config.
349     """
350     msg = 'Config %s should have %s as a parent'
351     parent_suffix = cbuildbot_config.CONFIG_TYPE_RELEASE_AFDO
352     generate_suffix = '%s-generate' % parent_suffix
353     use_suffix = '%s-use' % parent_suffix
354     for build_name, config in cbuildbot_config.config.iteritems():
355       if build_name.endswith(parent_suffix):
356         self.assertEqual(len(config.child_configs), 2,
357             'Config %s should have 2 child configs' % build_name)
358         for child_config in config.child_configs:
359           child_name = child_config.name
360           self.assertTrue(child_name.endswith(generate_suffix) or
361                           child_name.endswith(use_suffix),
362                           'Config %s has wrong %s child' %
363                           (build_name, child_config))
364       if build_name.endswith(generate_suffix):
365         parent_config_name = build_name.replace(generate_suffix,
366                                                 parent_suffix)
367         self.assertTrue(parent_config_name in cbuildbot_config.config,
368                         msg % (build_name, parent_config_name))
369       if build_name.endswith(use_suffix):
370         parent_config_name = build_name.replace(use_suffix,
371                                                 parent_suffix)
372         self.assertTrue(parent_config_name in cbuildbot_config.config,
373                         msg % (build_name, parent_config_name))
374
375   def testNoGrandChildConfigs(self):
376     """Verify that no child configs have a child config."""
377     for build_name, config in cbuildbot_config.config.iteritems():
378       for child_config in config.child_configs:
379         for grandchild_config in child_config.child_configs:
380           self.fail('Config %s has grandchild %s' % (build_name,
381                                                      grandchild_config.name))
382
383   def testUseChromeLKGMImpliesInternal(self):
384     """Currently use_chrome_lkgm refers only to internal manifests."""
385     for build_name, config in cbuildbot_config.config.iteritems():
386       if config['use_chrome_lkgm']:
387         self.assertTrue(config['internal'],
388             'Chrome lkgm currently only works with an internal manifest: %s' % (
389                 build_name,))
390
391   def testNonOverlappingConfigTypes(self):
392     """Test that a config can only match one build suffix."""
393     for config_type in cbuildbot_config.CONFIG_TYPE_DUMP_ORDER:
394       # A longer config_type should never end with a shorter suffix.
395       my_list = list(cbuildbot_config.CONFIG_TYPE_DUMP_ORDER)
396       my_list.remove(config_type)
397       self.assertEquals(
398           cbuildbot_config.GetDisplayPosition(
399               config_type, type_order=my_list),
400           len(my_list))
401
402   def testCorrectConfigTypeIndex(self):
403     """Test that the correct build suffix index is returned."""
404     type_order = (
405         'type1',
406         'donkey-type2',
407         'kong-type3')
408
409     for index, config_type in enumerate(type_order):
410       config = '-'.join(['pre-fix', config_type])
411       self.assertEquals(
412           cbuildbot_config.GetDisplayPosition(
413               config, type_order=type_order),
414           index)
415
416     # Verify suffix needs to match up to a '-'.
417     self.assertEquals(
418         cbuildbot_config.GetDisplayPosition(
419             'pre-fix-sometype1', type_order=type_order),
420         len(type_order))
421
422   def testConfigTypesComplete(self):
423     """Verify CONFIG_TYPE_DUMP_ORDER contains all valid config types."""
424     for config_name in cbuildbot_config.config:
425       self.assertNotEqual(
426           cbuildbot_config.GetDisplayPosition(config_name),
427           len(cbuildbot_config.CONFIG_TYPE_DUMP_ORDER),
428           '%s did not match any types in %s' %
429           (config_name, 'cbuildbot_config.CONFIG_TYPE_DUMP_ORDER'))
430
431   def testCantBeBothTypesOfLKGM(self):
432     """Using lkgm and chrome_lkgm doesn't make sense."""
433     for config in cbuildbot_config.config.values():
434       self.assertFalse(config['use_lkgm'] and config['use_chrome_lkgm'])
435
436   def testNoDuplicateSlavePrebuilts(self):
437     """Test that no two same-board paladin slaves upload prebuilts."""
438     for cfg in cbuildbot_config.config.values():
439       if (cfg['build_type'] == constants.PALADIN_TYPE and cfg['master']):
440         slaves = cbuildbot_config.GetSlavesForMaster(cfg)
441         prebuilt_slaves = [s for s in slaves if s['prebuilts']]
442         # Dictionary from board name to builder name that uploads prebuilt
443         prebuilt_slave_boards = {}
444         for slave in prebuilt_slaves:
445           for board in slave['boards']:
446             self.assertFalse(prebuilt_slave_boards.has_key(board),
447                              'Configs %s and %s both upload prebuilts for '
448                              'board %s.' % (prebuilt_slave_boards.get(board),
449                                             slave['name'],
450                                             board))
451             prebuilt_slave_boards[board] = slave['name']
452
453   def testCantBeBothTypesOfAFDO(self):
454     """Using afdo_generate and afdo_use together doesn't work."""
455     for config in cbuildbot_config.config.values():
456       self.assertFalse(config['afdo_use'] and config['afdo_generate'])
457       self.assertFalse(config['afdo_use'] and config['afdo_generate_min'])
458       self.assertFalse(config['afdo_generate'] and config['afdo_generate_min'])
459
460   def testValidPrebuilts(self):
461     """Verify all builders have valid prebuilt values."""
462     for build_name, config in cbuildbot_config.config.iteritems():
463       msg = 'Config %s: has unexpected prebuilts value.' % build_name
464       valid_values = (False, constants.PRIVATE, constants.PUBLIC)
465       self.assertTrue(config['prebuilts'] in valid_values, msg)
466
467   def testInternalPrebuilts(self):
468     for build_name, config in cbuildbot_config.config.iteritems():
469       if (config['internal'] and
470           config['build_type'] != constants.CHROME_PFQ_TYPE):
471         msg = 'Config %s is internal but has public prebuilts.' % build_name
472         self.assertNotEqual(config['prebuilts'], constants.PUBLIC, msg)
473
474   def testValidHWTestPriority(self):
475     """Verify that hw test priority is valid."""
476     for build_name, config in cbuildbot_config.config.iteritems():
477       for test_config in config['hw_tests']:
478         self.assertTrue(
479             test_config.priority in constants.HWTEST_VALID_PRIORITIES,
480             '%s has an invalid hwtest priority.' % build_name)
481
482   def testPushImagePaygenDependancies(self):
483     """Paygen requires PushImage."""
484     for build_name, config in cbuildbot_config.config.iteritems():
485
486       # paygen can't complete without push_image, except for payloads
487       # where --channel arguments meet the requirements.
488       if config['paygen']:
489         self.assertTrue(config['push_image'] or
490                         config['build_type'] == constants.PAYLOADS_TYPE,
491                         '%s has paygen without push_image' % build_name)
492
493   def testPaygenTestDependancies(self):
494     """paygen testing requires upload_hw_test_artifacts."""
495     for build_name, config in cbuildbot_config.config.iteritems():
496
497       # This requirement doesn't apply to payloads builds. Payloads are
498       # using artifacts from a previous build.
499       if build_name.endswith('-payloads'):
500         continue
501
502       if config['paygen'] and not config['paygen_skip_testing']:
503         self.assertTrue(config['upload_hw_test_artifacts'],
504                         '%s is not upload_hw_test_artifacts, but also not'
505                         ' paygen_skip_testing' % build_name)
506
507   def testBuildPackagesForRecoveryImage(self):
508     """Tests that we build the packages required for recovery image."""
509     for build_name, config in cbuildbot_config.config.iteritems():
510       if config['images']:
511         # If we build any image, the base image will be built, and the
512         # recovery image will be created.
513         if not config['packages']:
514           # No packages are specified. Defaults to build all packages.
515           continue
516
517         self.assertIn('chromeos-base/chromeos-initramfs',
518                       config['packages'],
519                       '%s does not build chromeos-initramfs, which is required '
520                       'for creating the recovery image' % build_name)
521
522   def testChildConfigsNotImportantInReleaseGroup(self):
523     """Verify that configs in an important group are not important."""
524     msg = ('Child config %s for %s should not be important because %s is '
525            'already important')
526     for build_name, config in cbuildbot_config.config.iteritems():
527       if build_name.endswith('-release-group') and config['important']:
528         for child_config in config.child_configs:
529           self.assertFalse(child_config.important,
530                            msg % (child_config.name, build_name, build_name))
531
532   def testFullCQBuilderDoNotRunHWTest(self):
533     """Full CQ configs should not run HWTest."""
534     msg = ('%s should not be a full builder and run HWTest for '
535            'performance reasons')
536     for build_name, config in cbuildbot_config.config.iteritems():
537       if config.build_type == constants.PALADIN_TYPE:
538         self.assertFalse(config.chrome_binhost_only and config.hw_tests,
539                          msg % build_name)
540
541
542 class FindFullTest(cros_test_lib.TestCase):
543   """Test locating of official build for a board."""
544
545   def _RunTest(self, board, external_expected=None, internal_expected=None):
546     def check_expected(l, expected):
547       if expected is not None:
548         self.assertTrue(expected in [v['name'] for v in l])
549
550     external, internal = cbuildbot_config.FindFullConfigsForBoard(board)
551     self.assertFalse(
552         all(v is None for v in [external_expected, internal_expected]))
553     check_expected(external, external_expected)
554     check_expected(internal, internal_expected)
555
556   def _CheckCanonicalConfig(self, board, ending):
557     self.assertEquals(
558         '-'.join((board, ending)),
559         cbuildbot_config.FindCanonicalConfigForBoard(board)['name'])
560
561   def testExternal(self):
562     """Test finding of a full builder."""
563     self._RunTest('amd64-generic', external_expected='amd64-generic-full')
564
565   def testInternal(self):
566     """Test finding of a release builder."""
567     self._RunTest('lumpy', internal_expected='lumpy-release')
568
569   def testBoth(self):
570     """Both an external and internal config exist for board."""
571     self._RunTest('daisy', external_expected='daisy-full',
572                   internal_expected='daisy-release')
573
574   def testExternalCanonicalResolution(self):
575     """Test an external canonical config."""
576     self._CheckCanonicalConfig('x86-generic', 'full')
577
578   def testInternalCanonicalResolution(self):
579     """Test prefer internal over external when both exist."""
580     self._CheckCanonicalConfig('daisy', 'release')
581
582   def testAFDOCanonicalResolution(self):
583     """Test prefer non-AFDO over AFDO builder."""
584     self._CheckCanonicalConfig('lumpy', 'release')
585
586   def testOneFullConfigPerBoard(self):
587     """There is at most one 'full' config for a board."""
588     # Verifies that there is one external 'full' and one internal 'release'
589     # build per board.  This is to ensure that we fail any new configs that
590     # wrongly have names like *-bla-release or *-bla-full. This case can also
591     # be caught if the new suffix was added to
592     # cbuildbot_config.CONFIG_TYPE_DUMP_ORDER
593     # (see testNonOverlappingConfigTypes), but that's not guaranteed to happen.
594     def AtMostOneConfig(board, label, configs):
595       if len(configs) > 1:
596         self.fail(
597             'Found more than one %s config for %s: %r'
598             % (label, board, [c['name'] for c in configs]))
599
600     boards = set()
601     for config in cbuildbot_config.config.itervalues():
602       boards.update(config['boards'])
603     # Sanity check of the boards.
604     assert boards
605
606     for b in boards:
607       external, internal = cbuildbot_config.FindFullConfigsForBoard(b)
608       AtMostOneConfig(b, 'external', external)
609       AtMostOneConfig(b, 'internal', internal)
610
611
612 class OverrideForTrybotTest(cros_test_lib.TestCase):
613   """Test config override functionality."""
614
615   def _testWithOptions(self, **kwargs):
616     mock_options = mock.Mock()
617     for k, v in kwargs.iteritems():
618       mock_options.setattr(k, v)
619
620     for config in cbuildbot_config.config.itervalues():
621       cbuildbot_config.OverrideConfigForTrybot(config, mock_options)
622
623   def testLocalTrybot(self):
624     """Override each config for local trybot."""
625     self._testWithOptions(remote_trybot=False, hw_test=False)
626
627   def testRemoteTrybot(self):
628     """Override each config for remote trybot."""
629     self._testWithOptions(remote_trybot=True, hw_test=False)
630
631   def testRemoteHWTest(self):
632     """Override each config for remote trybot + hwtests."""
633     self._testWithOptions(remote_trybot=True, hw_test=True)
634
635   def testChromeInternalOverride(self):
636     """Verify that we are not using official Chrome for local trybots."""
637     mock_options = mock.Mock()
638     mock_options.remote_trybot = False
639     mock_options.hw_test = False
640     old = cbuildbot_config.config['x86-mario-paladin']
641     new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options)
642     self.assertTrue(constants.USE_CHROME_INTERNAL in old['useflags'])
643     self.assertFalse(constants.USE_CHROME_INTERNAL in new['useflags'])
644
645   def testVmTestOverride(self):
646     """Verify that vm_tests override for trybots pay heed to original config."""
647     mock_options = mock.Mock()
648     old = cbuildbot_config.config['x86-mario-paladin']
649     new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options)
650     self.assertEquals(new['vm_tests'], [constants.SIMPLE_AU_TEST_TYPE,
651                                         constants.CROS_VM_TEST_TYPE])
652     old['vm_tests'] = None
653     new = cbuildbot_config.OverrideConfigForTrybot(old, mock_options)
654     self.assertIsNone(new['vm_tests'])
655
656
657 if __name__ == '__main__':
658   cros_test_lib.main()