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 |
11 import re | 11 import re |
12 import shutil | 12 import shutil |
13 import subprocess | 13 import subprocess |
14 import sys | 14 import sys |
15 import tempfile | 15 import tempfile |
16 import unittest | 16 import unittest |
17 | 17 |
18 import isolate | 18 import isolate |
19 | 19 |
20 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) | 20 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) |
21 VERBOSE = False | 21 VERBOSE = False |
22 | 22 |
23 | 23 |
| 24 # Keep the list hard coded. |
| 25 EXPECTED_MODES = ('check', 'hashtable', 'remap', 'run', 'trace') |
| 26 # These are per test case, not per mode. |
| 27 RELATIVE_CWD = { |
| 28 'fail': '.', |
| 29 'missing_trailing_slash': '.', |
| 30 'no_run': '.', |
| 31 'non_existent': '.', |
| 32 'touch_root': 'data/isolate', |
| 33 'with_flag': '.', |
| 34 } |
| 35 DEPENDENCIES = { |
| 36 'fail': ['fail.py'], |
| 37 'missing_trailing_slash': [], |
| 38 'no_run': [ |
| 39 'no_run.isolate', 'files1/test_file1.txt', 'files1/test_file2.txt', |
| 40 ], |
| 41 'non_existent': [], |
| 42 'touch_root': ['data/isolate/touch_root.py', 'isolate.py'], |
| 43 'with_flag': [ |
| 44 'with_flag.py', 'files1/test_file1.txt', 'files1/test_file2.txt', |
| 45 ], |
| 46 } |
24 | 47 |
25 class CalledProcessError(subprocess.CalledProcessError): | 48 class CalledProcessError(subprocess.CalledProcessError): |
26 """Makes 2.6 version act like 2.7""" | 49 """Makes 2.6 version act like 2.7""" |
27 def __init__(self, returncode, cmd, output, cwd): | 50 def __init__(self, returncode, cmd, output, cwd): |
28 super(CalledProcessError, self).__init__(returncode, cmd) | 51 super(CalledProcessError, self).__init__(returncode, cmd) |
29 self.output = output | 52 self.output = output |
30 self.cwd = cwd | 53 self.cwd = cwd |
31 | 54 |
32 def __str__(self): | 55 def __str__(self): |
33 return super(CalledProcessError, self).__str__() + ( | 56 return super(CalledProcessError, self).__str__() + ( |
34 '\n' | 57 '\n' |
35 'cwd=%s\n%s') % (self.cwd, self.output) | 58 'cwd=%s\n%s') % (self.cwd, self.output) |
36 | 59 |
37 | 60 |
38 class Isolate(unittest.TestCase): | 61 class IsolateBase(unittest.TestCase): |
| 62 # To be defined by the subclass, it defines the amount of meta data saved by |
| 63 # isolate.py for each file. Should be one of (NO_INFO, STATS_ONLY, WITH_HASH). |
| 64 LEVEL = None |
| 65 |
39 def setUp(self): | 66 def setUp(self): |
40 # The tests assume the current directory is the file's directory. | 67 # The tests assume the current directory is the file's directory. |
41 os.chdir(ROOT_DIR) | 68 os.chdir(ROOT_DIR) |
42 self.tempdir = tempfile.mkdtemp() | 69 self.tempdir = tempfile.mkdtemp() |
43 self.result = os.path.join(self.tempdir, 'result') | 70 self.result = os.path.join(self.tempdir, 'isolate_smoke_test.result') |
44 self.child = os.path.join('data', 'isolate', 'child.py') | 71 self.outdir = os.path.join(self.tempdir, 'isolated') |
45 if VERBOSE: | |
46 print | |
47 self.files = [ | |
48 self.child, | |
49 os.path.join('data', 'isolate', 'files1', 'test_file1.txt'), | |
50 os.path.join('data', 'isolate', 'files1', 'test_file2.txt'), | |
51 ] | |
52 | 72 |
53 def tearDown(self): | 73 def tearDown(self): |
54 shutil.rmtree(self.tempdir) | 74 shutil.rmtree(self.tempdir) |
55 | 75 |
56 def _expected_tree(self, files): | 76 def _expect_no_tree(self): |
57 self.assertEquals(sorted(files), sorted(os.listdir(self.tempdir))) | 77 self.assertFalse(os.path.exists(self.outdir)) |
58 | 78 |
59 def _expected_result(self, with_hash, files, args, read_only): | 79 def _result_tree(self): |
| 80 actual = [] |
| 81 for root, _dirs, files in os.walk(self.outdir): |
| 82 actual.extend(os.path.join(root, f)[len(self.outdir)+1:] for f in files) |
| 83 return sorted(actual) |
| 84 |
| 85 def _expected_tree(self): |
| 86 """Verifies the files written in the temporary directory.""" |
| 87 self.assertEquals(sorted(DEPENDENCIES[self.case()]), self._result_tree()) |
| 88 |
| 89 @staticmethod |
| 90 def _fix_file_mode(filename, read_only): |
60 if sys.platform == 'win32': | 91 if sys.platform == 'win32': |
61 mode = lambda _: 420 | 92 # Deterministic file mode for a deterministic OS. |
| 93 return 420 |
62 else: | 94 else: |
63 # 4 modes are supported, 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r) | 95 # 4 modes are supported, 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r) |
64 min_mode = 0444 | 96 min_mode = 0444 |
65 if not read_only: | 97 if not read_only: |
66 min_mode |= 0200 | 98 min_mode |= 0200 |
67 def mode(filename): | 99 return (min_mode | 0111) if filename.endswith('.py') else min_mode |
68 return (min_mode | 0111) if filename.endswith('.py') else min_mode | |
69 | 100 |
70 if not isinstance(files, dict): | 101 def _gen_files(self, read_only): |
71 # Update files to dict. | 102 root_dir = ROOT_DIR |
72 files = dict((unicode(f), {u'mode': mode(f)}) for f in files) | 103 if RELATIVE_CWD[self.case()] == '.': |
73 # Add size and timestamp. | 104 root_dir = os.path.join(root_dir, 'data', 'isolate') |
74 files = files.copy() | 105 |
75 for k, v in files.iteritems(): | 106 files = dict((unicode(f), {}) for f in DEPENDENCIES[self.case()]) |
76 if v: | 107 |
77 filestats = os.stat(k) | 108 if self.LEVEL >= isolate.STATS_ONLY: |
| 109 for k, v in files.iteritems(): |
| 110 v[u'mode'] = self._fix_file_mode(k, read_only) |
| 111 filestats = os.stat(os.path.join(root_dir, k)) |
78 v[u'size'] = filestats.st_size | 112 v[u'size'] = filestats.st_size |
79 # Used the skip recalculating the hash. Use the most recent update | 113 # Used the skip recalculating the hash. Use the most recent update |
80 # time. | 114 # time. |
81 v[u'timestamp'] = int(round( | 115 v[u'timestamp'] = int(round(filestats.st_mtime)) |
82 max(filestats.st_mtime, filestats.st_ctime))) | |
83 | 116 |
| 117 if self.LEVEL >= isolate.WITH_HASH: |
| 118 for filename in files: |
| 119 # Calculate our hash. |
| 120 h = hashlib.sha1() |
| 121 h.update(open(os.path.join(root_dir, filename), 'rb').read()) |
| 122 files[filename][u'sha-1'] = unicode(h.hexdigest()) |
| 123 return files |
| 124 |
| 125 def _expected_result(self, args, read_only): |
| 126 """Verifies self.result contains the expected data.""" |
84 expected = { | 127 expected = { |
85 u'files': files, | 128 u'files': self._gen_files(read_only), |
86 u'relative_cwd': u'data/isolate', | 129 u'relative_cwd': unicode(RELATIVE_CWD[self.case()]), |
87 u'read_only': None, | 130 u'read_only': read_only, |
88 } | 131 } |
89 if args: | 132 if args: |
90 expected[u'command'] = [u'python'] + [unicode(x) for x in args] | 133 expected[u'command'] = [u'python'] + [unicode(x) for x in args] |
91 else: | 134 else: |
92 expected[u'command'] = [] | 135 expected[u'command'] = [] |
93 if with_hash: | |
94 for filename in expected[u'files']: | |
95 # Calculate our hash. | |
96 h = hashlib.sha1() | |
97 h.update(open(os.path.join(ROOT_DIR, filename), 'rb').read()) | |
98 expected[u'files'][filename][u'sha-1'] = unicode(h.hexdigest()) | |
99 | 136 |
100 actual = json.load(open(self.result, 'rb')) | 137 self.assertEquals(expected, json.load(open(self.result, 'rb'))) |
101 self.assertEquals(expected, actual) | |
102 return expected | 138 return expected |
103 | 139 |
104 def _execute(self, filename, args, need_output=False): | 140 def _expect_no_result(self): |
| 141 self.assertFalse(os.path.exists(self.result)) |
| 142 |
| 143 def _execute(self, mode, case, args, need_output): |
| 144 """Executes isolate.py.""" |
| 145 self.assertEquals( |
| 146 mode, self.mode(), 'Rename the test fixture to Isolate_%s' % mode) |
| 147 self.assertEquals( |
| 148 case, |
| 149 self.case() + '.isolate', |
| 150 'Rename the test case to test_%s()' % case) |
| 151 # TODO(maruel): This is going away, temporary until DEPTH support is |
| 152 # removed. |
| 153 depth = os.path.join('data', 'isolate') |
| 154 if RELATIVE_CWD[self.case()] != '.': |
| 155 depth = '.' |
105 cmd = [ | 156 cmd = [ |
106 sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), | 157 sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), |
107 '--variable', 'DEPTH=%s' % ROOT_DIR, | |
108 '--result', self.result, | 158 '--result', self.result, |
109 os.path.join(ROOT_DIR, 'data', 'isolate', filename), | 159 '--outdir', self.outdir, |
110 ] + args | 160 '-V', 'DEPTH=%s' % depth, |
| 161 self.filename(), |
| 162 '--mode', self.mode(), |
| 163 ] |
| 164 cmd.extend(args) |
| 165 |
111 env = os.environ.copy() | 166 env = os.environ.copy() |
112 if 'ISOLATE_DEBUG' in env: | 167 if 'ISOLATE_DEBUG' in env: |
113 del env['ISOLATE_DEBUG'] | 168 del env['ISOLATE_DEBUG'] |
| 169 |
114 if need_output or not VERBOSE: | 170 if need_output or not VERBOSE: |
115 stdout = subprocess.PIPE | 171 stdout = subprocess.PIPE |
116 stderr = subprocess.STDOUT | 172 stderr = subprocess.STDOUT |
117 else: | 173 else: |
118 cmd.extend(['-v'] * 3) | 174 cmd.extend(['-v'] * 3) |
119 stdout = None | 175 stdout = None |
120 stderr = None | 176 stderr = None |
| 177 |
121 cwd = ROOT_DIR | 178 cwd = ROOT_DIR |
122 p = subprocess.Popen( | 179 p = subprocess.Popen( |
123 cmd + args, | 180 cmd, |
124 stdout=stdout, | 181 stdout=stdout, |
125 stderr=stderr, | 182 stderr=stderr, |
126 cwd=cwd, | 183 cwd=cwd, |
127 env=env, | 184 env=env, |
128 universal_newlines=True) | 185 universal_newlines=True) |
129 out = p.communicate()[0] | 186 out = p.communicate()[0] |
130 if p.returncode: | 187 if p.returncode: |
131 raise CalledProcessError(p.returncode, cmd, out, cwd) | 188 raise CalledProcessError(p.returncode, cmd, out, cwd) |
132 return out | 189 return out |
133 | 190 |
| 191 def mode(self): |
| 192 """Returns the execution mode corresponding to this test case.""" |
| 193 test_id = self.id().split('.') |
| 194 self.assertEquals(3, len(test_id)) |
| 195 self.assertEquals('__main__', test_id[0]) |
| 196 return re.match('^Isolate_([a-z]+)$', test_id[1]).group(1) |
| 197 |
| 198 def case(self): |
| 199 """Returns the filename corresponding to this test case.""" |
| 200 test_id = self.id().split('.') |
| 201 return re.match('^test_([a-z_]+)$', test_id[2]).group(1) |
| 202 |
| 203 def filename(self): |
| 204 """Returns the filename corresponding to this test case.""" |
| 205 filename = os.path.join( |
| 206 ROOT_DIR, 'data', 'isolate', self.case() + '.isolate') |
| 207 self.assertTrue(os.path.isfile(filename), filename) |
| 208 return filename |
| 209 |
| 210 |
| 211 class Isolate(unittest.TestCase): |
134 def test_help_modes(self): | 212 def test_help_modes(self): |
135 # Check coherency in the help and implemented modes. | 213 # Check coherency in the help and implemented modes. |
136 p = subprocess.Popen( | 214 p = subprocess.Popen( |
137 [sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), '--help'], | 215 [sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), '--help'], |
138 stdout=subprocess.PIPE, | 216 stdout=subprocess.PIPE, |
139 stderr=subprocess.STDOUT, | 217 stderr=subprocess.STDOUT, |
140 cwd=ROOT_DIR) | 218 cwd=ROOT_DIR) |
141 out = p.communicate()[0].splitlines() | 219 out = p.communicate()[0].splitlines() |
142 self.assertEquals(0, p.returncode) | 220 self.assertEquals(0, p.returncode) |
143 out = out[out.index('') + 1:] | 221 out = out[out.index('') + 1:] |
144 out = out[:out.index('')] | 222 out = out[:out.index('')] |
145 modes = [re.match(r'^ (\w+) .+', l) for l in out] | 223 modes = [re.match(r'^ (\w+) .+', l) for l in out] |
146 modes = tuple(m.group(1) for m in modes if m) | 224 modes = tuple(m.group(1) for m in modes if m) |
147 # Keep the list hard coded. | 225 self.assertEquals(EXPECTED_MODES, modes) |
148 expected = ('check', 'hashtable', 'remap', 'run', 'trace') | 226 |
149 self.assertEquals(expected, modes) | 227 def test_modes(self): |
150 self.assertEquals(expected, modes) | 228 # This is a bit redundant but make sure all combinations are tested. |
151 for mode in modes: | 229 files = sorted( |
152 self.assertTrue(hasattr(self, 'test_%s' % mode), mode) | 230 i[:-len('.isolate')] |
153 self._expected_tree([]) | 231 for i in os.listdir(os.path.join(ROOT_DIR, 'data', 'isolate')) |
154 | 232 if i.endswith('.isolate') |
155 def test_check(self): | 233 ) |
156 self._execute('fail.isolate', ['--mode', 'check']) | 234 self.assertEquals(sorted(RELATIVE_CWD), files) |
157 self._expected_tree(['result']) | 235 self.assertEquals(sorted(DEPENDENCIES), files) |
158 self._expected_result( | 236 for mode in EXPECTED_MODES: |
159 False, dict((f, {}) for f in self.files), ['child.py', '--fail'], False) | 237 expected_cases = set('test_%s' % f for f in files) |
160 | 238 fixture_name = 'Isolate_%s' % mode |
161 def test_check_no_run(self): | 239 fixture = getattr(sys.modules[__name__], fixture_name) |
162 self._execute('no_run.isolate', ['--mode', 'check']) | 240 actual_cases = set(i for i in dir(fixture) if i.startswith('test_')) |
163 self._expected_tree(['result']) | 241 missing = expected_cases - actual_cases |
164 self._expected_result( | 242 self.assertFalse(missing, '%s.%s' % (fixture_name, missing)) |
165 False, dict((f, {}) for f in self.files), None, False) | 243 |
166 | 244 |
167 def test_check_non_existent(self): | 245 class Isolate_check(IsolateBase): |
168 try: | 246 LEVEL = isolate.NO_INFO |
169 self._execute('non_existent.isolate', ['--mode', 'check']) | 247 |
170 self.fail() | 248 def test_fail(self): |
171 except subprocess.CalledProcessError: | 249 self._execute('check', 'fail.isolate', [], False) |
172 pass | 250 self._expect_no_tree() |
173 self._expected_tree([]) | 251 self._expected_result(['fail.py'], None) |
174 | 252 |
175 def test_check_directory_no_slash(self): | 253 def test_missing_trailing_slash(self): |
176 try: | 254 try: |
177 self._execute('missing_trailing_slash.isolate', ['--mode', 'check']) | 255 self._execute('check', 'missing_trailing_slash.isolate', [], False) |
178 self.fail() | 256 self.fail() |
179 except subprocess.CalledProcessError: | 257 except subprocess.CalledProcessError: |
180 pass | 258 pass |
181 self._expected_tree([]) | 259 self._expect_no_tree() |
182 | 260 self._expect_no_result() |
183 def test_hashtable(self): | 261 |
184 cmd = [ | 262 def test_non_existent(self): |
185 '--mode', 'hashtable', | 263 try: |
186 '--outdir', self.tempdir, | 264 self._execute('check', 'non_existent.isolate', [], False) |
187 ] | 265 self.fail() |
188 self._execute('no_run.isolate', cmd) | 266 except subprocess.CalledProcessError: |
189 data = self._expected_result(True, self.files, None, False) | 267 pass |
190 self._expected_tree( | 268 self._expect_no_tree() |
191 [f['sha-1'] for f in data['files'].itervalues()] + ['result']) | 269 self._expect_no_result() |
192 | 270 |
193 def test_remap(self): | 271 def test_no_run(self): |
194 cmd = [ | 272 self._execute('check', 'no_run.isolate', [], False) |
195 '--mode', 'remap', | 273 self._expect_no_tree() |
196 '--outdir', self.tempdir, | 274 self._expected_result([], None) |
197 ] | 275 |
198 self._execute('no_run.isolate', cmd) | 276 def test_touch_root(self): |
199 self._expected_tree(['data', 'result']) | 277 self._execute('check', 'touch_root.isolate', [], False) |
200 self._expected_result( | 278 self._expect_no_tree() |
201 False, | 279 self._expected_result(['touch_root.py'], None) |
202 self.files, | 280 |
203 None, | 281 def test_with_flag(self): |
204 False) | 282 self._execute('check', 'with_flag.isolate', ['-V', 'FLAG=gyp'], False) |
205 | 283 self._expect_no_tree() |
206 def test_run(self): | 284 self._expected_result(['with_flag.py', 'gyp'], None) |
207 self._execute('ok.isolate', ['--mode', 'run']) | 285 |
208 self._expected_tree(['result']) | 286 |
209 # cmd[0] is not generated from infiles[0] so it's not using a relative path. | 287 class Isolate_hashtable(IsolateBase): |
210 self._expected_result( | 288 LEVEL = isolate.WITH_HASH |
211 False, self.files, ['child.py', '--ok'], False) | 289 |
212 | 290 def _expected_hash_tree(self): |
213 def test_run_fail(self): | 291 """Verifies the files written in the temporary directory.""" |
214 try: | 292 expected = [v['sha-1'] for v in self._gen_files(False).itervalues()] |
215 self._execute('fail.isolate', ['--mode', 'run']) | 293 self.assertEquals(sorted(expected), self._result_tree()) |
216 self.fail() | 294 |
217 except subprocess.CalledProcessError: | 295 def test_fail(self): |
218 pass | 296 self._execute('hashtable', 'fail.isolate', [], False) |
219 self._expected_tree(['result']) | 297 self._expected_hash_tree() |
220 | 298 self._expected_result(['fail.py'], None) |
221 def test_trace(self): | 299 |
222 out = self._execute('ok.isolate', ['--mode', 'trace'], True) | 300 def test_missing_trailing_slash(self): |
223 self._expected_tree(['result', 'result.log']) | 301 try: |
224 # The 'result.log' log is OS-specific so we can't read it but we can read | 302 self._execute('hashtable', 'missing_trailing_slash.isolate', [], False) |
225 # the gyp result. | 303 self.fail() |
226 # cmd[0] is not generated from infiles[0] so it's not using a relative path. | 304 except subprocess.CalledProcessError: |
227 self._expected_result( | 305 pass |
228 False, self.files, ['child.py', '--ok'], False) | 306 self._expect_no_tree() |
229 | 307 self._expect_no_result() |
230 expected_value = { | 308 |
| 309 def test_non_existent(self): |
| 310 try: |
| 311 self._execute('hashtable', 'non_existent.isolate', [], False) |
| 312 self.fail() |
| 313 except subprocess.CalledProcessError: |
| 314 pass |
| 315 self._expect_no_tree() |
| 316 self._expect_no_result() |
| 317 |
| 318 def test_no_run(self): |
| 319 self._execute('hashtable', 'no_run.isolate', [], False) |
| 320 self._expected_hash_tree() |
| 321 self._expected_result([], None) |
| 322 |
| 323 def test_touch_root(self): |
| 324 self._execute('hashtable', 'touch_root.isolate', [], False) |
| 325 self._expected_hash_tree() |
| 326 self._expected_result(['touch_root.py'], None) |
| 327 |
| 328 def test_with_flag(self): |
| 329 self._execute('hashtable', 'with_flag.isolate', ['-V', 'FLAG=gyp'], False) |
| 330 self._expected_hash_tree() |
| 331 self._expected_result(['with_flag.py', 'gyp'], None) |
| 332 |
| 333 |
| 334 class Isolate_remap(IsolateBase): |
| 335 LEVEL = isolate.STATS_ONLY |
| 336 |
| 337 def test_fail(self): |
| 338 self._execute('remap', 'fail.isolate', [], False) |
| 339 self._expected_tree() |
| 340 self._expected_result(['fail.py'], None) |
| 341 |
| 342 def test_missing_trailing_slash(self): |
| 343 try: |
| 344 self._execute('remap', 'missing_trailing_slash.isolate', [], False) |
| 345 self.fail() |
| 346 except subprocess.CalledProcessError: |
| 347 pass |
| 348 self._expect_no_tree() |
| 349 self._expect_no_result() |
| 350 |
| 351 def test_non_existent(self): |
| 352 try: |
| 353 self._execute('remap', 'non_existent.isolate', [], False) |
| 354 self.fail() |
| 355 except subprocess.CalledProcessError: |
| 356 pass |
| 357 self._expect_no_tree() |
| 358 self._expect_no_result() |
| 359 |
| 360 def test_no_run(self): |
| 361 self._execute('remap', 'no_run.isolate', [], False) |
| 362 self._expected_tree() |
| 363 self._expected_result([], None) |
| 364 |
| 365 def test_touch_root(self): |
| 366 self._execute('remap', 'touch_root.isolate', [], False) |
| 367 self._expected_tree() |
| 368 self._expected_result(['touch_root.py'], None) |
| 369 |
| 370 def test_with_flag(self): |
| 371 self._execute('remap', 'with_flag.isolate', ['-V', 'FLAG=gyp'], False) |
| 372 self._expected_tree() |
| 373 self._expected_result(['with_flag.py', 'gyp'], None) |
| 374 |
| 375 |
| 376 class Isolate_run(IsolateBase): |
| 377 LEVEL = isolate.STATS_ONLY |
| 378 |
| 379 def _expect_empty_tree(self): |
| 380 self.assertEquals([], self._result_tree()) |
| 381 |
| 382 def test_fail(self): |
| 383 try: |
| 384 self._execute('run', 'fail.isolate', [], False) |
| 385 self.fail() |
| 386 except subprocess.CalledProcessError: |
| 387 pass |
| 388 self._expect_empty_tree() |
| 389 self._expected_result(['fail.py'], None) |
| 390 |
| 391 def test_missing_trailing_slash(self): |
| 392 try: |
| 393 self._execute('run', 'missing_trailing_slash.isolate', [], False) |
| 394 self.fail() |
| 395 except subprocess.CalledProcessError: |
| 396 pass |
| 397 self._expect_no_tree() |
| 398 self._expect_no_result() |
| 399 |
| 400 def test_non_existent(self): |
| 401 try: |
| 402 self._execute('run', 'non_existent.isolate', [], False) |
| 403 self.fail() |
| 404 except subprocess.CalledProcessError: |
| 405 pass |
| 406 self._expect_no_tree() |
| 407 self._expect_no_result() |
| 408 |
| 409 def test_no_run(self): |
| 410 try: |
| 411 self._execute('run', 'no_run.isolate', [], False) |
| 412 self.fail() |
| 413 except subprocess.CalledProcessError: |
| 414 pass |
| 415 self._expect_empty_tree() |
| 416 self._expected_result([], None) |
| 417 |
| 418 def test_touch_root(self): |
| 419 self._execute('run', 'touch_root.isolate', [], False) |
| 420 self._expect_empty_tree() |
| 421 self._expected_result(['touch_root.py'], None) |
| 422 |
| 423 def test_with_flag(self): |
| 424 self._execute('run', 'with_flag.isolate', ['-V', 'FLAG=run'], False) |
| 425 # Not sure about the empty tree, should be deleted. |
| 426 self._expect_empty_tree() |
| 427 self._expected_result(['with_flag.py', 'run'], None) |
| 428 |
| 429 |
| 430 class Isolate_trace(IsolateBase): |
| 431 LEVEL = isolate.STATS_ONLY |
| 432 |
| 433 @staticmethod |
| 434 def _to_string(values): |
| 435 buf = cStringIO.StringIO() |
| 436 isolate.trace_inputs.pretty_print(values, buf) |
| 437 return buf.getvalue() |
| 438 |
| 439 def test_fail(self): |
| 440 try: |
| 441 self._execute('trace', 'fail.isolate', [], True) |
| 442 self.fail() |
| 443 except subprocess.CalledProcessError, e: |
| 444 out = e.output |
| 445 self._expect_no_tree() |
| 446 self._expected_result(['fail.py'], None) |
| 447 expected = 'Failure: 1\nFailing\n\n' |
| 448 self.assertEquals(expected, out) |
| 449 |
| 450 def test_missing_trailing_slash(self): |
| 451 try: |
| 452 self._execute('trace', 'missing_trailing_slash.isolate', [], True) |
| 453 self.fail() |
| 454 except subprocess.CalledProcessError, e: |
| 455 out = e.output |
| 456 self._expect_no_tree() |
| 457 self._expect_no_result() |
| 458 expected = 'Input directory %s must have a trailing slash\n' % os.path.join( |
| 459 ROOT_DIR, 'data', 'isolate', 'files1') |
| 460 self.assertEquals(expected, out) |
| 461 |
| 462 def test_non_existent(self): |
| 463 try: |
| 464 self._execute('trace', 'non_existent.isolate', [], True) |
| 465 self.fail() |
| 466 except subprocess.CalledProcessError, e: |
| 467 out = e.output |
| 468 self._expect_no_tree() |
| 469 self._expect_no_result() |
| 470 expected = 'Input file %s doesn\'t exist\n' % os.path.join( |
| 471 ROOT_DIR, 'data', 'isolate', 'A_file_that_do_not_exist') |
| 472 self.assertEquals(expected, out) |
| 473 |
| 474 def test_no_run(self): |
| 475 try: |
| 476 self._execute('trace', 'no_run.isolate', [], True) |
| 477 self.fail() |
| 478 except subprocess.CalledProcessError, e: |
| 479 out = e.output |
| 480 self._expect_no_tree() |
| 481 self._expected_result([], None) |
| 482 expected = 'No command to run\n' |
| 483 self.assertEquals(expected, out) |
| 484 |
| 485 def test_touch_root(self): |
| 486 out = self._execute('trace', 'touch_root.isolate', [], True) |
| 487 self._expect_no_tree() |
| 488 self._expected_result(['touch_root.py'], None) |
| 489 expected = { |
231 'conditions': [ | 490 'conditions': [ |
232 ['OS=="%s"' % isolate.trace_inputs.get_flavor(), { | 491 ['OS=="%s"' % isolate.trace_inputs.get_flavor(), { |
233 'variables': { | 492 'variables': { |
234 isolate.trace_inputs.KEY_TRACKED: [ | 493 isolate.trace_inputs.KEY_TRACKED: [ |
235 'child.py', | 494 'touch_root.py', |
| 495 '../../isolate.py', |
| 496 ], |
| 497 }, |
| 498 }], |
| 499 ], |
| 500 } |
| 501 self.assertEquals(self._to_string(expected), out) |
| 502 |
| 503 def test_with_flag(self): |
| 504 out = self._execute( |
| 505 'trace', 'with_flag.isolate', ['-V', 'FLAG=trace'], True) |
| 506 self._expect_no_tree() |
| 507 self._expected_result(['with_flag.py', 'trace'], None) |
| 508 expected = { |
| 509 'conditions': [ |
| 510 ['OS=="%s"' % isolate.trace_inputs.get_flavor(), { |
| 511 'variables': { |
| 512 isolate.trace_inputs.KEY_TRACKED: [ |
| 513 'with_flag.py', |
236 ], | 514 ], |
237 isolate.trace_inputs.KEY_UNTRACKED: [ | 515 isolate.trace_inputs.KEY_UNTRACKED: [ |
238 'files1/', | 516 'files1/', |
239 ], | 517 ], |
240 }, | 518 }, |
241 }], | 519 }], |
242 ], | 520 ], |
243 } | 521 } |
244 expected_buffer = cStringIO.StringIO() | 522 self.assertEquals(self._to_string(expected), out) |
245 isolate.trace_inputs.pretty_print(expected_value, expected_buffer) | |
246 self.assertEquals(expected_buffer.getvalue(), out) | |
247 | 523 |
248 | 524 |
249 | 525 |
250 if __name__ == '__main__': | 526 if __name__ == '__main__': |
251 VERBOSE = '-v' in sys.argv | 527 VERBOSE = '-v' in sys.argv |
252 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) | 528 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) |
253 unittest.main() | 529 unittest.main() |
OLD | NEW |