2 # Copyright 2014 The Swarming Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 that
4 # can be found in the LICENSE file.
13 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
14 sys.path.insert(0, ROOT_DIR)
19 from isolate_format import KEY_TOUCHED, KEY_TRACKED, KEY_UNTRACKED
22 # Access to a protected member XXX of a client class
23 # pylint: disable=W0212
27 u'z:\\path\\to\\non_existing'
28 if sys.platform == 'win32' else u'/path/to/non_existing')
31 class IsolateFormatTest(unittest.TestCase):
32 def test_unknown_key(self):
34 isolate_format.verify_variables({'foo': [],})
36 except AssertionError:
39 def test_unknown_var(self):
41 isolate_format.verify_condition({'variables': {'foo': [],}}, {})
43 except AssertionError:
46 def test_eval_content(self):
48 # Intrinsics are not available.
49 isolate_format.eval_content('map(str, [1, 2])')
54 def test_load_isolate_as_config_empty(self):
57 'isolate_dir': FAKE_DIR,
62 isolate_format.load_isolate_as_config(FAKE_DIR, {}, None).flatten())
64 def test_load_isolate_as_config(self):
67 ['OS=="amiga" or OS=="atari" or OS=="coleco" or OS=="dendy"', {
71 KEY_TOUCHED: ['touched'],
76 KEY_TRACKED: ['c', 'x'],
78 KEY_TOUCHED: ['touched_a'],
79 'command': ['echo', 'Hello World'],
83 ['OS=="amiga" or OS=="coleco" or OS=="dendy"', {
85 KEY_TRACKED: ['e', 'x'],
87 KEY_TOUCHED: ['touched_e'],
88 'command': ['echo', 'You should get an Atari'],
97 ['OS=="amiga" or OS=="atari" or OS=="dendy"', {
106 'isolate_dir': FAKE_DIR,
109 KEY_TOUCHED: ['touched', 'touched_e'],
110 KEY_TRACKED: ['a', 'e', 'g', 'x'],
111 KEY_UNTRACKED: ['b', 'f', 'h'],
112 'command': ['echo', 'You should get an Atari'],
113 'isolate_dir': FAKE_DIR,
117 KEY_TOUCHED: ['touched', 'touched_a'],
118 KEY_TRACKED: ['a', 'c', 'x'],
119 KEY_UNTRACKED: ['b', 'd', 'h'],
120 'command': ['echo', 'Hello World'],
121 'isolate_dir': FAKE_DIR,
125 KEY_TOUCHED: ['touched', 'touched_e'],
126 KEY_TRACKED: ['a', 'e', 'x'],
127 KEY_UNTRACKED: ['b', 'f'],
128 'command': ['echo', 'You should get an Atari'],
129 'isolate_dir': FAKE_DIR,
132 KEY_TOUCHED: ['touched', 'touched_e'],
133 KEY_TRACKED: ['a', 'e', 'x'],
134 KEY_UNTRACKED: ['b', 'f', 'h'],
135 'command': ['echo', 'You should get an Atari'],
136 'isolate_dir': FAKE_DIR,
140 expected, isolate_format.load_isolate_as_config(
141 FAKE_DIR, value, None).flatten())
143 def test_load_isolate_as_config_duplicate_command(self):
146 'command': ['rm', '-rf', '/'],
151 'command': ['echo', 'Hello World'],
157 isolate_format.load_isolate_as_config(FAKE_DIR, value, None)
159 except AssertionError:
162 def test_load_isolate_as_config_no_variable(self):
165 'command': ['echo', 'You should get an Atari'],
167 KEY_UNTRACKED: ['b'],
168 KEY_TOUCHED: ['touched'],
172 # The key is the empty tuple, since there is no variable to bind to.
176 KEY_UNTRACKED: ['b'],
177 KEY_TOUCHED: ['touched'],
178 'command': ['echo', 'You should get an Atari'],
179 'isolate_dir': FAKE_DIR,
184 expected, isolate_format.load_isolate_as_config(
185 FAKE_DIR, value, None).flatten())
187 def test_invert_map(self):
190 'command': ['echo', 'You should get an Atari'],
191 KEY_TOUCHED: ['touched', 'touched_e'],
192 KEY_TRACKED: ['a', 'e', 'g', 'x'],
193 KEY_UNTRACKED: ['b', 'f', 'h'],
197 'command': ['echo', 'Hello World'],
198 KEY_TOUCHED: ['touched', 'touched_a'],
199 KEY_TRACKED: ['a', 'c', 'x'],
200 KEY_UNTRACKED: ['b', 'd', 'h'],
204 'command': ['echo', 'You should get an Atari'],
205 KEY_TOUCHED: ['touched', 'touched_e'],
206 KEY_TRACKED: ['a', 'e', 'x'],
207 KEY_UNTRACKED: ['b', 'f'],
210 'command': ['echo', 'You should get an Atari'],
211 KEY_TOUCHED: ['touched', 'touched_e'],
212 KEY_TRACKED: ['a', 'e', 'x'],
213 KEY_UNTRACKED: ['b', 'f', 'h'],
216 amiga, atari, coleco, dendy = (
217 set([(os,)]) for os in ('amiga', 'atari', 'coleco', 'dendy'))
220 ('echo', 'Hello World'): atari,
221 ('echo', 'You should get an Atari'): amiga | coleco | dendy,
224 'a': amiga | atari | coleco | dendy,
226 'e': amiga | coleco | dendy,
228 'x': amiga | atari | coleco | dendy,
231 'b': amiga | atari | coleco | dendy,
233 'f': amiga | coleco | dendy,
234 'h': amiga | atari | dendy,
237 'touched': amiga | atari | coleco | dendy,
239 'touched_e': amiga | coleco | dendy,
246 actual_values = isolate_format.invert_map(value)
247 self.assertEqual(expected_values, actual_values)
249 def test_reduce_inputs(self):
250 amiga, atari, coleco, dendy = (
251 set([(os,)]) for os in ('amiga', 'atari', 'coleco', 'dendy'))
254 ('echo', 'Hello World'): atari,
255 ('echo', 'You should get an Atari'): amiga | coleco | dendy,
258 'a': amiga | atari | coleco | dendy,
260 'e': amiga | coleco | dendy,
262 'x': amiga | atari | coleco | dendy,
265 'b': amiga | atari | coleco | dendy,
267 'f': amiga | coleco | dendy,
268 'h': amiga | atari | dendy,
271 'touched': amiga | atari | coleco | dendy,
273 'touched_e': amiga | coleco | dendy,
282 ('echo', 'Hello World'): atari,
283 ('echo', 'You should get an Atari'): amiga | coleco | dendy,
286 'a': amiga | atari | coleco | dendy,
288 'e': amiga | coleco | dendy,
290 'x': amiga | atari | coleco | dendy,
293 'b': amiga | atari | coleco | dendy,
295 'f': amiga | coleco | dendy,
296 'h': amiga | atari | dendy,
299 'touched': amiga | atari | coleco | dendy,
301 'touched_e': amiga | coleco | dendy,
308 actual_values = isolate_format.reduce_inputs(values)
309 self.assertEqual(expected_values, actual_values)
311 def test_reduce_inputs_merge_subfolders_and_files(self):
312 linux, mac, win = (set([(os,)]) for os in ('linux', 'mac', 'win'))
315 'folder/tracked_file': win,
316 'folder_helper/tracked_file': win,
319 'folder/': linux | mac | win,
320 'folder/subfolder/': win,
321 'folder/untracked_file': linux | mac | win,
322 'folder_helper/': linux,
325 'folder/touched_file': win,
326 'folder/helper_folder/deep_file': win,
327 'folder_helper/touched_file1': mac | win,
328 'folder_helper/touched_file2': linux,
334 'folder_helper/tracked_file': win,
337 'folder/': linux | mac | win,
338 'folder_helper/': linux,
341 'folder_helper/touched_file1': mac | win,
345 actual_values = isolate_format.reduce_inputs(values)
346 self.assertEqual(expected_values, actual_values)
348 def test_reduce_inputs_take_strongest_dependency(self):
349 amiga, atari, coleco, dendy = (
350 set([(os,)]) for os in ('amiga', 'atari', 'coleco', 'dendy'))
353 ('echo', 'Hello World'): atari,
354 ('echo', 'You should get an Atari'): amiga | coleco | dendy,
357 'a': amiga | atari | coleco | dendy,
358 'b': amiga | atari | coleco,
361 'c': amiga | atari | coleco | dendy,
362 'd': amiga | coleco | dendy,
365 'a': amiga | atari | coleco | dendy,
366 'b': atari | coleco | dendy,
367 'c': amiga | atari | coleco | dendy,
368 'd': atari | coleco | dendy,
373 ('echo', 'Hello World'): atari,
374 ('echo', 'You should get an Atari'): amiga | coleco | dendy,
377 'a': amiga | atari | coleco | dendy,
378 'b': amiga | atari | coleco,
381 'c': amiga | atari | coleco | dendy,
382 'd': amiga | coleco | dendy,
390 actual_values = isolate_format.reduce_inputs(values)
391 self.assertEqual(expected_values, actual_values)
393 def test_convert_map_to_isolate_dict(self):
400 ('echo', 'Hello World'): (atari,),
401 ('echo', 'You should get an Atari'): (amiga, coleco, dendy),
404 'a': (amiga, atari, coleco, dendy),
406 'e': (amiga, coleco, dendy),
408 'x': (amiga, atari, coleco, dendy),
411 'b': (amiga, atari, coleco, dendy),
413 'f': (amiga, coleco, dendy),
414 'h': (amiga, atari, dendy),
417 'touched': (amiga, atari, coleco, dendy),
418 'touched_a': (atari,),
419 'touched_e': (amiga, coleco, dendy),
426 expected_conditions = [
433 ['OS=="amiga" or OS=="atari" or OS=="coleco" or OS=="dendy"', {
435 KEY_TRACKED: ['a', 'x'],
436 KEY_UNTRACKED: ['b'],
437 KEY_TOUCHED: ['touched'],
440 ['OS=="amiga" or OS=="atari" or OS=="dendy"', {
442 KEY_UNTRACKED: ['h'],
445 ['OS=="amiga" or OS=="coleco" or OS=="dendy"', {
447 'command': ['echo', 'You should get an Atari'],
449 KEY_UNTRACKED: ['f'],
450 KEY_TOUCHED: ['touched_e'],
455 'command': ['echo', 'Hello World'],
457 KEY_UNTRACKED: ['d'],
458 KEY_TOUCHED: ['touched_a'],
463 actual = isolate_format.convert_map_to_isolate_dict(values, ('OS',))
464 self.assertEqual(expected_conditions, sorted(actual.pop('conditions')))
465 self.assertFalse(actual)
467 def test_merge_two_empty(self):
468 # Flat stay flat. Pylint is confused about union() return type.
469 # pylint: disable=E1103
470 actual = isolate_format.Configs(None, ()).union(
471 isolate_format.load_isolate_as_config(FAKE_DIR, {}, None)).union(
472 isolate_format.load_isolate_as_config(FAKE_DIR, {}, None))
475 'isolate_dir': FAKE_DIR,
478 self.assertEqual(expected, actual.flatten())
480 def test_merge_empty(self):
481 actual = isolate_format.convert_map_to_isolate_dict(
482 isolate_format.reduce_inputs(isolate_format.invert_map({})),
483 ('dummy1', 'dummy2'))
484 self.assertEqual({'conditions': []}, actual)
486 def test_load_two_conditions(self):
491 'isolate_dependency_tracked': [
503 'isolate_dependency_tracked': [
513 'isolate_dir': FAKE_DIR,
516 'isolate_dependency_tracked': ['file_common', 'file_linux'],
517 'isolate_dir': FAKE_DIR,
520 'isolate_dependency_tracked': ['file_common', 'file_mac'],
521 'isolate_dir': FAKE_DIR,
524 # Pylint is confused about union() return type.
525 # pylint: disable=E1103
526 configs = isolate_format.Configs(None, ()).union(
527 isolate_format.load_isolate_as_config(FAKE_DIR, linux, None)).union(
528 isolate_format.load_isolate_as_config(FAKE_DIR, mac, None)
530 self.assertEqual(expected, configs)
532 def test_load_three_conditions(self):
535 ['OS=="linux" and chromeos==1', {
537 'isolate_dependency_tracked': [
547 ['OS=="mac" and chromeos==0', {
549 'isolate_dependency_tracked': [
559 ['OS=="win" and chromeos==0', {
561 'isolate_dependency_tracked': [
571 'isolate_dir': FAKE_DIR,
574 'isolate_dependency_tracked': ['file_common', 'file_linux'],
575 'isolate_dir': FAKE_DIR,
578 'isolate_dependency_tracked': ['file_common', 'file_mac'],
579 'isolate_dir': FAKE_DIR,
582 'isolate_dependency_tracked': ['file_common', 'file_win'],
583 'isolate_dir': FAKE_DIR,
586 # Pylint is confused about union() return type.
587 # pylint: disable=E1103
588 configs = isolate_format.Configs(None, ()).union(
589 isolate_format.load_isolate_as_config(FAKE_DIR, linux, None)).union(
590 isolate_format.load_isolate_as_config(FAKE_DIR, mac, None)).union(
591 isolate_format.load_isolate_as_config(FAKE_DIR, win, None))
592 self.assertEqual(expected, configs.flatten())
594 def test_safe_index(self):
595 self.assertEqual(1, isolate_format._safe_index(('a', 'b'), 'b'))
596 self.assertEqual(None, isolate_format._safe_index(('a', 'b'), 'c'))
598 def test_get_map_keys(self):
600 (0, None, 1), isolate_format._get_map_keys(('a', 'b', 'c'), ('a', 'c')))
602 def test_map_keys(self):
605 isolate_format._map_keys((0, None, 1), ('a', 'c')))
607 def test_load_multi_variables(self):
608 # Load an .isolate with different condition on different variables.
623 configs = isolate_format.load_isolate_as_config(FAKE_DIR, data, None)
624 self.assertEqual(('CHROMEOS', 'OS'), configs.config_variables)
625 flatten = dict((k, v.flatten()) for k, v in configs._by_config.iteritems())
628 'isolate_dir': FAKE_DIR,
632 'isolate_dir': FAKE_DIR,
636 'isolate_dir': FAKE_DIR,
638 # TODO(maruel): It is a conflict.
641 'isolate_dir': FAKE_DIR,
644 self.assertEqual(expected, flatten)
646 def test_union_multi_variables(self):
665 configs1 = isolate_format.load_isolate_as_config(FAKE_DIR, data1, None)
666 configs2 = isolate_format.load_isolate_as_config(FAKE_DIR, data2, None)
667 configs = configs1.union(configs2)
668 self.assertEqual(('CHROMEOS', 'OS'), configs.config_variables)
669 flatten = dict((k, v.flatten()) for k, v in configs._by_config.iteritems())
672 'isolate_dir': FAKE_DIR,
676 'isolate_dir': FAKE_DIR,
680 'isolate_dir': FAKE_DIR,
683 self.assertEqual(expected, flatten)
685 def test_make_isolate_multi_variables(self):
686 config = isolate_format.Configs(None, ('CHROMEOS', 'OS'))
687 config._by_config[(('0', 'linux'))] = isolate_format.ConfigSettings(
688 {'command': ['bar']}, FAKE_DIR)
689 config._by_config[(('1', 'linux'))] = isolate_format.ConfigSettings(
690 {'command': ['foo']}, FAKE_DIR)
693 ['CHROMEOS=="0" and OS=="linux"', {
698 ['CHROMEOS=="1" and OS=="linux"', {
705 self.assertEqual(expected, config.make_isolate_file())
707 def test_make_isolate_multi_variables_missing(self):
708 config = isolate_format.Configs(None, ('CHROMEOS', 'OS'))
709 config._by_config[((None, 'abc'))] = isolate_format.ConfigSettings(
710 {'command': ['bar']}, FAKE_DIR)
711 config._by_config[(('1', None))] = isolate_format.ConfigSettings(
712 {'command': ['foo']}, FAKE_DIR)
727 self.assertEqual(expected, config.make_isolate_file())
729 def test_make_isolate_4_variables(self):
730 # Test multiple combinations of bound and free variables.
731 config = isolate_format.Configs(None, ('BRAND', 'CHROMEOS', 'LIB', 'OS'))
732 config._by_config = {
733 (None, 0, 's', 'linux'): isolate_format.ConfigSettings(
734 {'command': ['bar']}, FAKE_DIR),
735 (None, None, 's', 'mac'): isolate_format.ConfigSettings(
736 {'command': ['foo']}, FAKE_DIR),
737 (None, None, 's', 'win'): isolate_format.ConfigSettings(
738 {'command': ['ziz']}, FAKE_DIR),
739 ('Chrome', 0, 's', 'win'): isolate_format.ConfigSettings(
740 {'command': ['baz']}, FAKE_DIR),
744 ['BRAND=="Chrome" and CHROMEOS==0 and LIB=="s" and OS=="win"', {
749 ['CHROMEOS==0 and LIB=="s" and OS=="linux"', {
754 ['LIB=="s" and OS=="mac"', {
759 ['LIB=="s" and OS=="win"', {
766 self.assertEqual(expected, config.make_isolate_file())
768 def test_ConfigSettings_union(self):
770 rhs_values = {KEY_UNTRACKED: ['data/', 'test/data/']}
771 lhs = isolate_format.ConfigSettings(lhs_values, '/src/net/third_party/nss')
772 rhs = isolate_format.ConfigSettings(rhs_values, '/src/base')
775 KEY_UNTRACKED: ['data/', 'test/data/'],
776 'isolate_dir': '/src/base',
778 self.assertEqual(expected, out.flatten())
780 def test_merge_three_conditions(self):
783 'isolate_dependency_tracked': ['file_common', 'file_linux'],
786 'isolate_dependency_tracked': ['file_common', 'file_mac'],
789 'isolate_dependency_tracked': ['file_common', 'file_win'],
796 'isolate_dependency_tracked': [
801 ['OS=="linux" or OS=="mac" or OS=="win"', {
803 'isolate_dependency_tracked': [
810 'isolate_dependency_tracked': [
817 'isolate_dependency_tracked': [
824 actual = isolate_format.convert_map_to_isolate_dict(
825 isolate_format.reduce_inputs(isolate_format.invert_map(values)),
827 self.assertEqual(expected, actual)
829 def test_merge_three_conditions_read_only(self):
832 'isolate_dependency_tracked': ['file_common', 'file_linux'],
836 'isolate_dependency_tracked': ['file_common', 'file_mac'],
840 'isolate_dependency_tracked': ['file_common', 'file_win'],
849 ['OS=="amiga" or OS=="linux"', {
856 'isolate_dependency_tracked': [
861 ['OS=="linux" or OS=="mac" or OS=="win"', {
863 'isolate_dependency_tracked': [
870 'isolate_dependency_tracked': [
878 'isolate_dependency_tracked': [
886 actual = isolate_format.convert_map_to_isolate_dict(
887 isolate_format.reduce_inputs(isolate_format.invert_map(values)),
889 self.assertEqual(expected, actual)
891 def test_configs_comment(self):
892 # Pylint is confused with isolate_format.union() return type.
893 # pylint: disable=E1103
894 configs = isolate_format.load_isolate_as_config(
895 FAKE_DIR, {}, '# Yo dawg!\n# Chill out.\n').union(
896 isolate_format.load_isolate_as_config(FAKE_DIR, {}, None))
897 self.assertEqual('# Yo dawg!\n# Chill out.\n', configs.file_comment)
899 configs = isolate_format.load_isolate_as_config(FAKE_DIR, {}, None).union(
900 isolate_format.load_isolate_as_config(
901 FAKE_DIR, {}, '# Yo dawg!\n# Chill out.\n'))
902 self.assertEqual('# Yo dawg!\n# Chill out.\n', configs.file_comment)
904 # Only keep the first one.
905 configs = isolate_format.load_isolate_as_config(
906 FAKE_DIR, {}, '# Yo dawg!\n').union(
907 isolate_format.load_isolate_as_config(
908 FAKE_DIR, {}, '# Chill out.\n'))
909 self.assertEqual('# Yo dawg!\n', configs.file_comment)
911 def test_extract_comment(self):
913 '# Foo\n# Bar\n', isolate_format.extract_comment('# Foo\n# Bar\n{}'))
914 self.assertEqual('', isolate_format.extract_comment('{}'))
916 def _test_pretty_print_impl(self, value, expected):
917 actual = cStringIO.StringIO()
918 isolate_format.pretty_print(value, actual)
919 self.assertEqual(expected.splitlines(), actual.getvalue().splitlines())
921 def test_pretty_print_empty(self):
922 self._test_pretty_print_impl({}, '{\n}\n')
924 def test_pretty_print_mid_size(self):
943 'command': ['python', '-c', 'print "H\\i\'"'],
952 isolate_format.verify_root(value, {})
953 # This is an .isolate format.
957 " 'isolate_dependency_touched': [\n"
963 " ['OS==\"foo\"', {\n"
968 " 'print \"H\\i\'\"',\n"
971 " 'isolate_dependency_tracked': [\n"
975 " 'isolate_dependency_untracked': [\n"
981 " ['OS==\"bar\"', {\n"
987 self._test_pretty_print_impl(value, expected)
989 def test_convert_old_to_new_else(self):
990 isolate_with_else_clauses = {
993 'variables': {'foo': 'bar'},
995 'variables': {'x': 'y'},
999 with self.assertRaises(isolate_format.isolateserver.ConfigError):
1000 isolate_format.load_isolate_as_config(
1001 FAKE_DIR, isolate_with_else_clauses, None)
1003 def test_match_configs(self):
1006 ('OS=="win"', ('OS',), [('win',), ('mac',), ('linux',)]),
1011 '(foo==1 or foo==2) and bar=="b"',
1013 [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')],
1015 [(1, 'b'), (2, 'b')],
1021 [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')],
1023 # TODO(maruel): When a free variable match is found, it should not
1024 # list all the bounded values in addition. The problem is when an
1025 # intersection of two different bound variables that are tested singly
1026 # in two different conditions.
1027 [(1, 'b'), (2, 'b'), (None, 'b')],
1031 'foo==1 or bar=="b"',
1033 [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')],
1035 # TODO(maruel): (None, 'b') would match.
1036 # It is hard in this case to realize that each of the variables 'foo'
1037 # and 'bar' can be unbounded in a specific case.
1038 [(1, 'a'), (1, 'b'), (2, 'b'), (1, None)],
1041 for data, expected in expectations:
1042 self.assertEqual(expected, isolate_format.match_configs(*data))
1044 def test_load_with_globals(self):
1047 'isolate_dependency_tracked': [
1054 'isolate_dependency_tracked': [
1060 ['OS=="mac" or OS=="win"', {
1062 'isolate_dependency_tracked': [
1072 'isolate_dependency_tracked': [
1075 'isolate_dir': FAKE_DIR,
1078 'isolate_dependency_tracked': [
1081 'isolate_dir': FAKE_DIR,
1085 'isolate_dependency_tracked': [
1088 'isolate_dir': FAKE_DIR,
1092 'isolate_dependency_tracked': [
1095 'isolate_dir': FAKE_DIR,
1099 actual = isolate_format.load_isolate_as_config(FAKE_DIR, values, None)
1100 self.assertEqual(expected, actual.flatten())
1102 def test_configs_with_globals(self):
1103 c = isolate_format.Configs(None, ('x', 'y'))
1105 (1, 1), isolate_format.ConfigSettings({KEY_TRACKED: ['1,1']}, FAKE_DIR))
1107 (2, 2), isolate_format.ConfigSettings({KEY_TRACKED: ['2,2']}, FAKE_DIR))
1110 isolate_format.ConfigSettings({KEY_TRACKED: ['1,y']}, FAKE_DIR))
1113 isolate_format.ConfigSettings({KEY_TRACKED: ['x,2']}, FAKE_DIR))
1116 isolate_format.ConfigSettings({KEY_TRACKED: ['x,y']}, FAKE_DIR))
1119 KEY_TRACKED: ['x,y'],
1120 'isolate_dir': FAKE_DIR,
1123 KEY_TRACKED: ['x,2'],
1124 'isolate_dir': FAKE_DIR,
1127 KEY_TRACKED: ['1,y'],
1128 'isolate_dir': FAKE_DIR,
1131 KEY_TRACKED: ['1,1'],
1132 'isolate_dir': FAKE_DIR,
1135 KEY_TRACKED: ['2,2'],
1136 'isolate_dir': FAKE_DIR,
1139 self.assertEqual(expected, c.flatten())
1141 s = c.get_config((1, 1))
1143 KEY_TRACKED: ['1,1', '1,y', 'x,y'],
1144 'isolate_dir': FAKE_DIR,
1146 self.assertEqual(expected, s.flatten())
1148 s = c.get_config((1, None))
1150 KEY_TRACKED: ['1,y', 'x,y'],
1151 'isolate_dir': FAKE_DIR,
1153 self.assertEqual(expected, s.flatten())
1155 s = c.get_config((None, None))
1157 KEY_TRACKED: ['x,y'],
1158 'isolate_dir': FAKE_DIR,
1160 self.assertEqual(expected, s.flatten())
1164 ['x==1', {'variables': {KEY_TRACKED: ['1,y']}}],
1165 ['x==1 and y==1', {'variables': {KEY_TRACKED: ['1,1']}}],
1166 ['x==2 and y==2', {'variables': {KEY_TRACKED: ['2,2']}}],
1167 ['y==2', {'variables': {KEY_TRACKED: ['x,2']}}],
1169 'variables': {KEY_TRACKED: ['x,y']},
1171 self.assertEqual(expected, c.make_isolate_file())
1174 class IsolateFormatTmpDirTest(unittest.TestCase):
1176 super(IsolateFormatTmpDirTest, self).setUp()
1177 self.tempdir = tempfile.mkdtemp(prefix='isolate_')
1181 run_isolated.rmtree(self.tempdir)
1183 super(IsolateFormatTmpDirTest, self).tearDown()
1185 def test_load_with_includes(self):
1186 included_isolate = {
1188 'isolate_dependency_tracked': [
1195 'isolate_dependency_tracked': [
1201 ['OS=="mac" or OS=="win"', {
1203 'isolate_dependency_tracked': [
1211 with open(os.path.join(self.tempdir, 'included.isolate'), 'wb') as f:
1212 isolate_format.pretty_print(included_isolate, f)
1214 'includes': ['included.isolate'],
1216 'isolate_dependency_tracked': [
1223 'isolate_dependency_tracked': [
1231 actual = isolate_format.load_isolate_as_config(self.tempdir, values, None)
1235 'isolate_dependency_tracked': [
1239 'isolate_dir': self.tempdir,
1242 'isolate_dependency_tracked': [
1245 'isolate_dir': self.tempdir,
1249 'isolate_dependency_tracked': [
1253 'isolate_dir': self.tempdir,
1257 'isolate_dependency_tracked': [
1260 'isolate_dir': self.tempdir,
1264 self.assertEqual(expected, actual.flatten())
1266 def test_load_with_includes_with_commands(self):
1267 # This one is messy. Check that isolate_dir is the expected value. To
1268 # achieve this, put the .isolate files into subdirectories.
1269 dir_1 = os.path.join(self.tempdir, '1')
1270 dir_3 = os.path.join(self.tempdir, '3')
1271 dir_3_2 = os.path.join(self.tempdir, '3', '2')
1278 ['OS=="amiga" or OS=="win"', {
1281 'foo', 'amiga_or_win',
1290 'isolate_dependency_tracked': [
1295 ['OS=="mac" or OS=="win"', {
1297 'isolate_dependency_tracked': [
1306 ['OS=="linux" or OS=="mac"', {
1309 'foo', 'linux_or_mac',
1311 'isolate_dependency_tracked': [
1320 '../1/isolate1.isolate',
1321 '2/isolate2.isolate',
1326 'isolate_dependency_tracked': [
1336 'isolate_dependency_tracked': [
1343 # No need to write isolate3.
1344 with open(os.path.join(dir_1, 'isolate1.isolate'), 'wb') as f:
1345 isolate_format.pretty_print(isolate1, f)
1346 with open(os.path.join(dir_3_2, 'isolate2.isolate'), 'wb') as f:
1347 isolate_format.pretty_print(isolate2, f)
1349 # The 'isolate_dir' are important, they are what will be used when
1350 # definining the final isolate_dir to use to run the command in the
1352 actual = isolate_format.load_isolate_as_config(dir_3, isolate3, None)
1355 # TODO(maruel): See TODO in ConfigSettings.flatten().
1356 # TODO(maruel): If kept, in this case dir_3 should be selected.
1357 'isolate_dir': dir_1,
1360 'command': ['foo', 'amiga_or_win'],
1361 'isolate_dependency_tracked': [
1362 # Note that the file was rebased from isolate1. This is important,
1363 # isolate1 represent the canonical root path because it is the one
1364 # that defined the command.
1367 'isolate_dir': dir_1,
1370 # Last included takes precedence. *command comes from isolate2*, so
1371 # it becomes the canonical root, so reference to file from isolate1 is
1373 'command': ['foo', 'linux_or_mac'],
1374 'isolate_dependency_tracked': [
1375 '../../1/file_linux',
1378 'isolate_dir': dir_3_2,
1381 # command in isolate3 takes precedence over the ones included.
1382 'command': ['foo', 'mac'],
1383 'isolate_dependency_tracked': [
1384 '../1/file_non_linux',
1388 'isolate_dir': dir_3,
1391 # command comes from isolate1.
1392 'command': ['foo', 'amiga_or_win'],
1393 'isolate_dependency_tracked': [
1394 # While this may be surprising, this is because the command was
1395 # defined in isolate1, not isolate3.
1398 'isolate_dir': dir_1,
1401 self.assertEqual(expected, actual.flatten())
1403 def test_load_with_includes_with_commands_and_variables(self):
1404 # This one is the pinacle of fun. Check that isolate_dir is the expected
1405 # value. To achieve this, put the .isolate files into subdirectories.
1406 dir_1 = os.path.join(self.tempdir, '1')
1407 dir_3 = os.path.join(self.tempdir, '3')
1408 dir_3_2 = os.path.join(self.tempdir, '3', '2')
1415 ['OS=="amiga" or OS=="win"', {
1418 'foo', 'amiga_or_win', '<(PATH)',
1425 'foo', 'linux', '<(PATH)',
1427 'isolate_dependency_tracked': [
1428 '<(PATH)/file_linux',
1432 ['OS=="mac" or OS=="win"', {
1434 'isolate_dependency_tracked': [
1435 '<(PATH)/file_non_linux',
1443 ['OS=="linux" or OS=="mac"', {
1446 'foo', 'linux_or_mac', '<(PATH)',
1448 'isolate_dependency_tracked': [
1449 '<(PATH)/other/file',
1457 '../1/isolate1.isolate',
1458 '2/isolate2.isolate',
1463 'isolate_dependency_tracked': [
1464 '<(PATH)/file_amiga',
1471 'foo', 'mac', '<(PATH)',
1473 'isolate_dependency_tracked': [
1480 # No need to write isolate3.
1481 with open(os.path.join(dir_1, 'isolate1.isolate'), 'wb') as f:
1482 isolate_format.pretty_print(isolate1, f)
1483 with open(os.path.join(dir_3_2, 'isolate2.isolate'), 'wb') as f:
1484 isolate_format.pretty_print(isolate2, f)
1486 # The 'isolate_dir' are important, they are what will be used when
1487 # definining the final isolate_dir to use to run the command in the
1489 actual = isolate_format.load_isolate_as_config(dir_3, isolate3, None)
1492 'isolate_dir': dir_1,
1495 'command': ['foo', 'amiga_or_win', '<(PATH)'],
1496 'isolate_dependency_tracked': [
1497 '<(PATH)/file_amiga',
1499 'isolate_dir': dir_1,
1502 # Last included takes precedence. *command comes from isolate2*, so
1503 # it becomes the canonical root, so reference to file from isolate1 is
1505 'command': ['foo', 'linux_or_mac', '<(PATH)'],
1506 'isolate_dependency_tracked': [
1507 '<(PATH)/file_linux',
1508 '<(PATH)/other/file',
1510 'isolate_dir': dir_3_2,
1513 'command': ['foo', 'mac', '<(PATH)'],
1514 'isolate_dependency_tracked': [
1516 '<(PATH)/file_non_linux',
1517 '<(PATH)/other/file',
1519 'isolate_dir': dir_3,
1522 # command comes from isolate1.
1523 'command': ['foo', 'amiga_or_win', '<(PATH)'],
1524 'isolate_dependency_tracked': [
1525 '<(PATH)/file_non_linux',
1527 'isolate_dir': dir_1,
1530 self.assertEqual(expected, actual.flatten())
1533 if __name__ == '__main__':
1534 logging.basicConfig(
1535 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR,
1536 format='%(levelname)5s %(filename)15s(%(lineno)3d): %(message)s')
1537 if '-v' in sys.argv:
1538 unittest.TestCase.maxDiff = None