blob: 07ae3636cf963913a5bf3674cac4edc77c501562 [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2016 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.
import json
import logging
import os
import unittest
import factory_common # pylint: disable=unused-import
from cros.factory.utils import config_utils
from cros.factory.utils import type_utils
class ConfigUtilsTest(unittest.TestCase):
def assertOverrideConfigEqual(self, val, val_override, val_expected):
config_utils.OverrideConfig(val, val_override)
self.assertEqual(val_expected, val)
def testOverrideConfig(self):
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'c': 3}},
{'a': {'b': 1, 'c': 3}})
# override a non-dict value by dict value
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'b': {'d': 1}}},
{'a': {'b': {'d': 1}, 'c': 2}})
# override a dict value by non-dict value
self.assertOverrideConfigEqual(
{'a': {'b': {'d': 1}, 'c': 2}},
{'a': {'b': 1}},
{'a': {'b': 1, 'c': 2}})
def testOverrideConfigReplace(self):
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'__replace__': True, 'c': 3}},
{'a': {'c': 3}})
self.assertOverrideConfigEqual(
{'a': 1},
{'a': {'__replace__': True, 'c': 3}},
{'a': {'c': 3}})
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'b': {'__replace__': True, 'c': 3}},
{'a': {'b': 1, 'c': 2}, 'b': {'c': 3}})
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'__replace__': True, 'c': {'__replace__': True, 'd': 3}}},
{'a': {'c': {'d': 3}}})
def testOverrideConfigDelete(self):
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'__delete__': True}},
{})
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'__delete__': True, 'd': 3}},
{})
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'c': {'__delete__': True}, 'd': 3}},
{'a': {'b': 1, 'd': 3}})
self.assertOverrideConfigEqual(
{'a': {'b': 1, 'c': 2}},
{'a': {'d': {'__delete__': True}}},
{'a': {'b': 1, 'c': 2}})
def testOverrideConfigCopyOnWrite(self):
old_config = {
'a': {
'b': 'B',
'c': 'C',
},
'd': 'D',
}
new_config = config_utils.OverrideConfig(
old_config, {'a': {'b': 'BB'}, 'd': 'DD'}, copy_on_write=True)
self.assertEqual(new_config, {'a': {'b': 'BB', 'c': 'C'}, 'd': 'DD'})
self.assertEqual(old_config, {'a': {'b': 'B', 'c': 'C'}, 'd': 'D'})
def testMappingToNamedTuple(self):
val = {'a': {'b': 1, 'c': 2}}
val_tuple = config_utils.GetNamedTuple(val)
self.assertEqual(val['a']['b'], val_tuple.a.b)
def testLoadConfig(self):
config_m = config_utils.LoadConfig(
'testdata/config_utils_unittest',
default_config_dirs=[os.path.join(os.path.dirname(__file__),
'testdata', 'extra_dir'),
config_utils.CALLER_DIR],
allow_inherit=True,
generate_depend=True)
config = config_utils.GetNamedTuple(config_m)
# default values from ./config_utils_unittest.json
self.assertEqual(config.sample_int, 1)
self.assertEqual(config.sample_str, 'test')
self.assertEqual(config.sample_mapping.contents, 'abc')
expected = [
'config/testdata/config_utils_unittest.json',
'utils/testdata/config_utils_unittest.json',
'utils/testdata/config_utils_unittest_middle_b.json',
'utils/testdata/config_utils_unittest_middle_a.json',
'utils/testdata/config_utils_unittest_base.json', ]
for expected_path, config_path in zip(expected, config_m.GetDepend()):
self.assertTrue(config_path.endswith(expected_path))
# the inherited value.
self.assertEqual(config.sample_base_int, 10)
self.assertEqual(config.sample_base_overrided_str, 'middle_b')
# overrided values
self.assertEqual(config.sample_partial_int, 5)
self.assertEqual(config_m['sample_replace_sibling_mapping'], {'b': 42})
self.assertIsNone(config_m.get('sample_delete_sibling_int'))
# build values from ../config/config_utils_unittest.json
self.assertEqual(config.sample_mapping.contents, 'abc')
self.assertIsNone(config_m.get('sample_runtime_str'))
def testLoadConfigStringType(self):
config = config_utils.LoadConfig(
'testdata/config_utils_unittest', convert_to_str=False)
self.assertEqual(type(config['sample_str']), unicode)
config = config_utils.LoadConfig(
'testdata/config_utils_unittest', convert_to_str=True)
self.assertEqual(type(config['sample_str']), str)
def testLoopDetection(self):
with self.assertRaisesRegexp(
AssertionError, 'Detected loop inheritance dependency .*'):
config_utils.LoadConfig(
'testdata/config_utils_unittest_loop',
validate_schema=False,
allow_inherit=True)
def testC3LinearizationFail(self):
with self.assertRaisesRegexp(
RuntimeError, 'C3 linearization failed for .*'):
config_utils.LoadConfig(
'testdata/config_utils_unittest_c3',
validate_schema=False,
allow_inherit=True)
class ResolvedConfigTest(unittest.TestCase):
"""Test ResolvedConfig"""
def testSubclass(self):
self.assertTrue(issubclass(config_utils.ResolvedConfig, dict))
def testDictBehavior(self):
d = {
'a': 1,
'b': "string",
'c': [1, 2, 3],
'd': {'x': 1, 'y': 2}
}
resolved_config = config_utils.ResolvedConfig(d)
self.assertEqual(resolved_config, d)
# it can be serialized, deserialized, as if it's a normal
# dictionary.
self.assertEqual(json.loads(json.dumps(resolved_config)), d)
# it can be passed to AttrDict
attr_dict = type_utils.AttrDict(resolved_config)
self.assertEqual(attr_dict.a, 1)
self.assertEqual(attr_dict.b, "string")
self.assertEqual(attr_dict.c, [1, 2, 3])
self.assertEqual(attr_dict.d, {'x': 1, 'y': 2})
self.assertEqual(attr_dict.d.x, 1)
self.assertEqual(attr_dict.d.y, 2)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
unittest.main()