| 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 logging | 6 import logging |
| 7 import os | 7 import os |
| 8 import shutil | 8 import shutil |
| 9 import subprocess | 9 import subprocess |
| 10 import sys | 10 import sys |
| 11 import tempfile | 11 import tempfile |
| 12 import unittest | 12 import unittest |
| 13 | 13 |
| 14 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) | 14 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 15 | 15 |
| 16 VERBOSE = False | 16 VERBOSE = False |
| 17 | 17 |
| 18 | 18 |
| 19 class CalledProcessError(subprocess.CalledProcessError): | 19 class CalledProcessError(subprocess.CalledProcessError): |
| 20 """Makes 2.6 version act like 2.7""" | 20 """Makes 2.6 version act like 2.7""" |
| 21 def __init__(self, returncode, cmd, output): | 21 def __init__(self, returncode, cmd, output, cwd): |
| 22 super(CalledProcessError, self).__init__(returncode, cmd) | 22 super(CalledProcessError, self).__init__(returncode, cmd) |
| 23 self.output = output | 23 self.output = output |
| 24 self.cwd = cwd |
| 25 |
| 26 def __str__(self): |
| 27 return super(CalledProcessError, self).__str__() + ( |
| 28 '\n' |
| 29 'cwd=%s\n%s') % (self.cwd, self.output) |
| 24 | 30 |
| 25 | 31 |
| 26 class TraceInputs(unittest.TestCase): | 32 class TraceInputs(unittest.TestCase): |
| 27 def setUp(self): | 33 def setUp(self): |
| 28 self.tempdir = tempfile.mkdtemp() | 34 self.tempdir = tempfile.mkdtemp() |
| 29 self.log = os.path.join(self.tempdir, 'log') | 35 self.log = os.path.join(self.tempdir, 'log') |
| 30 | 36 |
| 31 def tearDown(self): | 37 def tearDown(self): |
| 32 shutil.rmtree(self.tempdir) | 38 shutil.rmtree(self.tempdir) |
| 33 | 39 |
| 34 def _execute(self, args): | 40 def _execute(self, args): |
| 35 cmd = [ | 41 cmd = [ |
| 36 sys.executable, os.path.join(ROOT_DIR, 'trace_inputs.py'), | 42 sys.executable, os.path.join(ROOT_DIR, 'trace_inputs.py'), |
| 37 '--log', self.log, | 43 '--log', self.log, |
| 38 '--gyp', os.path.join('data', 'trace_inputs'), | 44 '--root-dir', ROOT_DIR, |
| 39 '--product', '.', # Not tested. | |
| 40 '--root-dir', ROOT_DIR, | |
| 41 ] + args | 45 ] + args |
| 42 p = subprocess.Popen( | 46 p = subprocess.Popen( |
| 43 cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=ROOT_DIR) | 47 cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=ROOT_DIR) |
| 44 out = p.communicate()[0] | 48 out = p.communicate()[0] |
| 45 if p.returncode: | 49 if p.returncode: |
| 46 raise CalledProcessError(p.returncode, cmd, out) | 50 raise CalledProcessError(p.returncode, cmd, out, ROOT_DIR) |
| 47 return out | 51 return out |
| 48 | 52 |
| 53 @staticmethod |
| 54 def _gyp(): |
| 55 return [ |
| 56 '--gyp', os.path.join('data', 'trace_inputs'), |
| 57 '--product', '.', # Not tested. |
| 58 ] |
| 59 |
| 49 def test_trace(self): | 60 def test_trace(self): |
| 50 if sys.platform == 'linux2': | 61 if sys.platform == 'linux2': |
| 51 return self._test_trace_linux() | 62 return self._test_trace_linux() |
| 52 if sys.platform == 'darwin': | 63 if sys.platform == 'darwin': |
| 53 return self._test_trace_mac() | 64 return self._test_trace_mac() |
| 54 print 'Unsupported: %s' % sys.platform | 65 print 'Unsupported: %s' % sys.platform |
| 55 | 66 |
| 67 def test_trace_gyp(self): |
| 68 if sys.platform == 'linux2': |
| 69 return self._test_trace_gyp_linux() |
| 70 if sys.platform == 'darwin': |
| 71 return self._test_trace_gyp_mac() |
| 72 print 'Unsupported: %s' % sys.platform |
| 73 |
| 56 def _test_trace_linux(self): | 74 def _test_trace_linux(self): |
| 57 # TODO(maruel): BUG: Note that child.py is missing. | 75 expected_end = [ |
| 76 "Interesting: 4 reduced to 3", |
| 77 " data/trace_inputs/", |
| 78 " trace_inputs.py", |
| 79 " trace_inputs_test.py", |
| 80 ] |
| 81 actual = self._execute(['trace_inputs_test.py', '--child1']).splitlines() |
| 82 self.assertTrue(actual[0].startswith('Tracing... [')) |
| 83 self.assertTrue(actual[1].startswith('Loading traces... ')) |
| 84 self.assertTrue(actual[2].startswith('Total: ')) |
| 85 self.assertEquals("Non existent: 0", actual[3]) |
| 86 # Ignore any Unexpected part. |
| 87 # TODO(maruel): Make sure there is no Unexpected part, even in the case of |
| 88 # virtualenv usage. |
| 89 self.assertEquals(expected_end, actual[-len(expected_end):]) |
| 90 |
| 91 def _test_trace_gyp_linux(self): |
| 58 expected = ( | 92 expected = ( |
| 59 "{\n" | 93 "{\n" |
| 60 " 'variables': {\n" | 94 " 'variables': {\n" |
| 61 " 'isolate_files': [\n" | 95 " 'isolate_files': [\n" |
| 62 " '<(DEPTH)/trace_inputs.py',\n" | 96 " '<(DEPTH)/trace_inputs.py',\n" |
| 63 " '<(DEPTH)/trace_inputs_test.py',\n" | 97 " '<(DEPTH)/trace_inputs_test.py',\n" |
| 64 " ],\n" | 98 " ],\n" |
| 65 " 'isolate_dirs': [\n" | 99 " 'isolate_dirs': [\n" |
| 100 " './',\n" |
| 66 " ],\n" | 101 " ],\n" |
| 67 " },\n" | 102 " },\n" |
| 68 "},\n") | 103 "},\n") |
| 69 gyp = self._execute(['trace_inputs_test.py', '--child1']) | 104 actual = self._execute(self._gyp() + ['trace_inputs_test.py', '--child1']) |
| 70 self.assertEquals(expected, gyp) | 105 self.assertEquals(expected, actual) |
| 71 | 106 |
| 72 def _test_trace_mac(self): | 107 def _test_trace_mac(self): |
| 73 # It is annoying in the case of dtrace because it requires root access. | 108 # It is annoying in the case of dtrace because it requires root access. |
| 74 # TODO(maruel): BUG: Note that child.py is missing. | 109 # TODO(maruel): BUG: Note that child.py is missing. |
| 75 expected = ( | 110 expected = ( |
| 111 "Total: 2\n" |
| 112 "Non existent: 0\n" |
| 113 "Interesting: 2 reduced to 2\n" |
| 114 " trace_inputs.py\n" |
| 115 " trace_inputs_test.py\n") |
| 116 actual = self._execute( |
| 117 ['trace_inputs_test.py', '--child1']).splitlines(True) |
| 118 self.assertTrue(actual[0].startswith('Tracing... [')) |
| 119 self.assertTrue(actual[1].startswith('Loading traces... ')) |
| 120 self.assertEquals(expected, ''.join(actual[2:])) |
| 121 |
| 122 def _test_trace_gyp_mac(self): |
| 123 # It is annoying in the case of dtrace because it requires root access. |
| 124 # TODO(maruel): BUG: Note that child.py is missing. |
| 125 expected = ( |
| 76 "{\n" | 126 "{\n" |
| 77 " 'variables': {\n" | 127 " 'variables': {\n" |
| 78 " 'isolate_files': [\n" | 128 " 'isolate_files': [\n" |
| 79 " '<(DEPTH)/trace_inputs.py',\n" | 129 " '<(DEPTH)/trace_inputs.py',\n" |
| 80 " '<(DEPTH)/trace_inputs_test.py',\n" | 130 " '<(DEPTH)/trace_inputs_test.py',\n" |
| 81 " ],\n" | 131 " ],\n" |
| 82 " 'isolate_dirs': [\n" | 132 " 'isolate_dirs': [\n" |
| 83 " ],\n" | 133 " ],\n" |
| 84 " },\n" | 134 " },\n" |
| 85 "},\n") | 135 "},\n") |
| 86 gyp = self._execute(['trace_inputs_test.py', '--child1']) | 136 actual = self._execute(self._gyp() + ['trace_inputs_test.py', '--child1']) |
| 87 self.assertEquals(expected, gyp) | 137 self.assertEquals(expected, actual) |
| 88 | 138 |
| 89 | 139 |
| 90 def child1(): | 140 def child1(): |
| 91 print 'child1' | 141 print 'child1' |
| 92 # Implicitly force file opening. | 142 # Implicitly force file opening. |
| 93 import trace_inputs # pylint: disable=W0612 | 143 import trace_inputs # pylint: disable=W0612 |
| 94 # Do not wait for the child to exit. | 144 # Do not wait for the child to exit. |
| 95 # Use relative directory. | 145 # Use relative directory. |
| 96 subprocess.Popen( | 146 subprocess.Popen( |
| 97 ['python', 'child2.py'], cwd=os.path.join('data', 'trace_inputs')) | 147 ['python', 'child2.py'], cwd=os.path.join('data', 'trace_inputs')) |
| 98 return 0 | 148 return 0 |
| 99 | 149 |
| 100 | 150 |
| 101 def main(): | 151 def main(): |
| 102 global VERBOSE | 152 global VERBOSE |
| 103 VERBOSE = '-v' in sys.argv | 153 VERBOSE = '-v' in sys.argv |
| 104 level = logging.DEBUG if VERBOSE else logging.ERROR | 154 level = logging.DEBUG if VERBOSE else logging.ERROR |
| 105 logging.basicConfig(level=level) | 155 logging.basicConfig(level=level) |
| 106 if len(sys.argv) == 1: | 156 if len(sys.argv) == 1: |
| 107 unittest.main() | 157 unittest.main() |
| 108 | 158 |
| 109 if sys.argv[1] == '--child1': | 159 if sys.argv[1] == '--child1': |
| 110 return child1() | 160 return child1() |
| 111 | 161 |
| 112 unittest.main() | 162 unittest.main() |
| 113 | 163 |
| 114 | 164 |
| 115 if __name__ == '__main__': | 165 if __name__ == '__main__': |
| 116 sys.exit(main()) | 166 sys.exit(main()) |
| OLD | NEW |