Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: tools/command_tester.py

Issue 8439032: Add option to command tester for running a test multiple times. Use that (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: precommit Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tests/browser_startup_time/nacl.scons ('k') | tools/process_perf_combined.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2011 The Native Client Authors. All rights reserved. 2 # Copyright (c) 2011 The Native Client 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 6
7 """Simple testing harness for running commands and checking expected output. 7 """Simple testing harness for running commands and checking expected output.
8 8
9 This harness is used instead of shell scripts to ensure windows compatibility 9 This harness is used instead of shell scripts to ensure windows compatibility
10 10
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 98
99 # This option must be '1' for the output to be captured, for checking 99 # This option must be '1' for the output to be captured, for checking
100 # against golden files, special exit_status signals, etc. 100 # against golden files, special exit_status signals, etc.
101 # When this option is '0', stdout and stderr will be streamed out. 101 # When this option is '0', stdout and stderr will be streamed out.
102 'capture_output': '1', 102 'capture_output': '1',
103 103
104 'filter_regex': None, 104 'filter_regex': None,
105 'filter_inverse': False, 105 'filter_inverse': False,
106 'filter_group_only': False, 106 'filter_group_only': False,
107 107
108 # Script for processing output along with its arguments. 108 # Number of times a test is run.
109 'process_output': '', 109 # This is useful for getting multiple samples for time perf tests.
110 'num_runs': 1,
111
112 # Scripts for processing output along with its arguments.
113 # This script is given the output of a single run.
114 'process_output_single': None,
115 # This script is given the concatenated output of all |num_runs|, after
116 # having been filtered by |process_output_single| for individual runs.
117 'process_output_combined': None,
110 118
111 'time_warning': 0, 119 'time_warning': 0,
112 'time_error': 0, 120 'time_error': 0,
113 121
114 'run_under': None, 122 'run_under': None,
115 } 123 }
116 124
117 def StringifyList(lst): 125 def StringifyList(lst):
118 return ','.join(lst) 126 return ','.join(lst)
119 127
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 words[0] == 'qemu:' and words[1] == 'uncaught' and 311 words[0] == 'qemu:' and words[1] == 'uncaught' and
304 words[2] == 'target' and words[3] == 'signal'): 312 words[2] == 'target' and words[3] == 'signal'):
305 return -int(words[4]) 313 return -int(words[4])
306 return default 314 return default
307 315
308 def FormatExitStatus(number): 316 def FormatExitStatus(number):
309 # Include the hex version because it makes the Windows error exit 317 # Include the hex version because it makes the Windows error exit
310 # statuses (STATUS_*) more recognisable. 318 # statuses (STATUS_*) more recognisable.
311 return '%i (0x%x)' % (number, number & 0xffffffff) 319 return '%i (0x%x)' % (number, number & 0xffffffff)
312 320
321 def PrintStdStreams(stdout, stderr):
322 if stderr is not None:
323 Banner('Stdout for %s:' % os.path.basename(GlobalSettings['name']))
324 Print(stdout)
325 Banner('Stderr for %s:' % os.path.basename(GlobalSettings['name']))
326 Print(stderr)
327
313 def CheckExitStatus(failed, req_status, using_nacl_signal_handler, 328 def CheckExitStatus(failed, req_status, using_nacl_signal_handler,
314 exit_status, stdout, stderr): 329 exit_status, stdout, stderr):
315 expected_sigtype = 'normal' 330 expected_sigtype = 'normal'
316 if req_status in status_map: 331 if req_status in status_map:
317 expected_statuses = status_map[req_status][GlobalPlatform] 332 expected_statuses = status_map[req_status][GlobalPlatform]
318 if using_nacl_signal_handler: 333 if using_nacl_signal_handler:
319 if req_status.startswith('trusted_'): 334 if req_status.startswith('trusted_'):
320 expected_sigtype = 'trusted' 335 expected_sigtype = 'trusted'
321 elif req_status.startswith('untrusted_'): 336 elif req_status.startswith('untrusted_'):
322 expected_sigtype = 'untrusted' 337 expected_sigtype = 'untrusted'
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 expected_printed = (expected_printed_signum, expected_sigtype) 376 expected_printed = (expected_printed_signum, expected_sigtype)
362 actual_printed = GetNaClSignalInfoFromStderr(stderr) 377 actual_printed = GetNaClSignalInfoFromStderr(stderr)
363 msg = ('\nERROR: Command printed the signal info %s to stderr ' 378 msg = ('\nERROR: Command printed the signal info %s to stderr '
364 'but we expected %s' % 379 'but we expected %s' %
365 (actual_printed, expected_printed)) 380 (actual_printed, expected_printed))
366 if actual_printed != expected_printed: 381 if actual_printed != expected_printed:
367 Print(msg) 382 Print(msg)
368 failed = True 383 failed = True
369 384
370 if failed: 385 if failed:
371 if stderr is not None: 386 PrintStdStreams(stdout, stderr)
372 Banner('Stdout')
373 Print(stdout)
374 Banner('Stderr')
375 Print(stderr)
376 return not failed 387 return not failed
377 388
378 def CheckTimeBounds(total_time): 389 def CheckTimeBounds(total_time):
379 if GlobalSettings['time_error']: 390 if GlobalSettings['time_error']:
380 if total_time > GlobalSettings['time_error']: 391 if total_time > GlobalSettings['time_error']:
381 Print('ERROR: should have taken less than %f secs' % 392 Print('ERROR: should have taken less than %f secs' %
382 (GlobalSettings['time_error'])) 393 (GlobalSettings['time_error']))
383 return False 394 return False
384 395
385 if GlobalSettings['time_warning']: 396 if GlobalSettings['time_warning']:
(...skipping 14 matching lines...) Expand all
400 actual = getter() 411 actual = getter()
401 if GlobalSettings['filter_regex']: 412 if GlobalSettings['filter_regex']:
402 actual = test_lib.RegexpFilterLines(GlobalSettings['filter_regex'], 413 actual = test_lib.RegexpFilterLines(GlobalSettings['filter_regex'],
403 GlobalSettings['filter_inverse'], 414 GlobalSettings['filter_inverse'],
404 GlobalSettings['filter_group_only'], 415 GlobalSettings['filter_group_only'],
405 actual) 416 actual)
406 if DifferentFromGolden(actual, golden_data, stream): 417 if DifferentFromGolden(actual, golden_data, stream):
407 return False 418 return False
408 return True 419 return True
409 420
410 def ProcessLogOutput(stdout, stderr): 421 def ProcessLogOutputSingle(stdout, stderr):
411 output_processor = GlobalSettings['process_output'] 422 output_processor = GlobalSettings['process_output_single']
412 if output_processor: 423 if output_processor is None:
424 return (True, stdout, stderr)
425 else:
413 output_processor_cmd = DestringifyList(output_processor) 426 output_processor_cmd = DestringifyList(output_processor)
414 # Also, get the output from logout (to get NaClLog output in Windows). 427 # Also, get the output from log_file to get NaClLog output in Windows.
415 log_output = open(GlobalSettings['log_file']).read() 428 log_output = open(GlobalSettings['log_file']).read()
416 # Assume the log processor does not care about the order of the lines. 429 # Assume the log processor does not care about the order of the lines.
417 all_output = log_output + stdout + stderr 430 all_output = log_output + stdout + stderr
418 if not test_lib.RunCmdWithInput(output_processor_cmd, all_output): 431 _, retcode, failed, new_stdout, new_stderr = \
432 test_lib.RunTestWithInputOutput(output_processor_cmd, all_output)
433 # Print the result, since we have done some processing and we need
434 # to have the processed data. However, if we intend to process it some
435 # more later via process_output_combined, do not duplicate the data here.
436 # Only print out the final result!
437 if not GlobalSettings['process_output_combined']:
438 PrintStdStreams(new_stdout, new_stderr)
439 if retcode != 0 or failed:
440 return (False, new_stdout, new_stderr)
441 else:
442 return (True, new_stdout, new_stderr)
443
444 def ProcessLogOutputCombined(stdout, stderr):
445 output_processor = GlobalSettings['process_output_combined']
446 if output_processor is None:
447 return True
448 else:
449 output_processor_cmd = DestringifyList(output_processor)
450 all_output = stdout + stderr
451 _, retcode, failed, new_stdout, new_stderr = \
452 test_lib.RunTestWithInputOutput(output_processor_cmd, all_output)
453 # Print the result, since we have done some processing.
454 PrintStdStreams(new_stdout, new_stderr)
455 if retcode != 0 or failed:
419 return False 456 return False
420 return True 457 else:
458 return True
421 459
422 def main(argv): 460 def DoRun(command, stdin_data):
423 global GlobalPlatform 461 """
424 global GlobalReportStream 462 Run the command, given stdin_data. Returns a return code (0 is good)
425 command = ProcessOptions(argv) 463 and optionally a captured version of stdout, stderr from the run
426 464 (if the global setting capture_output is true).
427 if GlobalSettings['report']: 465 """
428 GlobalReportStream.append(open(GlobalSettings['report'], 'w')) 466 # Initialize stdout, stderr to indicate we have not captured
429 467 # any of stdout or stderr.
430 if not GlobalSettings['name']: 468 stdout = ''
431 GlobalSettings['name'] = command[0] 469 stderr = ''
432 GlobalSettings['name'] = os.path.basename(GlobalSettings['name'])
433
434 Print(RunMessage())
435
436 if GlobalSettings['osenv']:
437 Banner('setting environment')
438 env_vars = DestringifyList(GlobalSettings['osenv'])
439 else:
440 env_vars = []
441 for env_var in env_vars:
442 key, val = env_var.split('=', 1)
443 Print('[%s] = [%s]' % (key, val))
444 os.putenv(key, val)
445
446 stdin_data = ''
447 if GlobalSettings['stdin']:
448 stdin_data = open(GlobalSettings['stdin'])
449
450 if GlobalSettings['log_file']:
451 try:
452 os.unlink(GlobalSettings['log_file']) # might not pre-exist
453 except OSError:
454 pass
455
456 run_under = GlobalSettings['run_under']
457 if run_under:
458 command = run_under.split(',') + command
459
460 Banner('running %s' % str(command))
461 # print the command in copy-and-pastable fashion
462 print " ".join(env_vars + command)
463
464 if not int(GlobalSettings['capture_output']): 470 if not int(GlobalSettings['capture_output']):
465 # We are only blurting out the stdout and stderr, not capturing it 471 # We are only blurting out the stdout and stderr, not capturing it
466 # for comparison, etc. 472 # for comparison, etc.
467 assert (not GlobalSettings['stdout_golden'] 473 assert (not GlobalSettings['stdout_golden']
468 and not GlobalSettings['stderr_golden'] 474 and not GlobalSettings['stderr_golden']
469 and not GlobalSettings['log_golden'] 475 and not GlobalSettings['log_golden']
470 and not GlobalSettings['filter_regex'] 476 and not GlobalSettings['filter_regex']
471 and not GlobalSettings['filter_inverse'] 477 and not GlobalSettings['filter_inverse']
472 and not GlobalSettings['filter_group_only'] 478 and not GlobalSettings['filter_group_only']
473 and not GlobalSettings['process_output'] 479 and not GlobalSettings['process_output_single']
480 and not GlobalSettings['process_output_combined']
474 ) 481 )
475 # If python ever changes popen.stdout.read() to not risk deadlock, 482 # If python ever changes popen.stdout.read() to not risk deadlock,
476 # we could stream and capture, and use RunTestWithInputOutput instead. 483 # we could stream and capture, and use RunTestWithInputOutput instead.
477 (total_time, exit_status, failed) = test_lib.RunTestWithInput(command, 484 (total_time, exit_status, failed) = test_lib.RunTestWithInput(command,
478 stdin_data) 485 stdin_data)
479 PrintTotalTime(total_time) 486 PrintTotalTime(total_time)
480 if not CheckExitStatus(failed, 487 if not CheckExitStatus(failed,
481 GlobalSettings['exit_status'], 488 GlobalSettings['exit_status'],
482 GlobalSettings['using_nacl_signal_handler'], 489 GlobalSettings['using_nacl_signal_handler'],
483 exit_status, None, None): 490 exit_status, None, None):
484 Print(FailureMessage(total_time)) 491 Print(FailureMessage(total_time))
485 return -1 492 return (-1, stdout, stderr)
486 else: 493 else:
487 (total_time, exit_status, 494 (total_time, exit_status,
488 failed, stdout, stderr) = test_lib.RunTestWithInputOutput( 495 failed, stdout, stderr) = test_lib.RunTestWithInputOutput(
489 command, stdin_data) 496 command, stdin_data)
490 PrintTotalTime(total_time) 497 PrintTotalTime(total_time)
498 # CheckExitStatus may spew stdout/stderr when there is an error.
499 # Otherwise, we do not spew stdout/stderr in this case (capture_output).
491 if not CheckExitStatus(failed, 500 if not CheckExitStatus(failed,
492 GlobalSettings['exit_status'], 501 GlobalSettings['exit_status'],
493 GlobalSettings['using_nacl_signal_handler'], 502 GlobalSettings['using_nacl_signal_handler'],
494 exit_status, stdout, stderr): 503 exit_status, stdout, stderr):
495 Print(FailureMessage(total_time)) 504 Print(FailureMessage(total_time))
496 return -1 505 return (-1, stdout, stderr)
497 if not CheckGoldenOutput(stdout, stderr): 506 if not CheckGoldenOutput(stdout, stderr):
498 Print(FailureMessage(total_time)) 507 Print(FailureMessage(total_time))
499 return -1 508 return (-1, stdout, stderr)
500 if not ProcessLogOutput(stdout, stderr): 509 success, stdout, stderr = ProcessLogOutputSingle(stdout, stderr)
501 Print(FailureMessage(total_time)) 510 if not success:
502 return -1 511 Print(FailureMessage(total_time) + ' ProcessLogOutputSingle failed!')
512 return (-1, stdout, stderr)
503 513
504 if not CheckTimeBounds(total_time): 514 if not CheckTimeBounds(total_time):
505 Print(FailureMessage(total_time)) 515 Print(FailureMessage(total_time))
506 return -1 516 return (-1, stdout, stderr)
507 517
508 Print(SuccessMessage(total_time)) 518 Print(SuccessMessage(total_time))
519 return (0, stdout, stderr)
520
521
522 def Main(argv):
523 command = ProcessOptions(argv)
524
525 if GlobalSettings['report']:
526 GlobalReportStream.append(open(GlobalSettings['report'], 'w'))
527
528 if not GlobalSettings['name']:
529 GlobalSettings['name'] = command[0]
530 GlobalSettings['name'] = os.path.basename(GlobalSettings['name'])
531
532 Print(RunMessage())
533 num_runs = GlobalSettings['num_runs']
534 if num_runs > 1:
535 Print(' (running %d times)' % num_runs)
536
537 if GlobalSettings['osenv']:
538 Banner('setting environment')
539 env_vars = DestringifyList(GlobalSettings['osenv'])
540 else:
541 env_vars = []
542 for env_var in env_vars:
543 key, val = env_var.split('=', 1)
544 Print('[%s] = [%s]' % (key, val))
545 os.environ[key] = val
546
547 stdin_data = ''
548 if GlobalSettings['stdin']:
549 stdin_data = open(GlobalSettings['stdin'])
550
551 run_under = GlobalSettings['run_under']
552 if run_under:
553 command = run_under.split(',') + command
554
555 Banner('running %s' % str(command))
556 # print the command in copy-and-pastable fashion
557 print ' '.join(env_vars + command)
558
559 # Concatenate output when running multiple times (e.g., for timing).
560 combined_stdout = ''
561 combined_stderr = ''
562 cur_runs = 0
563 num_runs = GlobalSettings['num_runs']
564 while cur_runs < num_runs:
565 cur_runs += 1
566 # Clear out previous log_file.
567 if GlobalSettings['log_file']:
568 try:
569 os.unlink(GlobalSettings['log_file']) # might not pre-exist
570 except OSError:
571 pass
572 ret_code, stdout, stderr = DoRun(command, stdin_data)
573 if ret_code != 0:
574 return ret_code
575 combined_stdout += stdout
576 combined_stderr += stderr
577 # Process the log output after all the runs.
578 success = ProcessLogOutputCombined(combined_stdout, combined_stderr)
579 if not success:
580 # Bogus time, since only ProcessLogOutputCombined failed.
581 Print(FailureMessage(0.0) + ' ProcessLogOutputCombined failed!')
582 return -1
509 return 0 583 return 0
510 584
511
512 if __name__ == '__main__': 585 if __name__ == '__main__':
513 retval = main(sys.argv[1:]) 586 retval = Main(sys.argv[1:])
514 # Add some whitepsace to make the logs easier to read. 587 # Add some whitepsace to make the logs easier to read.
515 sys.stdout.write('\n\n') 588 sys.stdout.write('\n\n')
516 sys.exit(retval) 589 sys.exit(retval)
517
OLDNEW
« no previous file with comments | « tests/browser_startup_time/nacl.scons ('k') | tools/process_perf_combined.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698