OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium 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 import cStringIO | |
7 import hashlib | |
8 import json | |
9 import logging | |
10 import os | |
11 import sys | |
12 import tempfile | |
13 import unittest | |
14 | |
15 import auto_stub | |
16 | |
17 ROOT_DIR = unicode(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
18 sys.path.insert(0, ROOT_DIR) | |
19 | |
20 import isolate | |
21 from utils import file_path | |
22 # Create shortcuts. | |
23 from isolate import KEY_TOUCHED, KEY_TRACKED, KEY_UNTRACKED | |
24 | |
25 | |
26 ALGO = hashlib.sha1 | |
27 | |
28 | |
29 def _size(*args): | |
30 return os.stat(os.path.join(ROOT_DIR, *args)).st_size | |
31 | |
32 | |
33 def hash_file(*args): | |
34 return isolate.isolateserver.hash_file(os.path.join(ROOT_DIR, *args), ALGO) | |
35 | |
36 | |
37 class IsolateBase(auto_stub.TestCase): | |
38 def setUp(self): | |
39 super(IsolateBase, self).setUp() | |
40 self.old_cwd = os.getcwd() | |
41 self.cwd = tempfile.mkdtemp(prefix='isolate_') | |
42 # Everything should work even from another directory. | |
43 os.chdir(self.cwd) | |
44 | |
45 def tearDown(self): | |
46 try: | |
47 os.chdir(self.old_cwd) | |
48 isolate.run_isolated.rmtree(self.cwd) | |
49 finally: | |
50 super(IsolateBase, self).tearDown() | |
51 | |
52 | |
53 class IsolateTest(IsolateBase): | |
54 def test_savedstate_load_minimal(self): | |
55 # The file referenced by 'isolate_file' must exist even if its content is | |
56 # not read. | |
57 open(os.path.join(self.cwd, 'fake.isolate'), 'wb').close() | |
58 values = { | |
59 'isolate_file': 'fake.isolate', | |
60 } | |
61 expected = { | |
62 'algo': 'sha-1', | |
63 'child_isolated_files': [], | |
64 'command': [], | |
65 'files': {}, | |
66 'isolate_file': 'fake.isolate', | |
67 'variables': { | |
68 'OS': isolate.get_flavor(), | |
69 }, | |
70 'version': '1.0', | |
71 } | |
72 saved_state = isolate.SavedState.load(values, self.cwd) | |
73 self.assertEqual(expected, saved_state.flatten()) | |
74 | |
75 def test_savedstate_load(self): | |
76 # The file referenced by 'isolate_file' must exist even if its content is | |
77 # not read. | |
78 open(os.path.join(self.cwd, 'fake.isolate'), 'wb').close() | |
79 values = { | |
80 'isolate_file': 'fake.isolate', | |
81 'variables': { | |
82 'foo': 42, | |
83 'OS': isolate.get_flavor(), | |
84 }, | |
85 } | |
86 expected = { | |
87 'algo': 'sha-1', | |
88 'child_isolated_files': [], | |
89 'command': [], | |
90 'files': {}, | |
91 'isolate_file': 'fake.isolate', | |
92 'variables': { | |
93 'foo': 42, | |
94 'OS': isolate.get_flavor(), | |
95 }, | |
96 'version': '1.0', | |
97 } | |
98 saved_state = isolate.SavedState.load(values, self.cwd) | |
99 self.assertEqual(expected, saved_state.flatten()) | |
100 | |
101 def test_unknown_key(self): | |
102 try: | |
103 isolate.verify_variables({'foo': [],}) | |
104 self.fail() | |
105 except AssertionError: | |
106 pass | |
107 | |
108 def test_unknown_var(self): | |
109 try: | |
110 isolate.verify_condition({'variables': {'foo': [],}}, {}) | |
111 self.fail() | |
112 except AssertionError: | |
113 pass | |
114 | |
115 def test_union(self): | |
116 value1 = { | |
117 'a': set(['A']), | |
118 'b': ['B', 'C'], | |
119 'c': 'C', | |
120 } | |
121 value2 = { | |
122 'a': set(['B', 'C']), | |
123 'b': [], | |
124 'd': set(), | |
125 } | |
126 expected = { | |
127 'a': set(['A', 'B', 'C']), | |
128 'b': ['B', 'C'], | |
129 'c': 'C', | |
130 'd': set(), | |
131 } | |
132 self.assertEqual(expected, isolate.union(value1, value2)) | |
133 | |
134 def test_eval_content(self): | |
135 try: | |
136 # Intrinsics are not available. | |
137 isolate.eval_content('map(str, [1, 2])') | |
138 self.fail() | |
139 except NameError: | |
140 pass | |
141 | |
142 def test_load_isolate_as_config_empty(self): | |
143 self.assertEqual({}, isolate.load_isolate_as_config( | |
144 self.cwd, {}, None).flatten()) | |
145 | |
146 def test_load_isolate_as_config(self): | |
147 value = { | |
148 'conditions': [ | |
149 ['OS=="amiga" or OS=="atari" or OS=="coleco" or OS=="dendy"', { | |
150 'variables': { | |
151 KEY_TRACKED: ['a'], | |
152 KEY_UNTRACKED: ['b'], | |
153 KEY_TOUCHED: ['touched'], | |
154 }, | |
155 }], | |
156 ['OS=="atari"', { | |
157 'variables': { | |
158 KEY_TRACKED: ['c', 'x'], | |
159 KEY_UNTRACKED: ['d'], | |
160 KEY_TOUCHED: ['touched_a'], | |
161 'command': ['echo', 'Hello World'], | |
162 'read_only': True, | |
163 }, | |
164 }], | |
165 ['OS=="amiga" or OS=="coleco" or OS=="dendy"', { | |
166 'variables': { | |
167 KEY_TRACKED: ['e', 'x'], | |
168 KEY_UNTRACKED: ['f'], | |
169 KEY_TOUCHED: ['touched_e'], | |
170 'command': ['echo', 'You should get an Atari'], | |
171 }, | |
172 }], | |
173 ['OS=="amiga"', { | |
174 'variables': { | |
175 KEY_TRACKED: ['g'], | |
176 'read_only': False, | |
177 }, | |
178 }], | |
179 ['OS=="amiga" or OS=="atari" or OS=="dendy"', { | |
180 'variables': { | |
181 KEY_UNTRACKED: ['h'], | |
182 }, | |
183 }], | |
184 ], | |
185 } | |
186 expected = { | |
187 ('amiga',): { | |
188 'command': ['echo', 'You should get an Atari'], | |
189 KEY_TOUCHED: ['touched', 'touched_e'], | |
190 KEY_TRACKED: ['a', 'e', 'g', 'x'], | |
191 KEY_UNTRACKED: ['b', 'f', 'h'], | |
192 'read_only': False, | |
193 }, | |
194 ('atari',): { | |
195 'command': ['echo', 'Hello World'], | |
196 KEY_TOUCHED: ['touched', 'touched_a'], | |
197 KEY_TRACKED: ['a', 'c', 'x'], | |
198 KEY_UNTRACKED: ['b', 'd', 'h'], | |
199 'read_only': True, | |
200 }, | |
201 ('coleco',): { | |
202 'command': ['echo', 'You should get an Atari'], | |
203 KEY_TOUCHED: ['touched', 'touched_e'], | |
204 KEY_TRACKED: ['a', 'e', 'x'], | |
205 KEY_UNTRACKED: ['b', 'f'], | |
206 }, | |
207 ('dendy',): { | |
208 'command': ['echo', 'You should get an Atari'], | |
209 KEY_TOUCHED: ['touched', 'touched_e'], | |
210 KEY_TRACKED: ['a', 'e', 'x'], | |
211 KEY_UNTRACKED: ['b', 'f', 'h'], | |
212 }, | |
213 } | |
214 self.assertEqual( | |
215 expected, isolate.load_isolate_as_config( | |
216 self.cwd, value, None).flatten()) | |
217 | |
218 def test_load_isolate_as_config_duplicate_command(self): | |
219 value = { | |
220 'variables': { | |
221 'command': ['rm', '-rf', '/'], | |
222 }, | |
223 'conditions': [ | |
224 ['OS=="atari"', { | |
225 'variables': { | |
226 'command': ['echo', 'Hello World'], | |
227 }, | |
228 }], | |
229 ], | |
230 } | |
231 try: | |
232 isolate.load_isolate_as_config(self.cwd, value, None) | |
233 self.fail() | |
234 except AssertionError: | |
235 pass | |
236 | |
237 def test_invert_map(self): | |
238 value = { | |
239 ('amiga',): { | |
240 'command': ['echo', 'You should get an Atari'], | |
241 KEY_TOUCHED: ['touched', 'touched_e'], | |
242 KEY_TRACKED: ['a', 'e', 'g', 'x'], | |
243 KEY_UNTRACKED: ['b', 'f', 'h'], | |
244 'read_only': False, | |
245 }, | |
246 ('atari',): { | |
247 'command': ['echo', 'Hello World'], | |
248 KEY_TOUCHED: ['touched', 'touched_a'], | |
249 KEY_TRACKED: ['a', 'c', 'x'], | |
250 KEY_UNTRACKED: ['b', 'd', 'h'], | |
251 'read_only': True, | |
252 }, | |
253 ('coleco',): { | |
254 'command': ['echo', 'You should get an Atari'], | |
255 KEY_TOUCHED: ['touched', 'touched_e'], | |
256 KEY_TRACKED: ['a', 'e', 'x'], | |
257 KEY_UNTRACKED: ['b', 'f'], | |
258 }, | |
259 ('dendy',): { | |
260 'command': ['echo', 'You should get an Atari'], | |
261 KEY_TOUCHED: ['touched', 'touched_e'], | |
262 KEY_TRACKED: ['a', 'e', 'x'], | |
263 KEY_UNTRACKED: ['b', 'f', 'h'], | |
264 }, | |
265 } | |
266 amiga, atari, coleco, dendy = ( | |
267 set([(os,)]) for os in ('amiga', 'atari', 'coleco', 'dendy')) | |
268 expected_values = { | |
269 'command': { | |
270 ('echo', 'Hello World'): atari, | |
271 ('echo', 'You should get an Atari'): amiga | coleco | dendy, | |
272 }, | |
273 KEY_TRACKED: { | |
274 'a': amiga | atari | coleco | dendy, | |
275 'c': atari, | |
276 'e': amiga | coleco | dendy, | |
277 'g': amiga, | |
278 'x': amiga | atari | coleco | dendy, | |
279 }, | |
280 KEY_UNTRACKED: { | |
281 'b': amiga | atari | coleco | dendy, | |
282 'd': atari, | |
283 'f': amiga | coleco | dendy, | |
284 'h': amiga | atari | dendy, | |
285 }, | |
286 KEY_TOUCHED: { | |
287 'touched': amiga | atari | coleco | dendy, | |
288 'touched_a': atari, | |
289 'touched_e': amiga | coleco | dendy, | |
290 }, | |
291 'read_only': { | |
292 False: amiga, | |
293 True: atari, | |
294 }, | |
295 } | |
296 actual_values = isolate.invert_map(value) | |
297 self.assertEqual(expected_values, actual_values) | |
298 | |
299 def test_reduce_inputs(self): | |
300 amiga, atari, coleco, dendy = ( | |
301 set([(os,)]) for os in ('amiga', 'atari', 'coleco', 'dendy')) | |
302 values = { | |
303 'command': { | |
304 ('echo', 'Hello World'): atari, | |
305 ('echo', 'You should get an Atari'): amiga | coleco | dendy, | |
306 }, | |
307 KEY_TRACKED: { | |
308 'a': amiga | atari | coleco | dendy, | |
309 'c': atari, | |
310 'e': amiga | coleco | dendy, | |
311 'g': amiga, | |
312 'x': amiga | atari | coleco | dendy, | |
313 }, | |
314 KEY_UNTRACKED: { | |
315 'b': amiga | atari | coleco | dendy, | |
316 'd': atari, | |
317 'f': amiga | coleco | dendy, | |
318 'h': amiga | atari | dendy, | |
319 }, | |
320 KEY_TOUCHED: { | |
321 'touched': amiga | atari | coleco | dendy, | |
322 'touched_a': atari, | |
323 'touched_e': amiga | coleco | dendy, | |
324 }, | |
325 'read_only': { | |
326 False: amiga, | |
327 True: atari, | |
328 }, | |
329 } | |
330 expected_values = { | |
331 'command': { | |
332 ('echo', 'Hello World'): atari, | |
333 ('echo', 'You should get an Atari'): amiga | coleco | dendy, | |
334 }, | |
335 KEY_TRACKED: { | |
336 'a': amiga | atari | coleco | dendy, | |
337 'c': atari, | |
338 'e': amiga | coleco | dendy, | |
339 'g': amiga, | |
340 'x': amiga | atari | coleco | dendy, | |
341 }, | |
342 KEY_UNTRACKED: { | |
343 'b': amiga | atari | coleco | dendy, | |
344 'd': atari, | |
345 'f': amiga | coleco | dendy, | |
346 'h': amiga | atari | dendy, | |
347 }, | |
348 KEY_TOUCHED: { | |
349 'touched': amiga | atari | coleco | dendy, | |
350 'touched_a': atari, | |
351 'touched_e': amiga | coleco | dendy, | |
352 }, | |
353 'read_only': { | |
354 False: amiga, | |
355 True: atari, | |
356 }, | |
357 } | |
358 actual_values = isolate.reduce_inputs(values) | |
359 self.assertEqual(expected_values, actual_values) | |
360 | |
361 def test_reduce_inputs_merge_subfolders_and_files(self): | |
362 linux, mac, win = (set([(os,)]) for os in ('linux', 'mac', 'win')) | |
363 values = { | |
364 KEY_TRACKED: { | |
365 'folder/tracked_file': win, | |
366 'folder_helper/tracked_file': win, | |
367 }, | |
368 KEY_UNTRACKED: { | |
369 'folder/': linux | mac | win, | |
370 'folder/subfolder/': win, | |
371 'folder/untracked_file': linux | mac | win, | |
372 'folder_helper/': linux, | |
373 }, | |
374 KEY_TOUCHED: { | |
375 'folder/touched_file': win, | |
376 'folder/helper_folder/deep_file': win, | |
377 'folder_helper/touched_file1': mac | win, | |
378 'folder_helper/touched_file2': linux, | |
379 }, | |
380 } | |
381 expected_values = { | |
382 'command': {}, | |
383 KEY_TRACKED: { | |
384 'folder_helper/tracked_file': win, | |
385 }, | |
386 KEY_UNTRACKED: { | |
387 'folder/': linux | mac | win, | |
388 'folder_helper/': linux, | |
389 }, | |
390 KEY_TOUCHED: { | |
391 'folder_helper/touched_file1': mac | win, | |
392 }, | |
393 'read_only': {}, | |
394 } | |
395 actual_values = isolate.reduce_inputs(values) | |
396 self.assertEqual(expected_values, actual_values) | |
397 | |
398 def test_reduce_inputs_take_strongest_dependency(self): | |
399 amiga, atari, coleco, dendy = ( | |
400 set([(os,)]) for os in ('amiga', 'atari', 'coleco', 'dendy')) | |
401 values = { | |
402 'command': { | |
403 ('echo', 'Hello World'): atari, | |
404 ('echo', 'You should get an Atari'): amiga | coleco | dendy, | |
405 }, | |
406 KEY_TRACKED: { | |
407 'a': amiga | atari | coleco | dendy, | |
408 'b': amiga | atari | coleco, | |
409 }, | |
410 KEY_UNTRACKED: { | |
411 'c': amiga | atari | coleco | dendy, | |
412 'd': amiga | coleco | dendy, | |
413 }, | |
414 KEY_TOUCHED: { | |
415 'a': amiga | atari | coleco | dendy, | |
416 'b': atari | coleco | dendy, | |
417 'c': amiga | atari | coleco | dendy, | |
418 'd': atari | coleco | dendy, | |
419 }, | |
420 } | |
421 expected_values = { | |
422 'command': { | |
423 ('echo', 'Hello World'): atari, | |
424 ('echo', 'You should get an Atari'): amiga | coleco | dendy, | |
425 }, | |
426 KEY_TRACKED: { | |
427 'a': amiga | atari | coleco | dendy, | |
428 'b': amiga | atari | coleco, | |
429 }, | |
430 KEY_UNTRACKED: { | |
431 'c': amiga | atari | coleco | dendy, | |
432 'd': amiga | coleco | dendy, | |
433 }, | |
434 KEY_TOUCHED: { | |
435 'b': dendy, | |
436 'd': atari, | |
437 }, | |
438 'read_only': {}, | |
439 } | |
440 actual_values = isolate.reduce_inputs(values) | |
441 self.assertEqual(expected_values, actual_values) | |
442 | |
443 def test_convert_map_to_isolate_dict(self): | |
444 amiga = ('amiga',) | |
445 atari = ('atari',) | |
446 coleco = ('coleco',) | |
447 dendy = ('dendy',) | |
448 values = { | |
449 'command': { | |
450 ('echo', 'Hello World'): (atari,), | |
451 ('echo', 'You should get an Atari'): (amiga, coleco, dendy), | |
452 }, | |
453 KEY_TRACKED: { | |
454 'a': (amiga, atari, coleco, dendy), | |
455 'c': (atari,), | |
456 'e': (amiga, coleco, dendy), | |
457 'g': (amiga,), | |
458 'x': (amiga, atari, coleco, dendy), | |
459 }, | |
460 KEY_UNTRACKED: { | |
461 'b': (amiga, atari, coleco, dendy), | |
462 'd': (atari,), | |
463 'f': (amiga, coleco, dendy), | |
464 'h': (amiga, atari, dendy), | |
465 }, | |
466 KEY_TOUCHED: { | |
467 'touched': (amiga, atari, coleco, dendy), | |
468 'touched_a': (atari,), | |
469 'touched_e': (amiga, coleco, dendy), | |
470 }, | |
471 'read_only': { | |
472 False: (amiga,), | |
473 True: (atari,), | |
474 }, | |
475 } | |
476 expected_conditions = [ | |
477 ['OS=="amiga"', { | |
478 'variables': { | |
479 KEY_TRACKED: ['g'], | |
480 'read_only': False, | |
481 }, | |
482 }], | |
483 ['OS=="amiga" or OS=="atari" or OS=="coleco" or OS=="dendy"', { | |
484 'variables': { | |
485 KEY_TRACKED: ['a', 'x'], | |
486 KEY_UNTRACKED: ['b'], | |
487 KEY_TOUCHED: ['touched'], | |
488 }, | |
489 }], | |
490 ['OS=="amiga" or OS=="atari" or OS=="dendy"', { | |
491 'variables': { | |
492 KEY_UNTRACKED: ['h'], | |
493 }, | |
494 }], | |
495 ['OS=="amiga" or OS=="coleco" or OS=="dendy"', { | |
496 'variables': { | |
497 'command': ['echo', 'You should get an Atari'], | |
498 KEY_TRACKED: ['e'], | |
499 KEY_UNTRACKED: ['f'], | |
500 KEY_TOUCHED: ['touched_e'], | |
501 }, | |
502 }], | |
503 ['OS=="atari"', { | |
504 'variables': { | |
505 'command': ['echo', 'Hello World'], | |
506 KEY_TRACKED: ['c'], | |
507 KEY_UNTRACKED: ['d'], | |
508 KEY_TOUCHED: ['touched_a'], | |
509 'read_only': True, | |
510 }, | |
511 }], | |
512 ] | |
513 actual = isolate.convert_map_to_isolate_dict(values, ('OS',)) | |
514 self.assertEqual(expected_conditions, sorted(actual.pop('conditions'))) | |
515 self.assertFalse(actual) | |
516 | |
517 def test_merge_two_empty(self): | |
518 # Flat stay flat. Pylint is confused about union() return type. | |
519 # pylint: disable=E1103 | |
520 actual = isolate.union( | |
521 isolate.union( | |
522 isolate.Configs(None), | |
523 isolate.load_isolate_as_config(self.cwd, {}, None)), | |
524 isolate.load_isolate_as_config(self.cwd, {}, None)).flatten() | |
525 self.assertEqual({}, actual) | |
526 | |
527 def test_merge_empty(self): | |
528 actual = isolate.convert_map_to_isolate_dict( | |
529 isolate.reduce_inputs(isolate.invert_map({})), ('dummy1', 'dummy2')) | |
530 self.assertEqual({'conditions': []}, actual) | |
531 | |
532 def test_load_two_conditions(self): | |
533 linux = { | |
534 'conditions': [ | |
535 ['OS=="linux"', { | |
536 'variables': { | |
537 'isolate_dependency_tracked': [ | |
538 'file_linux', | |
539 'file_common', | |
540 ], | |
541 }, | |
542 }], | |
543 ], | |
544 } | |
545 mac = { | |
546 'conditions': [ | |
547 ['OS=="mac"', { | |
548 'variables': { | |
549 'isolate_dependency_tracked': [ | |
550 'file_mac', | |
551 'file_common', | |
552 ], | |
553 }, | |
554 }], | |
555 ], | |
556 } | |
557 expected = { | |
558 ('linux',): { | |
559 'isolate_dependency_tracked': ['file_common', 'file_linux'], | |
560 }, | |
561 ('mac',): { | |
562 'isolate_dependency_tracked': ['file_common', 'file_mac'], | |
563 }, | |
564 } | |
565 # Pylint is confused about union() return type. | |
566 # pylint: disable=E1103 | |
567 configs = isolate.union( | |
568 isolate.union( | |
569 isolate.Configs(None), | |
570 isolate.load_isolate_as_config(self.cwd, linux, None)), | |
571 isolate.load_isolate_as_config(self.cwd, mac, None)).flatten() | |
572 self.assertEqual(expected, configs) | |
573 | |
574 def test_load_three_conditions(self): | |
575 linux = { | |
576 'conditions': [ | |
577 ['OS=="linux" and chromeos==1', { | |
578 'variables': { | |
579 'isolate_dependency_tracked': [ | |
580 'file_linux', | |
581 'file_common', | |
582 ], | |
583 }, | |
584 }], | |
585 ], | |
586 } | |
587 mac = { | |
588 'conditions': [ | |
589 ['OS=="mac" and chromeos==0', { | |
590 'variables': { | |
591 'isolate_dependency_tracked': [ | |
592 'file_mac', | |
593 'file_common', | |
594 ], | |
595 }, | |
596 }], | |
597 ], | |
598 } | |
599 win = { | |
600 'conditions': [ | |
601 ['OS=="win" and chromeos==0', { | |
602 'variables': { | |
603 'isolate_dependency_tracked': [ | |
604 'file_win', | |
605 'file_common', | |
606 ], | |
607 }, | |
608 }], | |
609 ], | |
610 } | |
611 expected = { | |
612 ('linux', 1): { | |
613 'isolate_dependency_tracked': ['file_common', 'file_linux'], | |
614 }, | |
615 ('mac', 0): { | |
616 'isolate_dependency_tracked': ['file_common', 'file_mac'], | |
617 }, | |
618 ('win', 0): { | |
619 'isolate_dependency_tracked': ['file_common', 'file_win'], | |
620 }, | |
621 } | |
622 # Pylint is confused about union() return type. | |
623 # pylint: disable=E1103 | |
624 configs = isolate.union( | |
625 isolate.union( | |
626 isolate.union( | |
627 isolate.Configs(None), | |
628 isolate.load_isolate_as_config(self.cwd, linux, None)), | |
629 isolate.load_isolate_as_config(self.cwd, mac, None)), | |
630 isolate.load_isolate_as_config(self.cwd, win, None)).flatten() | |
631 self.assertEqual(expected, configs) | |
632 | |
633 def test_merge_three_conditions(self): | |
634 values = { | |
635 ('linux',): { | |
636 'isolate_dependency_tracked': ['file_common', 'file_linux'], | |
637 }, | |
638 ('mac',): { | |
639 'isolate_dependency_tracked': ['file_common', 'file_mac'], | |
640 }, | |
641 ('win',): { | |
642 'isolate_dependency_tracked': ['file_common', 'file_win'], | |
643 }, | |
644 } | |
645 expected = { | |
646 'conditions': [ | |
647 ['OS=="linux"', { | |
648 'variables': { | |
649 'isolate_dependency_tracked': [ | |
650 'file_linux', | |
651 ], | |
652 }, | |
653 }], | |
654 ['OS=="linux" or OS=="mac" or OS=="win"', { | |
655 'variables': { | |
656 'isolate_dependency_tracked': [ | |
657 'file_common', | |
658 ], | |
659 }, | |
660 }], | |
661 ['OS=="mac"', { | |
662 'variables': { | |
663 'isolate_dependency_tracked': [ | |
664 'file_mac', | |
665 ], | |
666 }, | |
667 }], | |
668 ['OS=="win"', { | |
669 'variables': { | |
670 'isolate_dependency_tracked': [ | |
671 'file_win', | |
672 ], | |
673 }, | |
674 }], | |
675 ], | |
676 } | |
677 actual = isolate.convert_map_to_isolate_dict( | |
678 isolate.reduce_inputs(isolate.invert_map(values)), ('OS',)) | |
679 self.assertEqual(expected, actual) | |
680 | |
681 def test_configs_comment(self): | |
682 # Pylint is confused with isolate.union() return type. | |
683 # pylint: disable=E1103 | |
684 configs = isolate.union( | |
685 isolate.load_isolate_as_config( | |
686 self.cwd, {}, '# Yo dawg!\n# Chill out.\n'), | |
687 isolate.load_isolate_as_config(self.cwd, {}, None)) | |
688 self.assertEqual('# Yo dawg!\n# Chill out.\n', configs.file_comment) | |
689 | |
690 configs = isolate.union( | |
691 isolate.load_isolate_as_config(self.cwd, {}, None), | |
692 isolate.load_isolate_as_config( | |
693 self.cwd, {}, '# Yo dawg!\n# Chill out.\n')) | |
694 self.assertEqual('# Yo dawg!\n# Chill out.\n', configs.file_comment) | |
695 | |
696 # Only keep the first one. | |
697 configs = isolate.union( | |
698 isolate.load_isolate_as_config(self.cwd, {}, '# Yo dawg!\n'), | |
699 isolate.load_isolate_as_config(self.cwd, {}, '# Chill out.\n')) | |
700 self.assertEqual('# Yo dawg!\n', configs.file_comment) | |
701 | |
702 def test_load_with_includes(self): | |
703 included_isolate = { | |
704 'variables': { | |
705 'isolate_dependency_tracked': [ | |
706 'file_common', | |
707 ], | |
708 }, | |
709 'conditions': [ | |
710 ['OS=="linux"', { | |
711 'variables': { | |
712 'isolate_dependency_tracked': [ | |
713 'file_linux', | |
714 ], | |
715 }, | |
716 }, { | |
717 'variables': { | |
718 'isolate_dependency_tracked': [ | |
719 'file_non_linux', | |
720 ], | |
721 }, | |
722 }], | |
723 ], | |
724 } | |
725 isolate.trace_inputs.write_json( | |
726 os.path.join(self.cwd, 'included.isolate'), included_isolate, True) | |
727 values = { | |
728 'includes': ['included.isolate'], | |
729 'variables': { | |
730 'isolate_dependency_tracked': [ | |
731 'file_less_common', | |
732 ], | |
733 }, | |
734 'conditions': [ | |
735 ['OS=="mac"', { | |
736 'variables': { | |
737 'isolate_dependency_tracked': [ | |
738 'file_mac', | |
739 ], | |
740 }, | |
741 }], | |
742 ], | |
743 } | |
744 actual = isolate.load_isolate_as_config(self.cwd, values, None) | |
745 | |
746 expected = { | |
747 ('linux',): { | |
748 'isolate_dependency_tracked': [ | |
749 'file_common', | |
750 'file_less_common', | |
751 'file_linux', | |
752 ], | |
753 }, | |
754 ('mac',): { | |
755 'isolate_dependency_tracked': [ | |
756 'file_common', | |
757 'file_less_common', | |
758 'file_mac', | |
759 'file_non_linux', | |
760 ], | |
761 }, | |
762 ('win',): { | |
763 'isolate_dependency_tracked': [ | |
764 'file_common', | |
765 'file_less_common', | |
766 'file_non_linux', | |
767 ], | |
768 }, | |
769 } | |
770 self.assertEqual(expected, actual.flatten()) | |
771 | |
772 def test_extract_comment(self): | |
773 self.assertEqual( | |
774 '# Foo\n# Bar\n', isolate.extract_comment('# Foo\n# Bar\n{}')) | |
775 self.assertEqual('', isolate.extract_comment('{}')) | |
776 | |
777 def _test_pretty_print_impl(self, value, expected): | |
778 actual = cStringIO.StringIO() | |
779 isolate.pretty_print(value, actual) | |
780 self.assertEqual(expected, actual.getvalue()) | |
781 | |
782 def test_pretty_print_empty(self): | |
783 self._test_pretty_print_impl({}, '{\n}\n') | |
784 | |
785 def test_pretty_print_mid_size(self): | |
786 value = { | |
787 'variables': { | |
788 'bar': [ | |
789 'file1', | |
790 'file2', | |
791 ], | |
792 }, | |
793 'conditions': [ | |
794 ['OS=\"foo\"', { | |
795 'variables': { | |
796 isolate.KEY_UNTRACKED: [ | |
797 'dir1', | |
798 'dir2', | |
799 ], | |
800 isolate.KEY_TRACKED: [ | |
801 'file4', | |
802 'file3', | |
803 ], | |
804 'command': ['python', '-c', 'print "H\\i\'"'], | |
805 'read_only': True, | |
806 'relative_cwd': 'isol\'at\\e', | |
807 }, | |
808 }], | |
809 ['OS=\"bar\"', { | |
810 'variables': {}, | |
811 }, { | |
812 'variables': {}, | |
813 }], | |
814 ], | |
815 } | |
816 expected = ( | |
817 "{\n" | |
818 " 'variables': {\n" | |
819 " 'bar': [\n" | |
820 " 'file1',\n" | |
821 " 'file2',\n" | |
822 " ],\n" | |
823 " },\n" | |
824 " 'conditions': [\n" | |
825 " ['OS=\"foo\"', {\n" | |
826 " 'variables': {\n" | |
827 " 'command': [\n" | |
828 " 'python',\n" | |
829 " '-c',\n" | |
830 " 'print \"H\\i\'\"',\n" | |
831 " ],\n" | |
832 " 'relative_cwd': 'isol\\'at\\\\e',\n" | |
833 " 'read_only': True\n" | |
834 " 'isolate_dependency_tracked': [\n" | |
835 " 'file4',\n" | |
836 " 'file3',\n" | |
837 " ],\n" | |
838 " 'isolate_dependency_untracked': [\n" | |
839 " 'dir1',\n" | |
840 " 'dir2',\n" | |
841 " ],\n" | |
842 " },\n" | |
843 " }],\n" | |
844 " ['OS=\"bar\"', {\n" | |
845 " 'variables': {\n" | |
846 " },\n" | |
847 " }, {\n" | |
848 " 'variables': {\n" | |
849 " },\n" | |
850 " }],\n" | |
851 " ],\n" | |
852 "}\n") | |
853 self._test_pretty_print_impl(value, expected) | |
854 | |
855 def test_convert_old_to_new_bypass(self): | |
856 isolate_not_needing_conversion = { | |
857 'conditions': [ | |
858 ['OS=="mac"', {'variables': {'foo': 'bar'}}], | |
859 ['condition shouldn\'t matter', {'variables': {'x': 'y'}}], | |
860 ], | |
861 } | |
862 self.assertEqual( | |
863 isolate_not_needing_conversion, | |
864 isolate.convert_old_to_new_format(isolate_not_needing_conversion)) | |
865 | |
866 def test_convert_old_to_new_else(self): | |
867 isolate_with_else_clauses = { | |
868 'conditions': [ | |
869 ['OS=="mac"', { | |
870 'variables': {'foo': 'bar'}, | |
871 }, { | |
872 'variables': {'x': 'y'}, | |
873 }], | |
874 ['OS=="foo"', { | |
875 }, { | |
876 'variables': {'p': 'q'}, | |
877 }], | |
878 ], | |
879 } | |
880 expected_output = { | |
881 'conditions': [ | |
882 ['OS=="foo" or OS=="linux" or OS=="win"', { | |
883 'variables': {'x': 'y'}, | |
884 }], | |
885 ['OS=="linux" or OS=="mac" or OS=="win"', { | |
886 'variables': {'p': 'q'}, | |
887 }], | |
888 ['OS=="mac"', { | |
889 'variables': {'foo': 'bar'}, | |
890 }], | |
891 ], | |
892 } | |
893 self.assertEqual( | |
894 expected_output, | |
895 isolate.convert_old_to_new_format(isolate_with_else_clauses)) | |
896 | |
897 def test_convert_old_to_new_default_variables(self): | |
898 isolate_with_default_variables = { | |
899 'conditions': [ | |
900 ['OS=="abc"', { | |
901 'variables': {'foo': 'bar'}, | |
902 }], | |
903 ], | |
904 'variables': {'p': 'q'}, | |
905 } | |
906 expected_output = { | |
907 'conditions': [ | |
908 ['OS=="abc"', { | |
909 'variables': {'foo': 'bar'}, | |
910 }], | |
911 ['OS=="abc" or OS=="linux" or OS=="mac" or OS=="win"', { | |
912 'variables': {'p': 'q'}, | |
913 }], | |
914 ], | |
915 } | |
916 self.assertEqual( | |
917 expected_output, | |
918 isolate.convert_old_to_new_format(isolate_with_default_variables)) | |
919 | |
920 def test_variable_arg(self): | |
921 parser = isolate.OptionParserIsolate() | |
922 parser.require_isolated = False | |
923 expected = { | |
924 'Baz': 'sub=string', | |
925 'EXECUTABLE_SUFFIX': '.exe' if isolate.get_flavor() == 'win' else '', | |
926 'Foo': 'bar', | |
927 'OS': isolate.get_flavor(), | |
928 } | |
929 | |
930 options, args = parser.parse_args( | |
931 ['-V', 'Foo', 'bar', '-V', 'Baz=sub=string']) | |
932 self.assertEqual(expected, options.variables) | |
933 self.assertEqual([], args) | |
934 | |
935 def test_variable_arg_fail(self): | |
936 parser = isolate.OptionParserIsolate() | |
937 self.mock(sys, 'stderr', cStringIO.StringIO()) | |
938 self.assertRaises(SystemExit, parser.parse_args, ['-V', 'Foo']) | |
939 | |
940 def test_blacklist(self): | |
941 ok = [ | |
942 '.git2', | |
943 '.pyc', | |
944 '.swp', | |
945 'allo.git', | |
946 'foo', | |
947 ] | |
948 blocked = [ | |
949 '.git', | |
950 os.path.join('foo', '.git'), | |
951 'foo.pyc', | |
952 'bar.swp', | |
953 ] | |
954 blacklist = isolate.trace_inputs.gen_blacklist(isolate.DEFAULT_BLACKLIST) | |
955 for i in ok: | |
956 self.assertFalse(blacklist(i), i) | |
957 for i in blocked: | |
958 self.assertTrue(blacklist(i), i) | |
959 | |
960 def test_blacklist_chromium(self): | |
961 ok = [ | |
962 '.run_test_cases', | |
963 'testserver.log2', | |
964 ] | |
965 blocked = [ | |
966 'foo.run_test_cases', | |
967 'testserver.log', | |
968 os.path.join('foo', 'testserver.log'), | |
969 ] | |
970 blacklist = isolate.trace_inputs.gen_blacklist(isolate.DEFAULT_BLACKLIST) | |
971 for i in ok: | |
972 self.assertFalse(blacklist(i), i) | |
973 for i in blocked: | |
974 self.assertTrue(blacklist(i), i) | |
975 | |
976 if sys.platform == 'darwin': | |
977 def test_expand_symlinks_path_case(self): | |
978 # Ensures that the resulting path case is fixed on case insensitive file | |
979 # system. | |
980 os.symlink('dest', os.path.join(self.cwd, 'link')) | |
981 os.mkdir(os.path.join(self.cwd, 'Dest')) | |
982 open(os.path.join(self.cwd, 'Dest', 'file.txt'), 'w').close() | |
983 | |
984 result = isolate.expand_symlinks(unicode(self.cwd), 'link') | |
985 self.assertEqual((u'Dest', [u'link']), result) | |
986 result = isolate.expand_symlinks(unicode(self.cwd), 'link/File.txt') | |
987 self.assertEqual((u'Dest/file.txt', [u'link']), result) | |
988 | |
989 def test_expand_directories_and_symlinks_path_case(self): | |
990 # Ensures that the resulting path case is fixed on case insensitive file | |
991 # system. A superset of test_expand_symlinks_path_case. | |
992 # Create *all* the paths with the wrong path case. | |
993 basedir = os.path.join(self.cwd, 'baseDir') | |
994 os.mkdir(basedir.lower()) | |
995 subdir = os.path.join(basedir, 'subDir') | |
996 os.mkdir(subdir.lower()) | |
997 open(os.path.join(subdir, 'Foo.txt'), 'w').close() | |
998 os.symlink('subDir', os.path.join(basedir, 'linkdir')) | |
999 actual = isolate.expand_directories_and_symlinks( | |
1000 unicode(self.cwd), [u'baseDir/'], lambda _: None, True, False) | |
1001 expected = [ | |
1002 u'basedir/linkdir', | |
1003 u'basedir/subdir/Foo.txt', | |
1004 u'basedir/subdir/Foo.txt', | |
1005 ] | |
1006 self.assertEqual(expected, actual) | |
1007 | |
1008 def test_process_input_path_case_simple(self): | |
1009 # Ensure the symlink dest is saved in the right path case. | |
1010 subdir = os.path.join(self.cwd, 'subdir') | |
1011 os.mkdir(subdir) | |
1012 linkdir = os.path.join(self.cwd, 'linkdir') | |
1013 os.symlink('subDir', linkdir) | |
1014 actual = isolate.process_input( | |
1015 unicode(linkdir.upper()), {}, True, 'mac', ALGO) | |
1016 expected = {'l': u'subdir', 'm': 360, 't': int(os.stat(linkdir).st_mtime)} | |
1017 self.assertEqual(expected, actual) | |
1018 | |
1019 def test_process_input_path_case_complex(self): | |
1020 # Ensure the symlink dest is saved in the right path case. This includes 2 | |
1021 # layers of symlinks. | |
1022 basedir = os.path.join(self.cwd, 'basebir') | |
1023 os.mkdir(basedir) | |
1024 | |
1025 linkeddir2 = os.path.join(self.cwd, 'linkeddir2') | |
1026 os.mkdir(linkeddir2) | |
1027 | |
1028 linkeddir1 = os.path.join(basedir, 'linkeddir1') | |
1029 os.symlink('../linkedDir2', linkeddir1) | |
1030 | |
1031 subsymlinkdir = os.path.join(basedir, 'symlinkdir') | |
1032 os.symlink('linkedDir1', subsymlinkdir) | |
1033 | |
1034 actual = isolate.process_input( | |
1035 unicode(subsymlinkdir.upper()), {}, True, 'mac', ALGO) | |
1036 expected = { | |
1037 'l': u'linkeddir1', 'm': 360, 't': int(os.stat(subsymlinkdir).st_mtime), | |
1038 } | |
1039 self.assertEqual(expected, actual) | |
1040 | |
1041 actual = isolate.process_input( | |
1042 unicode(linkeddir1.upper()), {}, True, 'mac', ALGO) | |
1043 expected = { | |
1044 'l': u'../linkeddir2', 'm': 360, 't': int(os.stat(linkeddir1).st_mtime), | |
1045 } | |
1046 self.assertEqual(expected, actual) | |
1047 | |
1048 if sys.platform != 'win32': | |
1049 def test_symlink_input_absolute_path(self): | |
1050 # A symlink is outside of the checkout, it should be treated as a normal | |
1051 # directory. | |
1052 # .../src | |
1053 # .../src/out -> .../tmp/foo | |
1054 # .../tmp | |
1055 # .../tmp/foo | |
1056 src = os.path.join(self.cwd, u'src') | |
1057 src_out = os.path.join(src, 'out') | |
1058 tmp = os.path.join(self.cwd, 'tmp') | |
1059 tmp_foo = os.path.join(tmp, 'foo') | |
1060 os.mkdir(src) | |
1061 os.mkdir(tmp) | |
1062 os.mkdir(tmp_foo) | |
1063 # The problem was that it's an absolute path, so it must be considered a | |
1064 # normal directory. | |
1065 os.symlink(tmp, src_out) | |
1066 open(os.path.join(tmp_foo, 'bar.txt'), 'w').close() | |
1067 actual = isolate.expand_symlinks(src, u'out/foo/bar.txt') | |
1068 self.assertEqual((u'out/foo/bar.txt', []), actual) | |
1069 | |
1070 | |
1071 class IsolateLoad(IsolateBase): | |
1072 def setUp(self): | |
1073 super(IsolateLoad, self).setUp() | |
1074 self.directory = tempfile.mkdtemp(prefix='isolate_') | |
1075 | |
1076 def tearDown(self): | |
1077 try: | |
1078 isolate.run_isolated.rmtree(self.directory) | |
1079 finally: | |
1080 super(IsolateLoad, self).tearDown() | |
1081 | |
1082 def _get_option(self, isolate_file): | |
1083 OS = isolate.get_flavor() | |
1084 chromeos_value = int(OS == 'linux') | |
1085 class Options(object): | |
1086 isolated = os.path.join(self.directory, 'foo.isolated') | |
1087 outdir = os.path.join(self.directory, 'outdir') | |
1088 isolate = isolate_file | |
1089 variables = {'foo': 'bar', 'OS': OS, 'chromeos': chromeos_value} | |
1090 ignore_broken_items = False | |
1091 return Options() | |
1092 | |
1093 def _cleanup_isolated(self, expected_isolated): | |
1094 """Modifies isolated to remove the non-deterministic parts.""" | |
1095 if sys.platform == 'win32': | |
1096 # 'm' are not saved in windows. | |
1097 for values in expected_isolated['files'].itervalues(): | |
1098 self.assertTrue(values.pop('m')) | |
1099 | |
1100 def _cleanup_saved_state(self, actual_saved_state): | |
1101 for item in actual_saved_state['files'].itervalues(): | |
1102 self.assertTrue(item.pop('t')) | |
1103 | |
1104 def test_load_stale_isolated(self): | |
1105 isolate_file = os.path.join( | |
1106 ROOT_DIR, 'tests', 'isolate', 'touch_root.isolate') | |
1107 | |
1108 # Data to be loaded in the .isolated file. Do not create a .state file. | |
1109 input_data = { | |
1110 'command': ['python'], | |
1111 'files': { | |
1112 'foo': { | |
1113 "m": 416, | |
1114 "h": "invalid", | |
1115 "s": 538, | |
1116 "t": 1335146921, | |
1117 }, | |
1118 os.path.join('tests', 'isolate', 'touch_root.py'): { | |
1119 "m": 488, | |
1120 "h": "invalid", | |
1121 "s": 538, | |
1122 "t": 1335146921, | |
1123 }, | |
1124 }, | |
1125 } | |
1126 options = self._get_option(isolate_file) | |
1127 isolate.trace_inputs.write_json(options.isolated, input_data, False) | |
1128 | |
1129 # A CompleteState object contains two parts: | |
1130 # - Result instance stored in complete_state.isolated, corresponding to the | |
1131 # .isolated file, is what is read by run_test_from_archive.py. | |
1132 # - SavedState instance stored in compelte_state.saved_state, | |
1133 # corresponding to the .state file, which is simply to aid the developer | |
1134 # when re-running the same command multiple times and contain | |
1135 # discardable information. | |
1136 complete_state = isolate.load_complete_state(options, self.cwd, None, False) | |
1137 actual_isolated = complete_state.saved_state.to_isolated() | |
1138 actual_saved_state = complete_state.saved_state.flatten() | |
1139 | |
1140 expected_isolated = { | |
1141 'algo': 'sha-1', | |
1142 'command': ['python', 'touch_root.py'], | |
1143 'files': { | |
1144 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1145 'm': 488, | |
1146 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1147 's': _size('tests', 'isolate', 'touch_root.py'), | |
1148 }, | |
1149 u'isolate.py': { | |
1150 'm': 488, | |
1151 'h': hash_file('isolate.py'), | |
1152 's': _size('isolate.py'), | |
1153 }, | |
1154 }, | |
1155 'os': isolate.get_flavor(), | |
1156 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1157 'version': '1.0', | |
1158 } | |
1159 self._cleanup_isolated(expected_isolated) | |
1160 self.assertEqual(expected_isolated, actual_isolated) | |
1161 | |
1162 expected_saved_state = { | |
1163 'algo': 'sha-1', | |
1164 'child_isolated_files': [], | |
1165 'command': ['python', 'touch_root.py'], | |
1166 'files': { | |
1167 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1168 'm': 488, | |
1169 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1170 's': _size('tests', 'isolate', 'touch_root.py'), | |
1171 }, | |
1172 u'isolate.py': { | |
1173 'm': 488, | |
1174 'h': hash_file('isolate.py'), | |
1175 's': _size('isolate.py'), | |
1176 }, | |
1177 }, | |
1178 'isolate_file': isolate.safe_relpath( | |
1179 file_path.get_native_path_case(isolate_file), | |
1180 os.path.dirname(options.isolated)), | |
1181 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1182 'variables': { | |
1183 'foo': 'bar', | |
1184 'OS': isolate.get_flavor(), | |
1185 'chromeos': options.variables['chromeos'], | |
1186 }, | |
1187 'version': '1.0', | |
1188 } | |
1189 self._cleanup_isolated(expected_saved_state) | |
1190 self._cleanup_saved_state(actual_saved_state) | |
1191 self.assertEqual(expected_saved_state, actual_saved_state) | |
1192 | |
1193 def test_subdir(self): | |
1194 # The resulting .isolated file will be missing ../../isolate.py. It is | |
1195 # because this file is outside the --subdir parameter. | |
1196 isolate_file = os.path.join( | |
1197 ROOT_DIR, 'tests', 'isolate', 'touch_root.isolate') | |
1198 options = self._get_option(isolate_file) | |
1199 chromeos_value = int(isolate.get_flavor() == 'linux') | |
1200 options.variables['chromeos'] = chromeos_value | |
1201 complete_state = isolate.load_complete_state( | |
1202 options, self.cwd, os.path.join('tests', 'isolate'), False) | |
1203 actual_isolated = complete_state.saved_state.to_isolated() | |
1204 actual_saved_state = complete_state.saved_state.flatten() | |
1205 | |
1206 expected_isolated = { | |
1207 'algo': 'sha-1', | |
1208 'command': ['python', 'touch_root.py'], | |
1209 'files': { | |
1210 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1211 'm': 488, | |
1212 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1213 's': _size('tests', 'isolate', 'touch_root.py'), | |
1214 }, | |
1215 }, | |
1216 'os': isolate.get_flavor(), | |
1217 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1218 'version': '1.0', | |
1219 } | |
1220 self._cleanup_isolated(expected_isolated) | |
1221 self.assertEqual(expected_isolated, actual_isolated) | |
1222 | |
1223 expected_saved_state = { | |
1224 'algo': 'sha-1', | |
1225 'child_isolated_files': [], | |
1226 'command': ['python', 'touch_root.py'], | |
1227 'files': { | |
1228 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1229 'm': 488, | |
1230 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1231 's': _size('tests', 'isolate', 'touch_root.py'), | |
1232 }, | |
1233 }, | |
1234 'isolate_file': isolate.safe_relpath( | |
1235 file_path.get_native_path_case(isolate_file), | |
1236 os.path.dirname(options.isolated)), | |
1237 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1238 'variables': { | |
1239 'foo': 'bar', | |
1240 'OS': isolate.get_flavor(), | |
1241 'chromeos': chromeos_value, | |
1242 }, | |
1243 'version': '1.0', | |
1244 } | |
1245 self._cleanup_isolated(expected_saved_state) | |
1246 self._cleanup_saved_state(actual_saved_state) | |
1247 self.assertEqual(expected_saved_state, actual_saved_state) | |
1248 | |
1249 def test_subdir_variable(self): | |
1250 # the resulting .isolated file will be missing ../../isolate.py. it is | |
1251 # because this file is outside the --subdir parameter. | |
1252 isolate_file = os.path.join( | |
1253 ROOT_DIR, 'tests', 'isolate', 'touch_root.isolate') | |
1254 options = self._get_option(isolate_file) | |
1255 chromeos_value = int(isolate.get_flavor() == 'linux') | |
1256 options.variables['chromeos'] = chromeos_value | |
1257 options.variables['BAZ'] = os.path.join('tests', 'isolate') | |
1258 complete_state = isolate.load_complete_state( | |
1259 options, self.cwd, '<(BAZ)', False) | |
1260 actual_isolated = complete_state.saved_state.to_isolated() | |
1261 actual_saved_state = complete_state.saved_state.flatten() | |
1262 | |
1263 expected_isolated = { | |
1264 'algo': 'sha-1', | |
1265 'command': ['python', 'touch_root.py'], | |
1266 'files': { | |
1267 os.path.join('tests', 'isolate', 'touch_root.py'): { | |
1268 'm': 488, | |
1269 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1270 's': _size('tests', 'isolate', 'touch_root.py'), | |
1271 }, | |
1272 }, | |
1273 'os': isolate.get_flavor(), | |
1274 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1275 'version': '1.0', | |
1276 } | |
1277 self._cleanup_isolated(expected_isolated) | |
1278 self.assertEqual(expected_isolated, actual_isolated) | |
1279 | |
1280 expected_saved_state = { | |
1281 'algo': 'sha-1', | |
1282 'child_isolated_files': [], | |
1283 'command': ['python', 'touch_root.py'], | |
1284 'files': { | |
1285 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1286 'm': 488, | |
1287 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1288 's': _size('tests', 'isolate', 'touch_root.py'), | |
1289 }, | |
1290 }, | |
1291 'isolate_file': isolate.safe_relpath( | |
1292 file_path.get_native_path_case(isolate_file), | |
1293 os.path.dirname(options.isolated)), | |
1294 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1295 'variables': { | |
1296 'foo': 'bar', | |
1297 'BAZ': os.path.join('tests', 'isolate'), | |
1298 'OS': isolate.get_flavor(), | |
1299 'chromeos': chromeos_value, | |
1300 }, | |
1301 'version': '1.0', | |
1302 } | |
1303 self._cleanup_isolated(expected_saved_state) | |
1304 self._cleanup_saved_state(actual_saved_state) | |
1305 self.assertEqual(expected_saved_state, actual_saved_state) | |
1306 | |
1307 def test_variable_not_exist(self): | |
1308 isolate_file = os.path.join( | |
1309 ROOT_DIR, 'tests', 'isolate', 'touch_root.isolate') | |
1310 options = self._get_option(isolate_file) | |
1311 options.variables['PRODUCT_DIR'] = os.path.join(u'tests', u'isolate') | |
1312 native_cwd = file_path.get_native_path_case(unicode(self.cwd)) | |
1313 try: | |
1314 isolate.load_complete_state(options, self.cwd, None, False) | |
1315 self.fail() | |
1316 except isolate.ExecutionError, e: | |
1317 self.assertEqual( | |
1318 'PRODUCT_DIR=%s is not a directory' % | |
1319 os.path.join(native_cwd, 'tests', 'isolate'), | |
1320 e.args[0]) | |
1321 | |
1322 def test_variable(self): | |
1323 isolate_file = os.path.join( | |
1324 ROOT_DIR, 'tests', 'isolate', 'touch_root.isolate') | |
1325 options = self._get_option(isolate_file) | |
1326 chromeos_value = int(isolate.get_flavor() == 'linux') | |
1327 options.variables['chromeos'] = chromeos_value | |
1328 options.variables['PRODUCT_DIR'] = os.path.join('tests', 'isolate') | |
1329 complete_state = isolate.load_complete_state(options, ROOT_DIR, None, False) | |
1330 actual_isolated = complete_state.saved_state.to_isolated() | |
1331 actual_saved_state = complete_state.saved_state.flatten() | |
1332 | |
1333 expected_isolated = { | |
1334 'algo': 'sha-1', | |
1335 'command': ['python', 'touch_root.py'], | |
1336 'files': { | |
1337 u'isolate.py': { | |
1338 'm': 488, | |
1339 'h': hash_file('isolate.py'), | |
1340 's': _size('isolate.py'), | |
1341 }, | |
1342 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1343 'm': 488, | |
1344 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1345 's': _size('tests', 'isolate', 'touch_root.py'), | |
1346 }, | |
1347 }, | |
1348 'os': isolate.get_flavor(), | |
1349 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1350 'version': '1.0', | |
1351 } | |
1352 self._cleanup_isolated(expected_isolated) | |
1353 self.assertEqual(expected_isolated, actual_isolated) | |
1354 | |
1355 expected_saved_state = { | |
1356 'algo': 'sha-1', | |
1357 'child_isolated_files': [], | |
1358 'command': ['python', 'touch_root.py'], | |
1359 'files': { | |
1360 u'isolate.py': { | |
1361 'm': 488, | |
1362 'h': hash_file('isolate.py'), | |
1363 's': _size('isolate.py'), | |
1364 }, | |
1365 os.path.join(u'tests', 'isolate', 'touch_root.py'): { | |
1366 'm': 488, | |
1367 'h': hash_file('tests', 'isolate', 'touch_root.py'), | |
1368 's': _size('tests', 'isolate', 'touch_root.py'), | |
1369 }, | |
1370 }, | |
1371 'isolate_file': isolate.safe_relpath( | |
1372 file_path.get_native_path_case(isolate_file), | |
1373 os.path.dirname(options.isolated)), | |
1374 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1375 'variables': { | |
1376 'foo': 'bar', | |
1377 'PRODUCT_DIR': '.', | |
1378 'OS': isolate.get_flavor(), | |
1379 'chromeos': chromeos_value, | |
1380 }, | |
1381 'version': '1.0', | |
1382 } | |
1383 self._cleanup_isolated(expected_saved_state) | |
1384 self._cleanup_saved_state(actual_saved_state) | |
1385 self.assertEqual(expected_saved_state, actual_saved_state) | |
1386 self.assertEqual([], os.listdir(self.directory)) | |
1387 | |
1388 def test_root_dir_because_of_variable(self): | |
1389 # Ensures that load_isolate() works even when path variables have deep root | |
1390 # dirs. The end result is similar to touch_root.isolate, except that | |
1391 # no_run.isolate doesn't reference '..' at all. | |
1392 # | |
1393 # A real world example would be PRODUCT_DIR=../../out/Release but nothing in | |
1394 # this directory is mapped. | |
1395 # | |
1396 # Imagine base/base_unittests.isolate would not map anything in | |
1397 # PRODUCT_DIR. In that case, the automatically determined root dir is | |
1398 # src/base, since nothing outside this directory is mapped. | |
1399 isolate_file = os.path.join( | |
1400 ROOT_DIR, 'tests', 'isolate', 'no_run.isolate') | |
1401 options = self._get_option(isolate_file) | |
1402 chromeos_value = int(isolate.get_flavor() == 'linux') | |
1403 # Any directory outside ROOT_DIR/tests/isolate. | |
1404 options.variables['PRODUCT_DIR'] = os.path.join('third_party') | |
1405 complete_state = isolate.load_complete_state(options, ROOT_DIR, None, False) | |
1406 actual_isolated = complete_state.saved_state.to_isolated() | |
1407 actual_saved_state = complete_state.saved_state.flatten() | |
1408 | |
1409 expected_isolated = { | |
1410 'algo': 'sha-1', | |
1411 'files': { | |
1412 os.path.join(u'tests', 'isolate', 'files1', 'subdir', '42.txt'): { | |
1413 'm': 416, | |
1414 'h': hash_file('tests', 'isolate', 'files1', 'subdir', '42.txt'), | |
1415 's': _size('tests', 'isolate', 'files1', 'subdir', '42.txt'), | |
1416 }, | |
1417 os.path.join(u'tests', 'isolate', 'files1', 'test_file1.txt'): { | |
1418 'm': 416, | |
1419 'h': hash_file('tests', 'isolate', 'files1', 'test_file1.txt'), | |
1420 's': _size('tests', 'isolate', 'files1', 'test_file1.txt'), | |
1421 }, | |
1422 os.path.join(u'tests', 'isolate', 'files1', 'test_file2.txt'): { | |
1423 'm': 416, | |
1424 'h': hash_file('tests', 'isolate', 'files1', 'test_file2.txt'), | |
1425 's': _size('tests', 'isolate', 'files1', 'test_file2.txt'), | |
1426 }, | |
1427 os.path.join(u'tests', 'isolate', 'no_run.isolate'): { | |
1428 'm': 416, | |
1429 'h': hash_file('tests', 'isolate', 'no_run.isolate'), | |
1430 's': _size('tests', 'isolate', 'no_run.isolate'), | |
1431 }, | |
1432 }, | |
1433 'os': isolate.get_flavor(), | |
1434 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1435 'version': '1.0', | |
1436 } | |
1437 self._cleanup_isolated(expected_isolated) | |
1438 self.assertEqual(expected_isolated, actual_isolated) | |
1439 | |
1440 expected_saved_state = { | |
1441 'algo': 'sha-1', | |
1442 'child_isolated_files': [], | |
1443 'command': [], | |
1444 'files': { | |
1445 os.path.join(u'tests', 'isolate', 'files1', 'subdir', '42.txt'): { | |
1446 'm': 416, | |
1447 'h': hash_file('tests', 'isolate', 'files1', 'subdir', '42.txt'), | |
1448 's': _size('tests', 'isolate', 'files1', 'subdir', '42.txt'), | |
1449 }, | |
1450 os.path.join(u'tests', 'isolate', 'files1', 'test_file1.txt'): { | |
1451 'm': 416, | |
1452 'h': hash_file('tests', 'isolate', 'files1', 'test_file1.txt'), | |
1453 's': _size('tests', 'isolate', 'files1', 'test_file1.txt'), | |
1454 }, | |
1455 os.path.join(u'tests', 'isolate', 'files1', 'test_file2.txt'): { | |
1456 'm': 416, | |
1457 'h': hash_file('tests', 'isolate', 'files1', 'test_file2.txt'), | |
1458 's': _size('tests', 'isolate', 'files1', 'test_file2.txt'), | |
1459 }, | |
1460 os.path.join(u'tests', 'isolate', 'no_run.isolate'): { | |
1461 'm': 416, | |
1462 'h': hash_file('tests', 'isolate', 'no_run.isolate'), | |
1463 's': _size('tests', 'isolate', 'no_run.isolate'), | |
1464 }, | |
1465 }, | |
1466 'isolate_file': isolate.safe_relpath( | |
1467 file_path.get_native_path_case(isolate_file), | |
1468 os.path.dirname(options.isolated)), | |
1469 'relative_cwd': os.path.join(u'tests', 'isolate'), | |
1470 'variables': { | |
1471 'foo': 'bar', | |
1472 'PRODUCT_DIR': os.path.join(u'..', '..', 'third_party'), | |
1473 'OS': isolate.get_flavor(), | |
1474 'chromeos': chromeos_value, | |
1475 }, | |
1476 'version': '1.0', | |
1477 } | |
1478 self._cleanup_isolated(expected_saved_state) | |
1479 self._cleanup_saved_state(actual_saved_state) | |
1480 self.assertEqual(expected_saved_state, actual_saved_state) | |
1481 self.assertEqual([], os.listdir(self.directory)) | |
1482 | |
1483 def test_chromium_split(self): | |
1484 # Create an .isolate file and a tree of random stuff. | |
1485 isolate_file = os.path.join( | |
1486 ROOT_DIR, 'tests', 'isolate', 'split.isolate') | |
1487 options = self._get_option(isolate_file) | |
1488 options.variables = { | |
1489 'OS': isolate.get_flavor(), | |
1490 'DEPTH': '.', | |
1491 'PRODUCT_DIR': os.path.join('files1'), | |
1492 } | |
1493 complete_state = isolate.load_complete_state( | |
1494 options, os.path.join(ROOT_DIR, 'tests', 'isolate'), None, False) | |
1495 # By saving the files, it forces splitting the data up. | |
1496 complete_state.save_files() | |
1497 | |
1498 actual_isolated_master = isolate.trace_inputs.read_json( | |
1499 os.path.join(self.directory, 'foo.isolated')) | |
1500 expected_isolated_master = { | |
1501 u'algo': u'sha-1', | |
1502 u'command': [u'python', u'split.py'], | |
1503 u'files': { | |
1504 u'split.py': { | |
1505 u'm': 488, | |
1506 u'h': unicode(hash_file('tests', 'isolate', 'split.py')), | |
1507 u's': _size('tests', 'isolate', 'split.py'), | |
1508 }, | |
1509 }, | |
1510 u'includes': [ | |
1511 unicode(hash_file(os.path.join(self.directory, 'foo.0.isolated'))), | |
1512 unicode(hash_file(os.path.join(self.directory, 'foo.1.isolated'))), | |
1513 ], | |
1514 u'os': unicode(isolate.get_flavor()), | |
1515 u'relative_cwd': u'.', | |
1516 u'version': u'1.0', | |
1517 } | |
1518 self._cleanup_isolated(expected_isolated_master) | |
1519 self.assertEqual(expected_isolated_master, actual_isolated_master) | |
1520 | |
1521 actual_isolated_0 = isolate.trace_inputs.read_json( | |
1522 os.path.join(self.directory, 'foo.0.isolated')) | |
1523 expected_isolated_0 = { | |
1524 u'algo': u'sha-1', | |
1525 u'files': { | |
1526 os.path.join(u'test', 'data', 'foo.txt'): { | |
1527 u'm': 416, | |
1528 u'h': unicode( | |
1529 hash_file('tests', 'isolate', 'test', 'data', 'foo.txt')), | |
1530 u's': _size('tests', 'isolate', 'test', 'data', 'foo.txt'), | |
1531 }, | |
1532 }, | |
1533 u'os': unicode(isolate.get_flavor()), | |
1534 u'version': u'1.0', | |
1535 } | |
1536 self._cleanup_isolated(expected_isolated_0) | |
1537 self.assertEqual(expected_isolated_0, actual_isolated_0) | |
1538 | |
1539 actual_isolated_1 = isolate.trace_inputs.read_json( | |
1540 os.path.join(self.directory, 'foo.1.isolated')) | |
1541 expected_isolated_1 = { | |
1542 u'algo': u'sha-1', | |
1543 u'files': { | |
1544 os.path.join(u'files1', 'subdir', '42.txt'): { | |
1545 u'm': 416, | |
1546 u'h': unicode( | |
1547 hash_file('tests', 'isolate', 'files1', 'subdir', '42.txt')), | |
1548 u's': _size('tests', 'isolate', 'files1', 'subdir', '42.txt'), | |
1549 }, | |
1550 }, | |
1551 u'os': unicode(isolate.get_flavor()), | |
1552 u'version': u'1.0', | |
1553 } | |
1554 self._cleanup_isolated(expected_isolated_1) | |
1555 self.assertEqual(expected_isolated_1, actual_isolated_1) | |
1556 | |
1557 actual_saved_state = isolate.trace_inputs.read_json( | |
1558 isolate.isolatedfile_to_state(options.isolated)) | |
1559 isolated_base = unicode(os.path.basename(options.isolated)) | |
1560 expected_saved_state = { | |
1561 u'algo': u'sha-1', | |
1562 u'child_isolated_files': [ | |
1563 isolated_base[:-len('.isolated')] + '.0.isolated', | |
1564 isolated_base[:-len('.isolated')] + '.1.isolated', | |
1565 ], | |
1566 u'command': [u'python', u'split.py'], | |
1567 u'files': { | |
1568 os.path.join(u'files1', 'subdir', '42.txt'): { | |
1569 u'm': 416, | |
1570 u'h': unicode( | |
1571 hash_file('tests', 'isolate', 'files1', 'subdir', '42.txt')), | |
1572 u's': _size('tests', 'isolate', 'files1', 'subdir', '42.txt'), | |
1573 }, | |
1574 u'split.py': { | |
1575 u'm': 488, | |
1576 u'h': unicode(hash_file('tests', 'isolate', 'split.py')), | |
1577 u's': _size('tests', 'isolate', 'split.py'), | |
1578 }, | |
1579 os.path.join(u'test', 'data', 'foo.txt'): { | |
1580 u'm': 416, | |
1581 u'h': unicode( | |
1582 hash_file('tests', 'isolate', 'test', 'data', 'foo.txt')), | |
1583 u's': _size('tests', 'isolate', 'test', 'data', 'foo.txt'), | |
1584 }, | |
1585 }, | |
1586 u'isolate_file': isolate.safe_relpath( | |
1587 file_path.get_native_path_case(isolate_file), | |
1588 unicode(os.path.dirname(options.isolated))), | |
1589 u'relative_cwd': u'.', | |
1590 u'variables': { | |
1591 u'OS': unicode(isolate.get_flavor()), | |
1592 u'DEPTH': u'.', | |
1593 u'PRODUCT_DIR': u'files1', | |
1594 }, | |
1595 u'version': u'1.0', | |
1596 } | |
1597 self._cleanup_isolated(expected_saved_state) | |
1598 self._cleanup_saved_state(actual_saved_state) | |
1599 self.assertEqual(expected_saved_state, actual_saved_state) | |
1600 self.assertEqual( | |
1601 [ | |
1602 'foo.0.isolated', 'foo.1.isolated', | |
1603 'foo.isolated', 'foo.isolated.state', | |
1604 ], | |
1605 sorted(os.listdir(self.directory))) | |
1606 | |
1607 | |
1608 class IsolateCommand(IsolateBase): | |
1609 def load_complete_state(self, *_): | |
1610 """Creates a minimalist CompleteState instance without an .isolated | |
1611 reference. | |
1612 """ | |
1613 out = isolate.CompleteState(None, isolate.SavedState(self.cwd)) | |
1614 out.saved_state.isolate_file = u'blah.isolate' | |
1615 out.saved_state.relative_cwd = u'' | |
1616 return out | |
1617 | |
1618 def test_CMDrewrite(self): | |
1619 isolate_file = os.path.join(self.cwd, 'x.isolate') | |
1620 data = ( | |
1621 '# Foo', | |
1622 '{', | |
1623 '}', | |
1624 ) | |
1625 with open(isolate_file, 'wb') as f: | |
1626 f.write('\n'.join(data)) | |
1627 | |
1628 self.mock(sys, 'stdout', cStringIO.StringIO()) | |
1629 cmd = ['-i', isolate_file] | |
1630 self.assertEqual(0, isolate.CMDrewrite(isolate.OptionParserIsolate(), cmd)) | |
1631 with open(isolate_file, 'rb') as f: | |
1632 actual = f.read() | |
1633 | |
1634 expected = "# Foo\n{\n 'conditions': [\n ],\n}\n" | |
1635 self.assertEqual(expected, actual) | |
1636 | |
1637 if sys.platform != 'win32': | |
1638 def test_CMDcheck_no_mode_on_windows(self): | |
1639 # Store for Windows, make sure file mode are not included. Hopefully, run | |
1640 # this test on another OS. | |
1641 isolate_file = os.path.join( | |
1642 ROOT_DIR, 'tests', 'isolate', 'symlink_full.isolate') | |
1643 isolated_file = os.path.join(self.cwd, 'foo.isolated') | |
1644 cmd = [ | |
1645 '-i', isolate_file, | |
1646 '-V', 'OS', 'win', | |
1647 '-V', 'chromeos', '0', | |
1648 '-s', isolated_file, | |
1649 ] | |
1650 self.assertEqual(0, isolate.CMDcheck(isolate.OptionParserIsolate(), cmd)) | |
1651 with open(isolated_file, 'rb') as f: | |
1652 actual = json.load(f) | |
1653 mapped = [ | |
1654 os.path.join(u'files2', 'subdir', '42.txt'), | |
1655 os.path.join(u'files2', 'test_file1.txt'), | |
1656 os.path.join(u'files2', 'test_file2.txt'), | |
1657 os.path.join(u'symlink_full.py'), | |
1658 ] | |
1659 files = dict( | |
1660 ( | |
1661 f, | |
1662 { | |
1663 u'h': unicode(hash_file('tests', 'isolate', f)), | |
1664 u's': _size('tests', 'isolate', f), | |
1665 } | |
1666 ) | |
1667 for f in mapped) | |
1668 expected = { | |
1669 u'algo': u'sha-1', | |
1670 u'command': [u'python', u'symlink_full.py'], | |
1671 u'files': files, | |
1672 u'os': u'win', | |
1673 u'relative_cwd': u'.', | |
1674 u'version': u'1.0', | |
1675 } | |
1676 self.assertEqual(expected, actual) | |
1677 | |
1678 def test_CMDrun_extra_args(self): | |
1679 cmd = [ | |
1680 'run', | |
1681 '--isolate', 'blah.isolate', | |
1682 '--outdir', os.path.join(self.cwd, 'jumbo'), | |
1683 '--', 'extra_args', | |
1684 ] | |
1685 self.mock(isolate, 'load_complete_state', self.load_complete_state) | |
1686 self.mock(isolate.subprocess, 'call', lambda *_, **_kwargs: 0) | |
1687 self.assertEqual(0, isolate.CMDrun(isolate.OptionParserIsolate(), cmd)) | |
1688 | |
1689 | |
1690 if __name__ == '__main__': | |
1691 logging.basicConfig( | |
1692 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR, | |
1693 format='%(levelname)5s %(filename)15s(%(lineno)3d): %(message)s') | |
1694 if '-v' in sys.argv: | |
1695 unittest.TestCase.maxDiff = None | |
1696 unittest.main() | |
OLD | NEW |