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 |