Chromium Code Reviews| 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 logging | 7 import logging |
| 8 import os | 8 import os |
| 9 import shutil | 9 import shutil |
| 10 import subprocess | 10 import subprocess |
| 11 import sys | 11 import sys |
| 12 import tempfile | 12 import tempfile |
| 13 import unittest | 13 import unittest |
| 14 | 14 |
| 15 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) | 15 FULLNAME = os.path.abspath(__file__) |
| 16 ROOT_DIR = os.path.dirname(FULLNAME) | |
| 16 FILENAME = os.path.basename(__file__) | 17 FILENAME = os.path.basename(__file__) |
| 17 VERBOSE = False | 18 VERBOSE = False |
| 18 | 19 |
| 19 | 20 |
| 20 class CalledProcessError(subprocess.CalledProcessError): | 21 class CalledProcessError(subprocess.CalledProcessError): |
| 21 """Makes 2.6 version act like 2.7""" | 22 """Makes 2.6 version act like 2.7""" |
| 22 def __init__(self, returncode, cmd, output, cwd): | 23 def __init__(self, returncode, cmd, output, cwd): |
| 23 super(CalledProcessError, self).__init__(returncode, cmd) | 24 super(CalledProcessError, self).__init__(returncode, cmd) |
| 24 self.output = output | 25 self.output = output |
| 25 self.cwd = cwd | 26 self.cwd = cwd |
| 26 | 27 |
| 27 def __str__(self): | 28 def __str__(self): |
| 28 return super(CalledProcessError, self).__str__() + ( | 29 return super(CalledProcessError, self).__str__() + ( |
| 29 '\n' | 30 '\n' |
| 30 'cwd=%s\n%s') % (self.cwd, self.output) | 31 'cwd=%s\n%s') % (self.cwd, self.output) |
| 31 | 32 |
| 32 | 33 |
| 33 class TraceInputs(unittest.TestCase): | 34 class TraceInputsBase(unittest.TestCase): |
| 34 def setUp(self): | 35 def setUp(self): |
| 35 self.tempdir = tempfile.mkdtemp(prefix='trace_smoke_test') | 36 self.tempdir = tempfile.mkdtemp(prefix='trace_smoke_test') |
| 36 self.log = os.path.join(self.tempdir, 'log') | 37 self.log = os.path.join(self.tempdir, 'log') |
| 37 os.chdir(ROOT_DIR) | 38 os.chdir(ROOT_DIR) |
| 38 | 39 |
| 39 def tearDown(self): | 40 def tearDown(self): |
| 40 if VERBOSE: | 41 if VERBOSE: |
| 41 print 'Leaking: %s' % self.tempdir | 42 print 'Leaking: %s' % self.tempdir |
| 42 else: | 43 else: |
| 43 shutil.rmtree(self.tempdir) | 44 shutil.rmtree(self.tempdir) |
| 44 | 45 |
| 45 def _execute(self, is_gyp): | 46 @staticmethod |
| 46 cmd = [ | 47 def command(from_data): |
| 47 sys.executable, os.path.join('..', '..', 'trace_inputs.py'), | 48 cmd = [sys.executable] |
| 48 '--log', self.log, | 49 if from_data: |
| 49 '--root-dir', ROOT_DIR, | |
| 50 ] | |
| 51 if VERBOSE: | |
| 52 cmd.extend(['-v'] * 3) | |
| 53 if is_gyp: | |
| 54 cmd.extend( | |
| 55 [ | |
| 56 '--cwd', 'data', | |
| 57 '--product', '.', # Not tested. | |
| 58 ]) | |
| 59 cmd.append(sys.executable) | |
| 60 if is_gyp: | |
| 61 # When the gyp argument is specified, the command is started from --cwd | 50 # When the gyp argument is specified, the command is started from --cwd |
| 62 # directory. In this case, 'data'. | 51 # directory. In this case, 'data'. |
| 63 cmd.extend([os.path.join('trace_inputs', 'child1.py'), '--child-gyp']) | 52 cmd.extend([os.path.join('trace_inputs', 'child1.py'), '--child-gyp']) |
| 64 else: | 53 else: |
| 65 # When the gyp argument is not specified, the command is started from | 54 # When the gyp argument is not specified, the command is started from |
| 66 # --root-dir directory. | 55 # --root-dir directory. |
| 67 cmd.extend([os.path.join('data', 'trace_inputs', 'child1.py'), '--child']) | 56 cmd.extend([os.path.join('data', 'trace_inputs', 'child1.py'), '--child']) |
| 57 return cmd | |
| 68 | 58 |
| 59 | |
| 60 class TraceInputs(TraceInputsBase): | |
| 61 def _execute(self, command): | |
| 62 cmd = [ | |
| 63 sys.executable, os.path.join('..', '..', 'trace_inputs.py'), | |
| 64 '--log', self.log, | |
| 65 '--root-dir', ROOT_DIR, | |
| 66 ] | |
| 67 if VERBOSE: | |
| 68 cmd.extend(['-v'] * 3) | |
| 69 cmd.extend(command) | |
| 69 # The current directory doesn't matter, the traced process will be called | 70 # The current directory doesn't matter, the traced process will be called |
| 70 # from the correct cwd. | 71 # from the correct cwd. |
| 71 cwd = os.path.join('data', 'trace_inputs') | 72 cwd = os.path.join('data', 'trace_inputs') |
| 72 # Ignore stderr. | 73 # Ignore stderr. |
| 73 logging.info('Command: %s' % ' '.join(cmd)) | 74 logging.info('Command: %s' % ' '.join(cmd)) |
| 74 p = subprocess.Popen( | 75 p = subprocess.Popen( |
| 75 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, | 76 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, |
| 76 universal_newlines=True) | 77 universal_newlines=True) |
| 77 out, err = p.communicate() | 78 out, err = p.communicate() |
| 78 if VERBOSE: | 79 if VERBOSE: |
| 79 print err | 80 print err |
| 80 if p.returncode: | 81 if p.returncode: |
| 81 raise CalledProcessError(p.returncode, cmd, out + err, cwd) | 82 raise CalledProcessError(p.returncode, cmd, out + err, cwd) |
| 82 return out or '' | 83 return out or '' |
| 83 | 84 |
| 84 def test_trace(self): | 85 def test_trace(self): |
| 85 expected_end = [ | 86 expected_end = [ |
| 86 'Interesting: 5 reduced to 3', | 87 'Interesting: 5 reduced to 3', |
| 87 ' data/trace_inputs/'.replace('/', os.path.sep), | 88 ' data/trace_inputs/'.replace('/', os.path.sep), |
| 88 ' trace_inputs.py', | 89 ' trace_inputs.py', |
| 89 ' %s' % FILENAME, | 90 ' %s' % FILENAME, |
| 90 ] | 91 ] |
| 91 actual = self._execute(False).splitlines() | 92 actual = self._execute(self.command(False)).splitlines() |
| 92 self.assertTrue(actual[0].startswith('Tracing... ['), actual) | 93 self.assertTrue(actual[0].startswith('Tracing... ['), actual) |
| 93 self.assertTrue(actual[1].startswith('Loading traces... '), actual) | 94 self.assertTrue(actual[1].startswith('Loading traces... '), actual) |
| 94 self.assertTrue(actual[2].startswith('Total: '), actual) | 95 self.assertTrue(actual[2].startswith('Total: '), actual) |
| 95 if sys.platform == 'win32': | 96 if sys.platform == 'win32': |
| 96 # On windows, python searches the current path for python stdlib like | 97 # On windows, python searches the current path for python stdlib like |
| 97 # subprocess.py and others, I'm not sure why. | 98 # subprocess.py and others, I'm not sure why. |
| 98 self.assertTrue(actual[3].startswith('Non existent: '), actual[3]) | 99 self.assertTrue(actual[3].startswith('Non existent: '), actual[3]) |
| 99 else: | 100 else: |
| 100 self.assertEquals('Non existent: 0', actual[3]) | 101 self.assertEquals('Non existent: 0', actual[3]) |
| 101 # Ignore any Unexpected part. | 102 # Ignore any Unexpected part. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 117 'isolate_dependency_untracked': [ | 118 'isolate_dependency_untracked': [ |
| 118 'trace_inputs/', | 119 'trace_inputs/', |
| 119 ], | 120 ], |
| 120 }, | 121 }, |
| 121 }], | 122 }], |
| 122 ], | 123 ], |
| 123 } | 124 } |
| 124 expected_buffer = cStringIO.StringIO() | 125 expected_buffer = cStringIO.StringIO() |
| 125 trace_inputs.pretty_print(expected_value, expected_buffer) | 126 trace_inputs.pretty_print(expected_value, expected_buffer) |
| 126 | 127 |
| 127 actual = self._execute(True) | 128 cmd = [ |
| 129 '--cwd', 'data', | |
| 130 '--product', '.', # Not tested. | |
| 131 ] + self.command(True) | |
| 132 actual = self._execute(cmd) | |
| 128 self.assertEquals(expected_buffer.getvalue(), actual) | 133 self.assertEquals(expected_buffer.getvalue(), actual) |
| 129 | 134 |
| 130 | 135 |
| 136 class TraceInputsImport(TraceInputsBase): | |
| 137 def setUp(self): | |
| 138 super(TraceInputsImport, self).setUp() | |
| 139 self.cwd = os.path.join(ROOT_DIR, u'data') | |
| 140 self.initial_cwd = self.cwd | |
| 141 if sys.platform == 'win32': | |
| 142 # Still not supported on Windows. | |
| 143 self.initial_cwd = None | |
| 144 | |
| 145 # Similar to TraceInputs test fixture except that it calls the function | |
| 146 # directly, so the Results instance can be inspected. | |
| 147 # Roughly, make sure the API is stable. | |
| 148 def _execute(self, command): | |
| 149 # Similar to what trace_test_cases.py does. | |
| 150 import trace_inputs | |
| 151 api = trace_inputs.get_api() | |
| 152 _, _ = trace_inputs.trace( | |
| 153 self.log, command, self.cwd, api, True) | |
| 154 # TODO(maruel): Check | |
| 155 #self.assertEquals(0, returncode) | |
| 156 #self.assertEquals('', output) | |
| 157 return trace_inputs.load_trace(self.log, ROOT_DIR, api) | |
| 158 | |
| 159 def test_trace_wrong_path(self): | |
| 160 # Deliberately start the trace from the wrong path. Start it from inside | |
| 161 # data so data/data/trace_inputs/child1.py is not accessible. | |
| 162 # and no child . | |
|
MAD
2012/05/30 20:29:36
and no child?
M-A Ruel
2012/05/30 22:34:10
No child is left behind, finished sentence.
MAD
2012/05/31 14:00:57
You end previous line with a "." and start this on
M-A Ruel
2012/05/31 14:56:45
I can't type. Hopefully fixed.
| |
| 163 results, simplified = self._execute(self.command(False)) | |
| 164 expected = { | |
| 165 'root': { | |
| 166 'children': [], | |
| 167 'command': None, | |
| 168 'executable': None, | |
| 169 'files': [], | |
| 170 'initial_cwd': self.initial_cwd, | |
| 171 }, | |
| 172 } | |
| 173 actual = results.flatten() | |
| 174 self.assertTrue(actual['root'].pop('pid')) | |
| 175 self.assertEquals(expected, actual) | |
| 176 self.assertEquals([], simplified) | |
| 177 | |
| 178 def test_trace(self): | |
| 179 size_t_i_s = os.stat(FULLNAME).st_size | |
| 180 size_t_i = os.stat(os.path.join(ROOT_DIR, 'trace_inputs.py')).st_size | |
| 181 expected = { | |
| 182 'root': { | |
| 183 'children': [ | |
| 184 { | |
| 185 'children': [], | |
| 186 'command': None, | |
| 187 'executable': None, | |
| 188 'files': [ | |
| 189 { | |
| 190 'path': os.path.join(u'data', 'trace_inputs', 'child2.py'), | |
| 191 'size': 776, | |
| 192 }, | |
| 193 { | |
| 194 'path': os.path.join(u'data', 'trace_inputs', 'test_file.txt'), | |
| 195 'size': 4, | |
| 196 }, | |
| 197 ], | |
| 198 'initial_cwd': self.initial_cwd, | |
| 199 }, | |
| 200 ], | |
| 201 'command': None, | |
| 202 'executable': None, | |
| 203 'files': [ | |
| 204 { | |
| 205 'path': os.path.join(u'data', 'trace_inputs', 'child1.py'), | |
| 206 'size': 1364, | |
| 207 }, | |
| 208 { | |
| 209 'path': u'trace_inputs.py', | |
| 210 'size': size_t_i, | |
| 211 }, | |
| 212 { | |
| 213 'path': u'trace_inputs_smoke_test.py', | |
| 214 'size': size_t_i_s, | |
| 215 }, | |
| 216 ], | |
| 217 'initial_cwd': self.initial_cwd, | |
| 218 }, | |
| 219 } | |
| 220 results, simplified = self._execute(self.command(True)) | |
| 221 actual = results.flatten() | |
| 222 self.assertTrue(actual['root'].pop('pid')) | |
| 223 self.assertTrue(actual['root']['children'][0].pop('pid')) | |
| 224 self.assertEquals(expected, actual) | |
| 225 files = [ | |
| 226 os.path.join(u'data', 'trace_inputs') + os.path.sep, | |
| 227 u'trace_inputs.py', | |
| 228 u'trace_inputs_smoke_test.py', | |
| 229 ] | |
| 230 self.assertEquals(files, [f.path for f in simplified]) | |
| 231 | |
| 232 | |
| 233 | |
| 131 if __name__ == '__main__': | 234 if __name__ == '__main__': |
| 132 VERBOSE = '-v' in sys.argv | 235 VERBOSE = '-v' in sys.argv |
| 133 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) | 236 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) |
| 134 unittest.main() | 237 unittest.main() |
| OLD | NEW |