blob: e92410780952b0e51d844e33f6b119eb5e9027b6 [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 config."""
from __future__ import print_function
import copy
import pickle
import json
from chromite.lib import config_lib
from chromite.lib import cros_test_lib
# pylint: disable=protected-access
def MockBuildConfig():
"""Create a BuildConfig object for convenient testing pleasure."""
site_config = MockSiteConfig()
return site_config['amd64-generic-paladin']
def MockSiteConfig():
"""Create a SiteConfig object for convenient testing pleasure.
Shared amoung a number of unittest files, so be careful if changing it.
"""
result = config_lib.SiteConfig()
# Add a single, simple build config.
result.Add(
'amd64-generic-paladin',
boards=['amd64-generic'],
display_label='MockLabel',
build_type='paladin',
chrome_sdk=True,
chrome_sdk_build_chrome=False,
description='Commit Queue',
doc='http://mock_url/',
image_test=True,
images=['base', 'test'],
important=True,
manifest_version=True,
prebuilts='public',
upload_standalone_images=False,
vm_tests=[config_lib.VMTestConfig('smoke_suite')],
)
return result
def AssertSiteIndependentParameters(site_config):
"""Helper function to test that SiteConfigs contain site-independent values.
Args:
site_config: A SiteConfig object.
Returns:
A boolean. True if the config contained all site-independent values.
False otherwise.
"""
# Enumerate the necessary site independent parameter keys.
# All keys must be documented.
# TODO (msartori): Fill in this list.
site_independent_params = [
]
site_params = site_config.params
return all([x in site_params for x in site_independent_params])
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 BuildConfigClassTest(cros_test_lib.TestCase):
"""BuildConfig tests."""
def setUp(self):
self.fooConfig = config_lib.BuildConfig(name='foo', foo=1)
self.barConfig = config_lib.BuildConfig(name='bar', bar=2)
self.deepConfig = config_lib.BuildConfig(
name='deep', nested=[1, 2, 3], deep=3,
child_configs=[self.fooConfig, self.barConfig])
def testAppendUseflags(self):
base_config = config_lib.BuildConfig(useflags=[])
inherited_config_1 = base_config.derive(
useflags=config_lib.append_useflags(
['foo', 'bar', '-baz']))
inherited_config_2 = inherited_config_1.derive(
useflags=config_lib.append_useflags(['-bar', 'baz']))
self.assertEqual(base_config.useflags, [])
self.assertEqual(inherited_config_1.useflags, ['-baz', 'bar', 'foo'])
self.assertEqual(inherited_config_2.useflags, ['-bar', 'baz', 'foo'])
def testMockSiteConfig(self):
"""Make sure Mock generator fucntion doesn't crash."""
site_config = MockSiteConfig()
self.assertIsNotNone(site_config)
build_config = MockBuildConfig()
self.assertIsNotNone(build_config)
def testValueAccess(self):
self.assertEqual(self.fooConfig.name, 'foo')
self.assertEqual(self.fooConfig.name, self.fooConfig['name'])
self.assertRaises(AttributeError, getattr, self.fooConfig, 'foobar')
def testApplyEmpty(self):
orig = self.fooConfig.deepcopy()
# Do nothing.
self.fooConfig.apply()
self.assertEqual(self.fooConfig, orig)
def testApplyValues(self):
# Apply simple values..
self.fooConfig.apply(a=1, b=2)
self.assertEqual(self.fooConfig, dict(name='foo', foo=1, a=1, b=2))
def testApplyBuildConfig(self):
# Apply a BuildConfig.
self.fooConfig.apply(self.barConfig)
self.assertEqual(self.fooConfig, dict(name='bar', foo=1, bar=2))
def testApplyMixed(self):
# Apply simple values..
config = config_lib.BuildConfig()
config.apply(self.fooConfig, self.barConfig, a=1, b=2, bar=3)
self.assertEqual(config, dict(name='bar', foo=1, bar=3, a=1, b=2))
def testDeriveMixed(self):
config = config_lib.BuildConfig()
result = config.derive(self.fooConfig, self.barConfig, a=1, b=2, bar=3)
self.assertIsNot(config, result)
self.assertEqual(config, dict())
self.assertEqual(result, dict(name='bar', foo=1, bar=3, a=1, b=2))
def testApplyCallable(self):
# Callable that adds a configurable amount.
def append(x):
return lambda base: base + ' ' + x
site_config = config_lib.SiteConfig()
site_config.AddTemplate('add1', foo=append('one'))
site_config.AddTemplate('add2', foo=append('two'))
site_config.AddTemplate('fixed', foo='fixed')
site_config.AddTemplate('derived',
site_config.templates.add1)
site_config.AddTemplate('stacked',
site_config.templates.add1,
site_config.templates.add2)
site_config.AddTemplate('stackedDeep',
site_config.templates.fixed,
site_config.templates.add1,
site_config.templates.add1,
site_config.templates.add1,
foo=append('deep'))
site_config.AddTemplate('stackedDeeper',
site_config.templates.stacked,
site_config.templates.stackedDeep,
foo=append('deeper'))
base = config_lib.BuildConfig(foo='base')
# Basic apply.
result = base.derive(site_config.templates.add1)
self.assertEqual(result.foo, 'base one')
# Callable template + local callable.
result = base.derive(site_config.templates.add1, foo=append('local'))
self.assertEqual(result.foo, 'base one local')
# Callable template + local fixed.
result = base.derive(site_config.templates.add1, foo='local')
self.assertEqual(result.foo, 'local')
# Derived template.
result = base.derive(site_config.templates.derived)
self.assertEqual(result.foo, 'base one')
# Template with fixed override after stacking template (all callable magic
# should disappear).
result = base.derive(site_config.templates.fixed)
self.assertEqual(result.foo, 'fixed')
# Template with stacked.
result = base.derive(site_config.templates.stacked)
self.assertEqual(result.foo, 'base one two')
# Callables on top of fixed from template.
result = base.derive(site_config.templates.stackedDeep)
self.assertEqual(result.foo, 'fixed one one one deep')
# Just get crazy with it.
result = base.derive(site_config.templates.stackedDeeper)
self.assertEqual(result.foo, 'fixed one one one deep deeper')
# Ensure objects derived from weren't modified.
self.assertEqual(base.foo, 'base')
self.assertEqual(site_config.templates.fixed.foo, 'fixed')
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.
# pylint: disable=consider-using-enumerate
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 [self.fooConfig, self.barConfig, self.deepConfig]:
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, pickle.loads(pickle.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))
def testPickle(self):
bc1 = MockBuildConfig()
bc2 = pickle.loads(pickle.dumps(bc1))
self.assertEqual(bc1.boards, bc2.boards)
self.assertEqual(bc1.name, bc2.name)
class GetSiteParamsTest(cros_test_lib.TestCase):
"""Tests for the return value from config_lib.GetSiteParams()."""
def testAttributeAccess(self):
"""Test that dot-accessor works correctly."""
site_params = config_lib.GetSiteParams()
# Ensure our test key is not in site_params.
self.assertNotIn('foo', site_params)
# Test that we raise when accessing a non-existent value.
# pylint: disable=pointless-statement
with self.assertRaises(AttributeError):
site_params.foo
# Test the dot-accessor.
site_params.update({'foo': 'bar'})
self.assertEqual('bar', site_params.foo)
class SiteConfigTest(cros_test_lib.TestCase):
"""Config tests."""
@staticmethod
def _callable(x):
return x + ' extended'
def setUp(self):
self.complex_defaults = {
'value': 'default',
}
# Construct our test config.
site_config = config_lib.SiteConfig(defaults=self.complex_defaults)
site_config.AddTemplate('match', value='default')
site_config.AddTemplate('template', value='template')
site_config.AddTemplate('mixin', value='mixin')
site_config.AddTemplate('unused', value='unused')
site_config.AddTemplate('callable', value=self._callable)
default = site_config.Add('default')
default_with_override = site_config.Add(
'default_with_override',
value='override')
site_config.AddWithoutTemplate(
'default_with_mixin',
site_config.templates.mixin)
site_config.AddWithoutTemplate(
'mixin_with_override',
site_config.templates.mixin,
value='override')
site_config.Add(
'default_with_template',
site_config.templates.template)
site_config.Add(
'template_with_override',
site_config.templates.template,
value='override')
site_config.Add(
'template_with_mixin',
site_config.templates.template,
site_config.templates.mixin)
site_config.Add(
'template_with_mixin_override',
site_config.templates.template,
site_config.templates.mixin,
value='override')
site_config.Add(
'match',
value='default')
site_config.Add(
'template_back_to_default',
site_config.templates.template,
value='default')
site_config.Add(
'calling',
site_config.templates.callable)
site_config.Add(
'vm_tests',
vm_tests=[config_lib.VMTestConfig('vm_suite')],
vm_tests_override=[config_lib.VMTestConfig('vm_override')])
site_config.Add(
'hw_tests',
hw_tests=[config_lib.HWTestConfig('hw_suite')],
hw_tests_override=[config_lib.HWTestConfig('hw_override')])
site_config.Add(
'tast_vm_tests',
tast_vm_tests=[config_lib.TastVMTestConfig('tast_vm_suite',
['(!disabled)'])])
site_config.AddGroup(
'parent',
default,
default_with_override)
self.site_config = site_config
def testAddedContents(self):
"""Verify that our complex config looks like we expect, before saving."""
expected = {
'default': {
'_template': None,
'name': 'default',
'value': 'default',
},
'default_with_override': {
'_template': None,
'name': 'default_with_override',
'value': 'override',
},
'default_with_mixin': {
'_template': None,
'name': 'default_with_mixin',
'value': 'mixin',
},
'mixin_with_override': {
'_template': None,
'name': 'mixin_with_override',
'value': 'override',
},
'default_with_template': {
'_template': 'template',
'name': 'default_with_template',
'value': 'template',
},
'template_with_override': {
'_template': 'template',
'name': 'template_with_override',
'value': 'override'
},
'template_with_mixin': {
'_template': 'template',
'name': 'template_with_mixin',
'value': 'mixin',
},
'template_with_mixin_override': {
'_template': 'template',
'name': 'template_with_mixin_override',
'value': 'override'
},
'calling': {
'_template': 'callable',
'name': 'calling',
'value': 'default extended',
},
'match': {
'_template': None,
'name': 'match',
'value': 'default',
},
'template_back_to_default': {
'_template': 'template',
'name': 'template_back_to_default',
'value': 'default',
},
'vm_tests': {
'_template': None,
'name': 'vm_tests',
'vm_tests': [config_lib.VMTestConfig('vm_suite')],
'vm_tests_override': [config_lib.VMTestConfig('vm_override')],
},
'hw_tests': {
'_template': None,
'name': 'hw_tests',
'hw_tests': [config_lib.HWTestConfig('hw_suite')],
'hw_tests_override': [config_lib.HWTestConfig('hw_override')],
},
'tast_vm_tests': {
'_template': None,
'name': 'tast_vm_tests',
'tast_vm_tests': [
config_lib.TastVMTestConfig('tast_vm_suite', ['(!disabled)'])],
},
'parent': {
'_template': None,
'name': 'parent',
'value': 'default',
},
}
# Make sure our expected build configs exist.
self.assertCountEqual(list(self.site_config), list(expected))
# Make sure each one contains
self.longMessage = True
for name in expected:
self.assertDictContainsSubset(expected[name],
self.site_config[name],
name)
# Special handling for child configs.
children = self.site_config['parent'].child_configs
self.assertEqual(len(children), 2)
self.assertDictContainsSubset(
{
'_template': None,
'name': 'default',
'value': 'default',
'grouped': True,
},
children[0])
self.assertDictContainsSubset(
{
'_template': None,
'name': 'default_with_override',
'value': 'override',
'grouped': True,
},
children[1])
def testAddErrors(self):
"""Test the SiteConfig.Add behavior."""
self.site_config.Add('foo')
# Test we can't add the 'foo' config again.
with self.assertRaises(AssertionError):
self.site_config.Add('foo')
# Create a template without using AddTemplate so the site config doesn't
# know about it.
fake_template = config_lib.BuildConfig(
name='fake_template', _template='fake_template')
with self.assertRaises(AssertionError):
self.site_config.Add('bar', fake_template)
def testTemplateAttr(self):
"""Test the SiteConfig.templates.name behavior."""
template1 = self.site_config.AddTemplate('template1', value='template')
template2 = self.site_config.AddTemplate('template2', value='template')
self.assertIs(template1, self.site_config.templates.template1)
self.assertIs(template2, self.site_config.templates.template2)
# Try to fetch a non-existent template.
with self.assertRaises(AttributeError):
# pylint: disable=pointless-statement
self.site_config.templates.no_such_template
# pylint: enable=pointless-statement
def testAddForBoards(self):
per_board = {
'foo': config_lib.BuildConfig(value='foo'),
'bar': config_lib.BuildConfig(value='bar'),
'multiboard': config_lib.BuildConfig(boards=['foo', 'bar']),
}
# Test the minimal invocation.
self.site_config.AddForBoards(
'minimal',
['foo', 'bar'],
)
self.assertIn('foo-minimal', self.site_config)
self.assertEqual(self.site_config['foo-minimal'].boards, ['foo'])
self.assertEqual(self.site_config['bar-minimal'].boards, ['bar'])
# Test a partial set of per-board values specified.
self.site_config.AddForBoards(
'partial_per_board',
['foo', 'no_per'],
per_board,
)
self.assertIn('foo-partial_per_board', self.site_config)
self.assertIn('no_per-partial_per_board', self.site_config)
self.assertEqual(self.site_config['foo-partial_per_board'].value, 'foo')
# Test all boards with per_board values specified, and test we can
# override board listing in per_board values.
self.site_config.AddForBoards(
'per_board',
['foo', 'bar', 'multiboard'],
per_board,
)
self.assertEqual(self.site_config['foo-per_board'].value, 'foo')
self.assertEqual(self.site_config['bar-per_board'].value, 'bar')
self.assertEqual(self.site_config['multiboard-per_board'].boards,
['foo', 'bar'])
# Test using a template
self.site_config.AddForBoards(
'template',
['foo', 'bar'],
None,
self.site_config.templates.template,
)
self.assertEqual(self.site_config['foo-template'].value, 'template')
# Test a template, and a mixin.
self.site_config.AddForBoards(
'mixin',
['foo', 'bar'],
None,
self.site_config.templates.template,
self.site_config.templates.mixin,
)
self.assertEqual(self.site_config['foo-mixin'].value, 'mixin')
# Test a template, and a mixin, and a per-board.
self.site_config.AddForBoards(
'mixin_per_board',
['foo', 'bar'],
per_board,
self.site_config.templates.template,
self.site_config.templates.mixin,
)
self.assertEqual(self.site_config['foo-mixin_per_board'].value, 'foo')
# Test a template, and a mixin, and a per-board, and an override.
self.site_config.AddForBoards(
'override',
['foo', 'bar'],
per_board,
self.site_config.templates.template,
self.site_config.templates.mixin,
value='override',
)
self.assertEqual(self.site_config['foo-override'].value, 'override')
def _verifyLoadSave(self, site_config):
"""Make sure that we can save and re-load a site."""
config_str = site_config.SaveConfigToString()
loaded = config_lib.LoadConfigFromString(config_str)
#
# BUG ALERT ON TEST FAILURE
#
# assertDictEqual can correctly compare these structs for equivalence, but
# has a bug when displaying differences on failure. The embedded
# HWTestConfig values are correctly compared, but ALWAYS display as
# different, if something else triggers a failure.
#
# This for loop is to make differences easier to find/read.
self.longMessage = True
for name in site_config:
self.assertDictEqual(loaded[name], site_config[name], name)
# This includes templates and the default build config.
self.assertEqual(site_config, loaded)
loaded_str = loaded.SaveConfigToString()
self.assertEqual(config_str, loaded_str)
# Cycle through save load again, just for completeness.
loaded2 = config_lib.LoadConfigFromString(loaded_str)
loaded2_str = loaded2.SaveConfigToString()
self.assertEqual(loaded_str, loaded2_str)
# Make sure we can dump long content without crashing.
self.assertNotEqual(site_config.DumpExpandedConfigToString(), '')
self.assertNotEqual(loaded.DumpExpandedConfigToString(), '')
self.assertNotEqual(loaded.DumpConfigCsv(), '')
return loaded
def testSaveLoadEmpty(self):
"""Create, save, and reload an empty config."""
site_config = config_lib.SiteConfig()
loaded = self._verifyLoadSave(site_config)
self.assertEqual(list(loaded), [])
self.assertEqual(list(loaded._templates), [])
self.assertDictEqual(
loaded.GetDefault(), config_lib.DefaultSettings())
def testSaveLoadComplex(self):
"""Create, save, and reload an complex config."""
# Verify it.
loaded = self._verifyLoadSave(self.site_config)
# Verify default build config
expected_defaults = config_lib.DefaultSettings()
expected_defaults.update(self.complex_defaults)
self.assertDictEqual(loaded.GetDefault(), expected_defaults)
# Ensure that expected templates are present.
self.assertCountEqual(list(loaded.templates),
['template', 'callable'])
def testTemplatesToSave(self):
def _invert(x):
return not x
config = config_lib.SiteConfig()
config.AddTemplate('base', foo=True, important=False)
config.AddTemplate('callable', important=_invert)
config.AddTemplate('unused', bar=True)
config.Add('build1', config.templates.base, var=1)
config.Add('build2', var=2)
config.Add('build3', config.templates.base, var=3)
config.Add('build4', config.templates.callable, var=4)
self.assertCountEqual(
config.templates,
{
'base': {'_template': 'base', 'foo': True, 'important': False},
'callable': {'_template': 'callable', 'important': _invert},
'unused': {'_template': 'unused', 'bar': True},
}
)
results = config._MarshalTemplates()
self.assertCountEqual(
results,
{
'base': {'_template': 'base', 'foo': True},
'callable': {'_template': 'callable', 'important': True},
}
)
class SiteConfigFindTests(cros_test_lib.TestCase):
"""Tests related to Find helpers on SiteConfig."""
def testGetBoardsMockConfig(self):
site_config = MockSiteConfig()
self.assertEqual(
site_config.GetBoards(),
set(['amd64-generic']))
def testGetBoardsComplexConfig(self):
site_config = MockSiteConfig()
site_config.Add('build_a', boards=['foo_board'])
site_config.Add('build_b', boards=['bar_board'])
site_config.Add('build_c', boards=['foo_board', 'car_board'])
self.assertEqual(
site_config.GetBoards(),
set(['amd64-generic', 'foo_board', 'bar_board', 'car_board']))
def testGetSlaveConfigMapForMasterAll(self):
"""Test GetSlaveConfigMapForMaster, GetSlavesForMaster all slaves."""
site_config = MockSiteConfig()
master = site_config.Add('master', master=True, manifest_version=True,
slave_configs=['slave_a', 'slave_b'])
slave_a = site_config.Add('slave_a', important=True)
slave_b = site_config.Add('slave_b', important=False)
site_config.Add('other')
results_map = site_config.GetSlaveConfigMapForMaster(master,
important_only=False)
results_slaves = site_config.GetSlavesForMaster(master,
important_only=False)
self.assertEqual(results_map, {'slave_a': slave_a, 'slave_b': slave_b})
self.assertCountEqual(results_slaves, [slave_a, slave_b])
def testGetSlaveConfigMapForMasterImportant(self):
"""Test GetSlaveConfigMapForMaster, GetSlavesForMaster important only."""
site_config = MockSiteConfig()
master = site_config.Add('master', master=True, manifest_version=True,
slave_configs=['slave_a', 'slave_b'])
slave_a = site_config.Add('slave_a', important=True)
site_config.Add('slave_b', important=False)
site_config.Add('other')
results_map = site_config.GetSlaveConfigMapForMaster(master)
results_slaves = site_config.GetSlavesForMaster(master)
self.assertEqual(results_map, {'slave_a': slave_a})
self.assertCountEqual(results_slaves, [slave_a])
class GetConfigTests(cros_test_lib.TestCase):
"""Tests related to SiteConfig.GetConfig()."""
def testGetConfigCaching(self):
"""Test that config_lib.GetConfig() caches it's results correctly."""
config_a = config_lib.GetConfig()
config_b = config_lib.GetConfig()
# Ensure that we get a SiteConfig, and that the result is cached.
self.assertIsInstance(config_a, config_lib.SiteConfig)
self.assertIs(config_a, config_b)
class GEBuildConfigTests(cros_test_lib.TestCase):
"""Test GE build config related methods."""
def setUp(self):
self._fake_ge_build_config_json = """
{
"metadata_version": "1.0",
"reference_board_unified_builds": [
{
"name": "reef",
"reference_board_name": "reef",
"builder": "RELEASE",
"experimental": true,
"arch": "X86_INTERNAL",
"models" : [
{
"board_name": "reef"
},
{
"board_name": "pyro"
}
]
}
],
"boards": [
{
"name": "reef",
"configs": [
{
"builder": "RELEASE",
"experimental": false,
"leader_board": true,
"board_group": "reef",
"arch": "X86_INTERNAL"
}
]
}
]
}
"""
self._fake_ge_build_config = json.loads(self._fake_ge_build_config_json)
def testGetArchBoardDict(self):
"""Test GetArchBoardDict."""
ge_build_config = config_lib.LoadGEBuildConfigFromFile()
arch_board_dict = config_lib.GetArchBoardDict(ge_build_config)
self.assertIsNotNone(arch_board_dict)
def testGetArchBoardDictUnifiedBuilds(self):
"""Test GetArchBoardDict."""
arch_board_dict = config_lib.GetArchBoardDict(self._fake_ge_build_config)
self.assertIsNotNone(arch_board_dict)
self.assertIs(1, len(arch_board_dict[config_lib.CONFIG_X86_INTERNAL]))
def testGetUnifiedBuildConfigAllBuilds(self):
uni_builds = config_lib.GetUnifiedBuildConfigAllBuilds(
self._fake_ge_build_config)
self.assertEqual(1, len(uni_builds))
def testGetUnifiedBuildConfigAllBuildsWithNoBuilds(self):
uni_builds = config_lib.GetUnifiedBuildConfigAllBuilds({})
self.assertEqual(0, len(uni_builds))