OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 import cStringIO | 6 import cStringIO |
7 import hashlib | 7 import hashlib |
8 import json | 8 import json |
9 import logging | 9 import logging |
10 import os | 10 import os |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 super(CalledProcessError, self).__init__(returncode, cmd) | 58 super(CalledProcessError, self).__init__(returncode, cmd) |
59 self.output = output | 59 self.output = output |
60 self.cwd = cwd | 60 self.cwd = cwd |
61 | 61 |
62 def __str__(self): | 62 def __str__(self): |
63 return super(CalledProcessError, self).__str__() + ( | 63 return super(CalledProcessError, self).__str__() + ( |
64 '\n' | 64 '\n' |
65 'cwd=%s\n%s') % (self.cwd, self.output) | 65 'cwd=%s\n%s') % (self.cwd, self.output) |
66 | 66 |
67 | 67 |
| 68 def list_files_tree(directory): |
| 69 """Returns the list of all the files in a tree.""" |
| 70 actual = [] |
| 71 for root, _dirs, files in os.walk(directory): |
| 72 actual.extend(os.path.join(root, f)[len(directory)+1:] for f in files) |
| 73 return sorted(actual) |
| 74 |
| 75 |
68 class IsolateBase(unittest.TestCase): | 76 class IsolateBase(unittest.TestCase): |
69 # To be defined by the subclass, it defines the amount of meta data saved by | 77 # To be defined by the subclass, it defines the amount of meta data saved by |
70 # isolate.py for each file. Should be one of (NO_INFO, STATS_ONLY, WITH_HASH). | 78 # isolate.py for each file. Should be one of (NO_INFO, STATS_ONLY, WITH_HASH). |
71 LEVEL = None | 79 LEVEL = None |
72 | 80 |
73 def setUp(self): | 81 def setUp(self): |
74 # The tests assume the current directory is the file's directory. | 82 # The tests assume the current directory is the file's directory. |
75 os.chdir(ROOT_DIR) | 83 os.chdir(ROOT_DIR) |
76 self.tempdir = tempfile.mkdtemp() | 84 self.tempdir = tempfile.mkdtemp() |
77 self.result = os.path.join(self.tempdir, 'isolate_smoke_test.result') | 85 self.result = os.path.join(self.tempdir, 'isolate_smoke_test.results') |
78 self.outdir = os.path.join(self.tempdir, 'isolated') | 86 self.outdir = os.path.join(self.tempdir, 'isolated') |
79 self.maxDiff = None | |
80 | 87 |
81 def tearDown(self): | 88 def tearDown(self): |
82 shutil.rmtree(self.tempdir) | 89 shutil.rmtree(self.tempdir) |
83 | 90 |
84 def _expect_no_tree(self): | 91 def _expect_no_tree(self): |
85 self.assertFalse(os.path.exists(self.outdir)) | 92 self.assertFalse(os.path.exists(self.outdir)) |
86 | 93 |
87 def _result_tree(self): | 94 def _result_tree(self): |
88 actual = [] | 95 return list_files_tree(self.outdir) |
89 for root, _dirs, files in os.walk(self.outdir): | |
90 actual.extend(os.path.join(root, f)[len(self.outdir)+1:] for f in files) | |
91 return sorted(actual) | |
92 | 96 |
93 def _expected_tree(self): | 97 def _expected_tree(self): |
94 """Verifies the files written in the temporary directory.""" | 98 """Verifies the files written in the temporary directory.""" |
95 self.assertEquals(sorted(DEPENDENCIES[self.case()]), self._result_tree()) | 99 self.assertEquals(sorted(DEPENDENCIES[self.case()]), self._result_tree()) |
96 | 100 |
97 @staticmethod | 101 @staticmethod |
98 def _fix_file_mode(filename, read_only): | 102 def _fix_file_mode(filename, read_only): |
99 """4 modes are supported, 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r).""" | 103 """4 modes are supported, 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r).""" |
100 min_mode = 0444 | 104 min_mode = 0444 |
101 if not read_only: | 105 if not read_only: |
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 return buf.getvalue() | 463 return buf.getvalue() |
460 | 464 |
461 def test_fail(self): | 465 def test_fail(self): |
462 try: | 466 try: |
463 self._execute('trace', 'fail.isolate', ['-v'], True) | 467 self._execute('trace', 'fail.isolate', ['-v'], True) |
464 self.fail() | 468 self.fail() |
465 except subprocess.CalledProcessError, e: | 469 except subprocess.CalledProcessError, e: |
466 out = e.output | 470 out = e.output |
467 self._expect_no_tree() | 471 self._expect_no_tree() |
468 self._expect_results(['fail.py'], None, None) | 472 self._expect_results(['fail.py'], None, None) |
469 # In theory, there should be 2 \n at the end of expected but for an | |
470 # unknown reason there's 3 \n on Windows so just rstrip() and compare the | |
471 # text, that's sufficient for this test. | |
472 expected = 'Failing' | 473 expected = 'Failing' |
473 self.assertEquals(expected, out.rstrip()) | 474 if sys.platform == 'win32': |
| 475 # Includes spew from tracerpt.exe. |
| 476 self.assertTrue(out.startswith(expected)) |
| 477 else: |
| 478 self.assertEquals(expected, out.rstrip()) |
474 | 479 |
475 def test_missing_trailing_slash(self): | 480 def test_missing_trailing_slash(self): |
476 try: | 481 try: |
477 self._execute('trace', 'missing_trailing_slash.isolate', [], True) | 482 self._execute('trace', 'missing_trailing_slash.isolate', [], True) |
478 self.fail() | 483 self.fail() |
479 except subprocess.CalledProcessError, e: | 484 except subprocess.CalledProcessError, e: |
480 out = e.output | 485 out = e.output |
481 self._expect_no_tree() | 486 self._expect_no_tree() |
482 self._expect_no_result() | 487 self._expect_no_result() |
483 expected = ( | 488 expected = ( |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 # Note that .isolate format mandates / and not os.path.sep. | 552 # Note that .isolate format mandates / and not os.path.sep. |
548 'files1/', | 553 'files1/', |
549 ], | 554 ], |
550 }, | 555 }, |
551 }], | 556 }], |
552 ], | 557 ], |
553 } | 558 } |
554 self.assertEquals(self._to_string(expected), out) | 559 self.assertEquals(self._to_string(expected), out) |
555 | 560 |
556 | 561 |
| 562 class IsolateNoOutdir(IsolateBase): |
| 563 # Test without the --outdir flag. |
| 564 # So all the files are first copied in the tempdir and the test is run from |
| 565 # there. |
| 566 def setUp(self): |
| 567 super(IsolateNoOutdir, self).setUp() |
| 568 self.root = os.path.join(self.tempdir, 'root') |
| 569 os.makedirs(os.path.join(self.root, 'data', 'isolate')) |
| 570 for i in ('touch_root.isolate', 'touch_root.py'): |
| 571 shutil.copy( |
| 572 os.path.join(ROOT_DIR, 'data', 'isolate', i), |
| 573 os.path.join(self.root, 'data', 'isolate', i)) |
| 574 shutil.copy( |
| 575 os.path.join(ROOT_DIR, 'isolate.py'), |
| 576 os.path.join(self.root, 'isolate.py')) |
| 577 |
| 578 def _execute(self, mode, case, args, need_output): |
| 579 """Executes isolate.py.""" |
| 580 self.assertEquals( |
| 581 mode, self.mode(), 'Rename the test fixture to Isolate_%s' % mode) |
| 582 self.assertEquals( |
| 583 case, |
| 584 self.case() + '.isolate', |
| 585 'Rename the test case to test_%s()' % case) |
| 586 cmd = [ |
| 587 sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), |
| 588 '--result', self.result, |
| 589 self.filename(), |
| 590 '--mode', self.mode(), |
| 591 ] |
| 592 cmd.extend(args) |
| 593 |
| 594 env = os.environ.copy() |
| 595 if 'ISOLATE_DEBUG' in env: |
| 596 del env['ISOLATE_DEBUG'] |
| 597 |
| 598 if need_output or not VERBOSE: |
| 599 stdout = subprocess.PIPE |
| 600 stderr = subprocess.STDOUT |
| 601 else: |
| 602 cmd.extend(['-v'] * 3) |
| 603 stdout = None |
| 604 stderr = None |
| 605 |
| 606 cwd = self.tempdir |
| 607 p = subprocess.Popen( |
| 608 cmd, |
| 609 stdout=stdout, |
| 610 stderr=stderr, |
| 611 cwd=cwd, |
| 612 env=env, |
| 613 universal_newlines=True) |
| 614 out = p.communicate()[0] |
| 615 if p.returncode: |
| 616 raise CalledProcessError(p.returncode, cmd, out, cwd) |
| 617 return out |
| 618 |
| 619 def mode(self): |
| 620 """Returns the execution mode corresponding to this test case.""" |
| 621 test_id = self.id().split('.') |
| 622 self.assertEquals(3, len(test_id)) |
| 623 self.assertEquals('__main__', test_id[0]) |
| 624 return re.match('^test_([a-z]+)$', test_id[2]).group(1) |
| 625 |
| 626 def case(self): |
| 627 """Returns the filename corresponding to this test case.""" |
| 628 return 'touch_root' |
| 629 |
| 630 def filename(self): |
| 631 """Returns the filename corresponding to this test case.""" |
| 632 filename = os.path.join( |
| 633 self.root, 'data', 'isolate', self.case() + '.isolate') |
| 634 self.assertTrue(os.path.isfile(filename), filename) |
| 635 return filename |
| 636 |
| 637 def test_check(self): |
| 638 self._execute('check', 'touch_root.isolate', [], False) |
| 639 files = [ |
| 640 'isolate_smoke_test.results', |
| 641 'isolate_smoke_test.state', |
| 642 os.path.join('root', 'data', 'isolate', 'touch_root.isolate'), |
| 643 os.path.join('root', 'data', 'isolate', 'touch_root.py'), |
| 644 os.path.join('root', 'isolate.py'), |
| 645 ] |
| 646 self.assertEquals(files, list_files_tree(self.tempdir)) |
| 647 |
| 648 def test_hashtable(self): |
| 649 self._execute('hashtable', 'touch_root.isolate', [], False) |
| 650 files = [ |
| 651 os.path.join('hashtable', '99a015fd7df97416caf25576df502a70a3f32078'), |
| 652 os.path.join('hashtable', 'ddcd30d62a6df9964a43541b14536ddaeafc8598'), |
| 653 'isolate_smoke_test.results', |
| 654 'isolate_smoke_test.state', |
| 655 os.path.join('root', 'data', 'isolate', 'touch_root.isolate'), |
| 656 os.path.join('root', 'data', 'isolate', 'touch_root.py'), |
| 657 os.path.join('root', 'isolate.py'), |
| 658 ] |
| 659 self.assertEquals(files, list_files_tree(self.tempdir)) |
| 660 |
| 661 def test_remap(self): |
| 662 self._execute('remap', 'touch_root.isolate', [], False) |
| 663 files = [ |
| 664 'isolate_smoke_test.results', |
| 665 'isolate_smoke_test.state', |
| 666 os.path.join('root', 'data', 'isolate', 'touch_root.isolate'), |
| 667 os.path.join('root', 'data', 'isolate', 'touch_root.py'), |
| 668 os.path.join('root', 'isolate.py'), |
| 669 ] |
| 670 self.assertEquals(files, list_files_tree(self.tempdir)) |
| 671 |
| 672 def test_run(self): |
| 673 self._execute('run', 'touch_root.isolate', [], False) |
| 674 files = [ |
| 675 'isolate_smoke_test.results', |
| 676 'isolate_smoke_test.state', |
| 677 os.path.join('root', 'data', 'isolate', 'touch_root.isolate'), |
| 678 os.path.join('root', 'data', 'isolate', 'touch_root.py'), |
| 679 os.path.join('root', 'isolate.py'), |
| 680 ] |
| 681 self.assertEquals(files, list_files_tree(self.tempdir)) |
| 682 |
| 683 def test_trace(self): |
| 684 self._execute('trace', 'touch_root.isolate', [], False) |
| 685 files = [ |
| 686 'isolate_smoke_test.results', |
| 687 'isolate_smoke_test.state', |
| 688 os.path.join('root', 'data', 'isolate', 'touch_root.isolate'), |
| 689 os.path.join('root', 'data', 'isolate', 'touch_root.py'), |
| 690 os.path.join('root', 'isolate.py'), |
| 691 ] |
| 692 # Clean the directory from the logs, which are OS-specific. |
| 693 isolate.trace_inputs.get_api().clean_trace( |
| 694 os.path.join(self.tempdir, 'isolate_smoke_test.results.log')) |
| 695 self.assertEquals(files, list_files_tree(self.tempdir)) |
| 696 |
557 | 697 |
558 if __name__ == '__main__': | 698 if __name__ == '__main__': |
559 VERBOSE = '-v' in sys.argv | 699 VERBOSE = '-v' in sys.argv |
560 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) | 700 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) |
561 unittest.main() | 701 unittest.main() |
OLD | NEW |