diff options
Diffstat (limited to 'taskcluster/taskgraph/test/test_util_templates.py')
-rwxr-xr-x | taskcluster/taskgraph/test/test_util_templates.py | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/taskcluster/taskgraph/test/test_util_templates.py b/taskcluster/taskgraph/test/test_util_templates.py new file mode 100755 index 000000000..47f7494a0 --- /dev/null +++ b/taskcluster/taskgraph/test/test_util_templates.py @@ -0,0 +1,232 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from __future__ import absolute_import, print_function, unicode_literals + +import unittest +import mozunit +import textwrap +from taskgraph.util.templates import ( + merge_to, + merge, + Templates, + TemplatesException +) + +files = {} +files['/fixtures/circular.yml'] = textwrap.dedent("""\ + $inherits: + from: 'circular_ref.yml' + variables: + woot: 'inherit' + """) + +files['/fixtures/inherit.yml'] = textwrap.dedent("""\ + $inherits: + from: 'templates.yml' + variables: + woot: 'inherit' + """) + +files['/fixtures/extend_child.yml'] = textwrap.dedent("""\ + list: ['1', '2', '3'] + was_list: ['1'] + obj: + level: 1 + deeper: + woot: 'bar' + list: ['baz'] + """) + +files['/fixtures/circular_ref.yml'] = textwrap.dedent("""\ + $inherits: + from: 'circular.yml' + """) + +files['/fixtures/child_pass.yml'] = textwrap.dedent("""\ + values: + - {{a}} + - {{b}} + - {{c}} + """) + +files['/fixtures/inherit_pass.yml'] = textwrap.dedent("""\ + $inherits: + from: 'child_pass.yml' + variables: + a: 'a' + b: 'b' + c: 'c' + """) + +files['/fixtures/deep/2.yml'] = textwrap.dedent("""\ + $inherits: + from: deep/1.yml + + """) + +files['/fixtures/deep/3.yml'] = textwrap.dedent("""\ + $inherits: + from: deep/2.yml + + """) + +files['/fixtures/deep/4.yml'] = textwrap.dedent("""\ + $inherits: + from: deep/3.yml + """) + +files['/fixtures/deep/1.yml'] = textwrap.dedent("""\ + variable: {{value}} + """) + +files['/fixtures/simple.yml'] = textwrap.dedent("""\ + is_simple: true + """) + +files['/fixtures/templates.yml'] = textwrap.dedent("""\ + content: 'content' + variable: '{{woot}}' + """) + +files['/fixtures/extend_parent.yml'] = textwrap.dedent("""\ + $inherits: + from: 'extend_child.yml' + + list: ['4'] + was_list: + replaced: true + obj: + level: 2 + from_parent: true + deeper: + list: ['bar'] + """) + + +class TemplatesTest(unittest.TestCase): + + def setUp(self): + self.mocked_open = mozunit.MockedOpen(files) + self.mocked_open.__enter__() + self.subject = Templates('/fixtures') + + def tearDown(self): + self.mocked_open.__exit__(None, None, None) + + def test_invalid_path(self): + with self.assertRaisesRegexp(TemplatesException, 'must be a directory'): + Templates('/zomg/not/a/dir') + + def test_no_templates(self): + content = self.subject.load('simple.yml', {}) + self.assertEquals(content, { + 'is_simple': True + }) + + def test_with_templates(self): + content = self.subject.load('templates.yml', { + 'woot': 'bar' + }) + + self.assertEquals(content, { + 'content': 'content', + 'variable': 'bar' + }) + + def test_inheritance(self): + ''' + The simple single pass inheritance case. + ''' + content = self.subject.load('inherit.yml', {}) + self.assertEqual(content, { + 'content': 'content', + 'variable': 'inherit' + }) + + def test_inheritance_implicat_pass(self): + ''' + Implicitly pass parameters from the child to the ancestor. + ''' + content = self.subject.load('inherit_pass.yml', { + 'a': 'overriden' + }) + + self.assertEqual(content, {'values': ['overriden', 'b', 'c']}) + + def test_inheritance_circular(self): + ''' + Circular reference handling. + ''' + with self.assertRaisesRegexp(TemplatesException, 'circular'): + self.subject.load('circular.yml', {}) + + def test_deep_inheritance(self): + content = self.subject.load('deep/4.yml', { + 'value': 'myvalue' + }) + self.assertEqual(content, {'variable': 'myvalue'}) + + def test_inheritance_with_simple_extensions(self): + content = self.subject.load('extend_parent.yml', {}) + self.assertEquals(content, { + 'list': ['1', '2', '3', '4'], + 'obj': { + 'from_parent': True, + 'deeper': { + 'woot': 'bar', + 'list': ['baz', 'bar'] + }, + 'level': 2, + }, + 'was_list': {'replaced': True} + }) + + +class MergeTest(unittest.TestCase): + + def test_merge_to_dicts(self): + source = {'a': 1, 'b': 2} + dest = {'b': '20', 'c': 30} + expected = { + 'a': 1, # source only + 'b': 2, # source overrides dest + 'c': 30, # dest only + } + self.assertEqual(merge_to(source, dest), expected) + self.assertEqual(dest, expected) + + def test_merge_to_lists(self): + source = {'x': [3, 4]} + dest = {'x': [1, 2]} + expected = {'x': [1, 2, 3, 4]} # dest first + self.assertEqual(merge_to(source, dest), expected) + self.assertEqual(dest, expected) + + def test_merge_diff_types(self): + source = {'x': [1, 2]} + dest = {'x': 'abc'} + expected = {'x': [1, 2]} # source wins + self.assertEqual(merge_to(source, dest), expected) + self.assertEqual(dest, expected) + + def test_merge(self): + first = {'a': 1, 'b': 2, 'd': 11} + second = {'b': 20, 'c': 30} + third = {'c': 300, 'd': 400} + expected = { + 'a': 1, + 'b': 20, + 'c': 300, + 'd': 400, + } + self.assertEqual(merge(first, second, third), expected) + + # inputs haven't changed.. + self.assertEqual(first, {'a': 1, 'b': 2, 'd': 11}) + self.assertEqual(second, {'b': 20, 'c': 30}) + self.assertEqual(third, {'c': 300, 'd': 400}) + +if __name__ == '__main__': + mozunit.main() |