OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 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 |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import json |
| 7 import logging |
| 8 import os |
| 9 import shutil |
| 10 import subprocess |
| 11 import sys |
| 12 import tempfile |
| 13 import unittest |
| 14 |
| 15 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 16 sys.path.insert(0, ROOT_DIR) |
| 17 |
| 18 import run_test_cases |
| 19 |
| 20 FILENAME = os.path.basename(__file__) |
| 21 REL_DATA = os.path.join(u'tests', 'trace_inputs') |
| 22 VERBOSE = False |
| 23 |
| 24 |
| 25 class CalledProcessError(subprocess.CalledProcessError): |
| 26 """Makes 2.6 version act like 2.7""" |
| 27 def __init__(self, returncode, cmd, output, cwd): |
| 28 super(CalledProcessError, self).__init__(returncode, cmd) |
| 29 self.output = output |
| 30 self.cwd = cwd |
| 31 |
| 32 def __str__(self): |
| 33 return super(CalledProcessError, self).__str__() + ( |
| 34 '\n' |
| 35 'cwd=%s\n%s') % (self.cwd, self.output) |
| 36 |
| 37 |
| 38 class TraceInputsBase(unittest.TestCase): |
| 39 def setUp(self): |
| 40 self.tempdir = tempfile.mkdtemp(prefix='trace_smoke_test') |
| 41 self.log = os.path.join(self.tempdir, 'log') |
| 42 self.trace_inputs_path = os.path.join(ROOT_DIR, 'trace_inputs.py') |
| 43 |
| 44 # Wraps up all the differences between OSes here. |
| 45 # - Windows doesn't track initial_cwd. |
| 46 # - OSX replaces /usr/bin/python with /usr/bin/python2.7. |
| 47 self.cwd = os.path.join(ROOT_DIR, u'tests') |
| 48 self.initial_cwd = unicode(self.cwd) |
| 49 self.expected_cwd = unicode(ROOT_DIR) |
| 50 if sys.platform == 'win32': |
| 51 # Not supported on Windows. |
| 52 self.initial_cwd = None |
| 53 self.expected_cwd = None |
| 54 |
| 55 # There's 3 kinds of references to python, self.executable, |
| 56 # self.real_executable and self.naked_executable. It depends how python was |
| 57 # started. |
| 58 self.executable = sys.executable |
| 59 if sys.platform == 'darwin': |
| 60 # /usr/bin/python is a thunk executable that decides which version of |
| 61 # python gets executed. |
| 62 suffix = '.'.join(map(str, sys.version_info[0:2])) |
| 63 if os.access(self.executable + suffix, os.X_OK): |
| 64 # So it'll look like /usr/bin/python2.7 |
| 65 self.executable += suffix |
| 66 |
| 67 import trace_inputs |
| 68 self.real_executable = trace_inputs.get_native_path_case( |
| 69 unicode(self.executable)) |
| 70 trace_inputs = None |
| 71 |
| 72 # self.naked_executable will only be naked on Windows. |
| 73 self.naked_executable = unicode(sys.executable) |
| 74 if sys.platform == 'win32': |
| 75 self.naked_executable = os.path.basename(sys.executable) |
| 76 |
| 77 def tearDown(self): |
| 78 if VERBOSE: |
| 79 print 'Leaking: %s' % self.tempdir |
| 80 else: |
| 81 shutil.rmtree(self.tempdir) |
| 82 |
| 83 @staticmethod |
| 84 def get_child_command(from_data): |
| 85 """Returns command to run the child1.py.""" |
| 86 cmd = [sys.executable] |
| 87 if from_data: |
| 88 # When the gyp argument is specified, the command is started from --cwd |
| 89 # directory. In this case, 'tests'. |
| 90 cmd.extend([os.path.join('trace_inputs', 'child1.py'), '--child-gyp']) |
| 91 else: |
| 92 # When the gyp argument is not specified, the command is started from |
| 93 # --root-dir directory. |
| 94 cmd.extend([os.path.join(REL_DATA, 'child1.py'), '--child']) |
| 95 return cmd |
| 96 |
| 97 @staticmethod |
| 98 def _size(*args): |
| 99 return os.stat(os.path.join(ROOT_DIR, *args)).st_size |
| 100 |
| 101 |
| 102 class TraceInputs(TraceInputsBase): |
| 103 def _execute(self, mode, command, cwd): |
| 104 cmd = [ |
| 105 sys.executable, |
| 106 self.trace_inputs_path, |
| 107 mode, |
| 108 '--log', self.log, |
| 109 ] |
| 110 if VERBOSE: |
| 111 cmd.extend(['-v'] * 3) |
| 112 cmd.extend(command) |
| 113 logging.info('Command: %s' % ' '.join(cmd)) |
| 114 p = subprocess.Popen( |
| 115 cmd, |
| 116 stdout=subprocess.PIPE, |
| 117 stderr=subprocess.PIPE, |
| 118 cwd=cwd, |
| 119 universal_newlines=True) |
| 120 out, err = p.communicate() |
| 121 if VERBOSE: |
| 122 print err |
| 123 if p.returncode: |
| 124 raise CalledProcessError(p.returncode, cmd, out + err, cwd) |
| 125 return out or '' |
| 126 |
| 127 def _trace(self, from_data): |
| 128 if from_data: |
| 129 cwd = os.path.join(ROOT_DIR, 'tests') |
| 130 else: |
| 131 cwd = ROOT_DIR |
| 132 return self._execute('trace', self.get_child_command(from_data), cwd=cwd) |
| 133 |
| 134 def test_trace(self): |
| 135 expected = '\n'.join(( |
| 136 'Total: 7', |
| 137 'Non existent: 0', |
| 138 'Interesting: 7 reduced to 6', |
| 139 ' tests/trace_inputs/child1.py'.replace('/', os.path.sep), |
| 140 ' tests/trace_inputs/child2.py'.replace('/', os.path.sep), |
| 141 ' tests/trace_inputs/files1/'.replace('/', os.path.sep), |
| 142 ' tests/trace_inputs/test_file.txt'.replace('/', os.path.sep), |
| 143 (' tests/%s' % FILENAME).replace('/', os.path.sep), |
| 144 ' trace_inputs.py', |
| 145 )) + '\n' |
| 146 trace_expected = '\n'.join(( |
| 147 'child from %s' % ROOT_DIR, |
| 148 'child2', |
| 149 )) + '\n' |
| 150 trace_actual = self._trace(False) |
| 151 actual = self._execute( |
| 152 'read', |
| 153 [ |
| 154 '--root-dir', ROOT_DIR, |
| 155 '--blacklist', '.+\\.pyc', |
| 156 '--blacklist', '.*\\.svn', |
| 157 '--blacklist', '.*do_not_care\\.txt', |
| 158 ], |
| 159 cwd=ROOT_DIR) |
| 160 self.assertEquals(expected, actual) |
| 161 self.assertEquals(trace_expected, trace_actual) |
| 162 |
| 163 def test_trace_json(self): |
| 164 expected = { |
| 165 u'root': { |
| 166 u'children': [ |
| 167 { |
| 168 u'children': [], |
| 169 u'command': [u'python', u'child2.py'], |
| 170 u'executable': self.naked_executable, |
| 171 u'files': [ |
| 172 { |
| 173 u'path': os.path.join(REL_DATA, 'child2.py'), |
| 174 u'size': self._size(REL_DATA, 'child2.py'), |
| 175 }, |
| 176 { |
| 177 u'path': os.path.join(REL_DATA, 'files1', 'bar'), |
| 178 u'size': self._size(REL_DATA, 'files1', 'bar'), |
| 179 }, |
| 180 { |
| 181 u'path': os.path.join(REL_DATA, 'files1', 'foo'), |
| 182 u'size': self._size(REL_DATA, 'files1', 'foo'), |
| 183 }, |
| 184 { |
| 185 u'path': os.path.join(REL_DATA, 'test_file.txt'), |
| 186 u'size': self._size(REL_DATA, 'test_file.txt'), |
| 187 }, |
| 188 ], |
| 189 u'initial_cwd': self.initial_cwd, |
| 190 #u'pid': 123, |
| 191 }, |
| 192 ], |
| 193 u'command': [ |
| 194 unicode(self.executable), |
| 195 os.path.join(u'trace_inputs', 'child1.py'), |
| 196 u'--child-gyp', |
| 197 ], |
| 198 u'executable': self.real_executable, |
| 199 u'files': [ |
| 200 { |
| 201 u'path': os.path.join(REL_DATA, 'child1.py'), |
| 202 u'size': self._size(REL_DATA, 'child1.py'), |
| 203 }, |
| 204 { |
| 205 u'path': os.path.join(u'tests', u'trace_inputs_smoke_test.py'), |
| 206 u'size': self._size('tests', 'trace_inputs_smoke_test.py'), |
| 207 }, |
| 208 { |
| 209 u'path': u'trace_inputs.py', |
| 210 u'size': self._size('trace_inputs.py'), |
| 211 }, |
| 212 ], |
| 213 u'initial_cwd': self.initial_cwd, |
| 214 #u'pid': 123, |
| 215 }, |
| 216 } |
| 217 trace_expected = '\n'.join(( |
| 218 'child_gyp from %s' % os.path.join(ROOT_DIR, 'tests'), |
| 219 'child2', |
| 220 )) + '\n' |
| 221 trace_actual = self._trace(True) |
| 222 actual_text = self._execute( |
| 223 'read', |
| 224 [ |
| 225 '--root-dir', ROOT_DIR, |
| 226 '--blacklist', '.+\\.pyc', |
| 227 '--blacklist', '.*\\.svn', |
| 228 '--blacklist', '.*do_not_care\\.txt', |
| 229 '--json', |
| 230 ], |
| 231 cwd=ROOT_DIR) |
| 232 actual_json = json.loads(actual_text) |
| 233 self.assertEquals(list, actual_json.__class__) |
| 234 self.assertEquals(1, len(actual_json)) |
| 235 actual_json = actual_json[0] |
| 236 # Removes the pids. |
| 237 self.assertTrue(actual_json['root'].pop('pid')) |
| 238 self.assertTrue(actual_json['root']['children'][0].pop('pid')) |
| 239 self.assertEquals(expected, actual_json) |
| 240 self.assertEquals(trace_expected, trace_actual) |
| 241 |
| 242 |
| 243 class TraceInputsImport(TraceInputsBase): |
| 244 def setUp(self): |
| 245 super(TraceInputsImport, self).setUp() |
| 246 import trace_inputs |
| 247 self.trace_inputs = trace_inputs |
| 248 |
| 249 def tearDown(self): |
| 250 del self.trace_inputs |
| 251 super(TraceInputsImport, self).tearDown() |
| 252 |
| 253 # Similar to TraceInputs test fixture except that it calls the function |
| 254 # directly, so the Results instance can be inspected. |
| 255 # Roughly, make sure the API is stable. |
| 256 def _execute_trace(self, command): |
| 257 # Similar to what trace_test_cases.py does. |
| 258 api = self.trace_inputs.get_api() |
| 259 _, _ = self.trace_inputs.trace( |
| 260 self.log, command, self.cwd, api, True) |
| 261 # TODO(maruel): Check |
| 262 #self.assertEquals(0, returncode) |
| 263 #self.assertEquals('', output) |
| 264 def blacklist(f): |
| 265 return f.endswith(('.pyc', '.svn', 'do_not_care.txt')) |
| 266 return self.trace_inputs.load_trace(self.log, ROOT_DIR, api, blacklist) |
| 267 |
| 268 def _gen_dict_wrong_path(self): |
| 269 """Returns the expected flattened Results when child1.py is called with the |
| 270 wrong relative path. |
| 271 """ |
| 272 return { |
| 273 'root': { |
| 274 'children': [], |
| 275 'command': [ |
| 276 self.executable, |
| 277 os.path.join(REL_DATA, 'child1.py'), |
| 278 '--child', |
| 279 ], |
| 280 'executable': self.real_executable, |
| 281 'files': [], |
| 282 'initial_cwd': self.initial_cwd, |
| 283 }, |
| 284 } |
| 285 |
| 286 def _gen_dict_full(self): |
| 287 """Returns the expected flattened Results when child1.py is called with |
| 288 --child. |
| 289 """ |
| 290 return { |
| 291 'root': { |
| 292 'children': [ |
| 293 { |
| 294 'children': [], |
| 295 'command': ['python', 'child2.py'], |
| 296 'executable': self.naked_executable, |
| 297 'files': [ |
| 298 { |
| 299 'path': os.path.join(REL_DATA, 'child2.py'), |
| 300 'size': self._size(REL_DATA, 'child2.py'), |
| 301 }, |
| 302 { |
| 303 'path': os.path.join(REL_DATA, 'files1', 'bar'), |
| 304 'size': self._size(REL_DATA, 'files1', 'bar'), |
| 305 }, |
| 306 { |
| 307 'path': os.path.join(REL_DATA, 'files1', 'foo'), |
| 308 'size': self._size(REL_DATA, 'files1', 'foo'), |
| 309 }, |
| 310 { |
| 311 'path': os.path.join(REL_DATA, 'test_file.txt'), |
| 312 'size': self._size(REL_DATA, 'test_file.txt'), |
| 313 }, |
| 314 ], |
| 315 'initial_cwd': self.expected_cwd, |
| 316 }, |
| 317 ], |
| 318 'command': [ |
| 319 self.executable, |
| 320 os.path.join(REL_DATA, 'child1.py'), |
| 321 '--child', |
| 322 ], |
| 323 'executable': self.real_executable, |
| 324 'files': [ |
| 325 { |
| 326 'path': os.path.join(REL_DATA, 'child1.py'), |
| 327 'size': self._size(REL_DATA, 'child1.py'), |
| 328 }, |
| 329 { |
| 330 u'path': os.path.join(u'tests', u'trace_inputs_smoke_test.py'), |
| 331 'size': self._size('tests', 'trace_inputs_smoke_test.py'), |
| 332 }, |
| 333 { |
| 334 'path': u'trace_inputs.py', |
| 335 'size': self._size('trace_inputs.py'), |
| 336 }, |
| 337 ], |
| 338 'initial_cwd': self.expected_cwd, |
| 339 }, |
| 340 } |
| 341 |
| 342 def _gen_dict_full_gyp(self): |
| 343 """Returns the expected flattened results when child1.py is called with |
| 344 --child-gyp. |
| 345 """ |
| 346 return { |
| 347 'root': { |
| 348 'children': [ |
| 349 { |
| 350 'children': [], |
| 351 'command': ['python', 'child2.py'], |
| 352 'executable': self.naked_executable, |
| 353 'files': [ |
| 354 { |
| 355 'path': os.path.join(REL_DATA, 'child2.py'), |
| 356 'size': self._size(REL_DATA, 'child2.py'), |
| 357 }, |
| 358 { |
| 359 'path': os.path.join(REL_DATA, 'files1', 'bar'), |
| 360 'size': self._size(REL_DATA, 'files1', 'bar'), |
| 361 }, |
| 362 { |
| 363 'path': os.path.join(REL_DATA, 'files1', 'foo'), |
| 364 'size': self._size(REL_DATA, 'files1', 'foo'), |
| 365 }, |
| 366 { |
| 367 'path': os.path.join(REL_DATA, 'test_file.txt'), |
| 368 'size': self._size(REL_DATA, 'test_file.txt'), |
| 369 }, |
| 370 ], |
| 371 'initial_cwd': self.initial_cwd, |
| 372 }, |
| 373 ], |
| 374 'command': [ |
| 375 self.executable, |
| 376 os.path.join('trace_inputs', 'child1.py'), |
| 377 '--child-gyp', |
| 378 ], |
| 379 'executable': self.real_executable, |
| 380 'files': [ |
| 381 { |
| 382 'path': os.path.join(REL_DATA, 'child1.py'), |
| 383 'size': self._size(REL_DATA, 'child1.py'), |
| 384 }, |
| 385 { |
| 386 'path': os.path.join(u'tests', u'trace_inputs_smoke_test.py'), |
| 387 'size': self._size('tests', 'trace_inputs_smoke_test.py'), |
| 388 }, |
| 389 { |
| 390 'path': u'trace_inputs.py', |
| 391 'size': self._size('trace_inputs.py'), |
| 392 }, |
| 393 ], |
| 394 'initial_cwd': self.initial_cwd, |
| 395 }, |
| 396 } |
| 397 |
| 398 def test_trace_wrong_path(self): |
| 399 # Deliberately start the trace from the wrong path. Starts it from the |
| 400 # directory 'tests' so 'tests/tests/trace_inputs/child1.py' is not |
| 401 # accessible, so child2.py process is not started. |
| 402 results = self._execute_trace(self.get_child_command(False)) |
| 403 expected = self._gen_dict_wrong_path() |
| 404 actual = results.flatten() |
| 405 self.assertTrue(actual['root'].pop('pid')) |
| 406 self.assertEquals(expected, actual) |
| 407 |
| 408 def test_trace(self): |
| 409 expected = self._gen_dict_full_gyp() |
| 410 results = self._execute_trace(self.get_child_command(True)) |
| 411 actual = results.flatten() |
| 412 self.assertTrue(actual['root'].pop('pid')) |
| 413 self.assertTrue(actual['root']['children'][0].pop('pid')) |
| 414 self.assertEquals(expected, actual) |
| 415 files = [ |
| 416 u'tests/trace_inputs/child1.py'.replace('/', os.path.sep), |
| 417 u'tests/trace_inputs/child2.py'.replace('/', os.path.sep), |
| 418 u'tests/trace_inputs/files1/'.replace('/', os.path.sep), |
| 419 u'tests/trace_inputs/test_file.txt'.replace('/', os.path.sep), |
| 420 u'tests/trace_inputs_smoke_test.py'.replace('/', os.path.sep), |
| 421 u'trace_inputs.py', |
| 422 ] |
| 423 def blacklist(f): |
| 424 return f.endswith(('.pyc', 'do_not_care.txt', '.git', '.svn')) |
| 425 simplified = self.trace_inputs.extract_directories( |
| 426 ROOT_DIR, results.files, blacklist) |
| 427 self.assertEquals(files, [f.path for f in simplified]) |
| 428 |
| 429 def test_trace_multiple(self): |
| 430 # Starts parallel threads and trace parallel child processes simultaneously. |
| 431 # Some are started from 'tests' directory, others from this script's |
| 432 # directory. One trace fails. Verify everything still goes one. |
| 433 parallel = 8 |
| 434 |
| 435 def trace(tracer, cmd, cwd, tracename): |
| 436 resultcode, output = tracer.trace( |
| 437 cmd, cwd, tracename, True) |
| 438 return (tracename, resultcode, output) |
| 439 |
| 440 with run_test_cases.ThreadPool(parallel) as pool: |
| 441 api = self.trace_inputs.get_api() |
| 442 with api.get_tracer(self.log) as tracer: |
| 443 pool.add_task( |
| 444 trace, tracer, self.get_child_command(False), ROOT_DIR, 'trace1') |
| 445 pool.add_task( |
| 446 trace, tracer, self.get_child_command(True), self.cwd, 'trace2') |
| 447 pool.add_task( |
| 448 trace, tracer, self.get_child_command(False), ROOT_DIR, 'trace3') |
| 449 pool.add_task( |
| 450 trace, tracer, self.get_child_command(True), self.cwd, 'trace4') |
| 451 # Have this one fail since it's started from the wrong directory. |
| 452 pool.add_task( |
| 453 trace, tracer, self.get_child_command(False), self.cwd, 'trace5') |
| 454 pool.add_task( |
| 455 trace, tracer, self.get_child_command(True), self.cwd, 'trace6') |
| 456 pool.add_task( |
| 457 trace, tracer, self.get_child_command(False), ROOT_DIR, 'trace7') |
| 458 pool.add_task( |
| 459 trace, tracer, self.get_child_command(True), self.cwd, 'trace8') |
| 460 trace_results = pool.join() |
| 461 def blacklist(f): |
| 462 return f.endswith(('.pyc', 'do_not_care.txt', '.git', '.svn')) |
| 463 actual_results = api.parse_log(self.log, blacklist) |
| 464 self.assertEquals(8, len(trace_results)) |
| 465 self.assertEquals(8, len(actual_results)) |
| 466 |
| 467 # Convert to dict keyed on the trace name, simpler to verify. |
| 468 trace_results = dict((i[0], i[1:]) for i in trace_results) |
| 469 actual_results = dict((x.pop('trace'), x) for x in actual_results) |
| 470 self.assertEquals(sorted(trace_results), sorted(actual_results)) |
| 471 |
| 472 # It'd be nice to start different kinds of processes. |
| 473 expected_results = [ |
| 474 self._gen_dict_full(), |
| 475 self._gen_dict_full_gyp(), |
| 476 self._gen_dict_full(), |
| 477 self._gen_dict_full_gyp(), |
| 478 self._gen_dict_wrong_path(), |
| 479 self._gen_dict_full_gyp(), |
| 480 self._gen_dict_full(), |
| 481 self._gen_dict_full_gyp(), |
| 482 ] |
| 483 self.assertEquals(len(expected_results), len(trace_results)) |
| 484 |
| 485 # See the comment above about the trace that fails because it's started from |
| 486 # the wrong directory. |
| 487 busted = 4 |
| 488 for index, key in enumerate(sorted(actual_results)): |
| 489 self.assertEquals('trace%d' % (index + 1), key) |
| 490 self.assertEquals(2, len(trace_results[key])) |
| 491 # returncode |
| 492 self.assertEquals(0 if index != busted else 2, trace_results[key][0]) |
| 493 # output |
| 494 self.assertEquals(actual_results[key]['output'], trace_results[key][1]) |
| 495 |
| 496 self.assertEquals(['output', 'results'], sorted(actual_results[key])) |
| 497 results = actual_results[key]['results'] |
| 498 results = results.strip_root(ROOT_DIR) |
| 499 actual = results.flatten() |
| 500 self.assertTrue(actual['root'].pop('pid')) |
| 501 if index != busted: |
| 502 self.assertTrue(actual['root']['children'][0].pop('pid')) |
| 503 self.assertEquals(expected_results[index], actual) |
| 504 |
| 505 if sys.platform != 'win32': |
| 506 def test_trace_symlink(self): |
| 507 expected = { |
| 508 'root': { |
| 509 'children': [], |
| 510 'command': [ |
| 511 self.executable, |
| 512 os.path.join('trace_inputs', 'symlink.py'), |
| 513 ], |
| 514 'executable': self.real_executable, |
| 515 'files': [ |
| 516 { |
| 517 'path': os.path.join(REL_DATA, 'files2', 'bar'), |
| 518 'size': self._size(REL_DATA, 'files2', 'bar'), |
| 519 }, |
| 520 { |
| 521 'path': os.path.join(REL_DATA, 'files2', 'foo'), |
| 522 'size': self._size(REL_DATA, 'files2', 'foo'), |
| 523 }, |
| 524 { |
| 525 'path': os.path.join(REL_DATA, 'symlink.py'), |
| 526 'size': self._size(REL_DATA, 'symlink.py'), |
| 527 }, |
| 528 ], |
| 529 'initial_cwd': self.initial_cwd, |
| 530 }, |
| 531 } |
| 532 cmd = [sys.executable, os.path.join('trace_inputs', 'symlink.py')] |
| 533 results = self._execute_trace(cmd) |
| 534 actual = results.flatten() |
| 535 self.assertTrue(actual['root'].pop('pid')) |
| 536 self.assertEquals(expected, actual) |
| 537 files = [ |
| 538 # In particular, the symlink is *not* resolved. |
| 539 u'tests/trace_inputs/files2/'.replace('/', os.path.sep), |
| 540 u'tests/trace_inputs/symlink.py'.replace('/', os.path.sep), |
| 541 ] |
| 542 def blacklist(f): |
| 543 return f.endswith(('.pyc', '.svn', 'do_not_care.txt')) |
| 544 simplified = self.trace_inputs.extract_directories( |
| 545 ROOT_DIR, results.files, blacklist) |
| 546 self.assertEquals(files, [f.path for f in simplified]) |
| 547 |
| 548 def test_trace_quoted(self): |
| 549 results = self._execute_trace([sys.executable, '-c', 'print("hi")']) |
| 550 expected = { |
| 551 'root': { |
| 552 'children': [], |
| 553 'command': [ |
| 554 self.executable, |
| 555 '-c', |
| 556 'print("hi")', |
| 557 ], |
| 558 'executable': self.real_executable, |
| 559 'files': [], |
| 560 'initial_cwd': self.initial_cwd, |
| 561 }, |
| 562 } |
| 563 actual = results.flatten() |
| 564 self.assertTrue(actual['root'].pop('pid')) |
| 565 self.assertEquals(expected, actual) |
| 566 |
| 567 def _touch_expected(self, command): |
| 568 # Looks for file that were touched but not opened, using different apis. |
| 569 results = self._execute_trace( |
| 570 [sys.executable, os.path.join('trace_inputs', 'touch_only.py'), command]) |
| 571 expected = { |
| 572 'root': { |
| 573 'children': [], |
| 574 'command': [ |
| 575 self.executable, |
| 576 os.path.join('trace_inputs', 'touch_only.py'), |
| 577 command, |
| 578 ], |
| 579 'executable': self.real_executable, |
| 580 'files': [ |
| 581 { |
| 582 'path': os.path.join(REL_DATA, 'test_file.txt'), |
| 583 'size': 0, |
| 584 }, |
| 585 { |
| 586 'path': os.path.join(REL_DATA, 'touch_only.py'), |
| 587 'size': self._size(REL_DATA, 'touch_only.py'), |
| 588 }, |
| 589 ], |
| 590 'initial_cwd': self.initial_cwd, |
| 591 }, |
| 592 } |
| 593 if sys.platform != 'linux2': |
| 594 # TODO(maruel): Remove once properly implemented. |
| 595 expected['root']['files'].pop(0) |
| 596 |
| 597 actual = results.flatten() |
| 598 self.assertTrue(actual['root'].pop('pid')) |
| 599 self.assertEquals(expected, actual) |
| 600 |
| 601 def test_trace_touch_only_access(self): |
| 602 self._touch_expected('access') |
| 603 |
| 604 def test_trace_touch_only_isfile(self): |
| 605 self._touch_expected('isfile') |
| 606 |
| 607 def test_trace_touch_only_stat(self): |
| 608 self._touch_expected('stat') |
| 609 |
| 610 |
| 611 if __name__ == '__main__': |
| 612 VERBOSE = '-v' in sys.argv |
| 613 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) |
| 614 unittest.main() |
OLD | NEW |