OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2008 the V8 project authors. All rights reserved. | 3 # Copyright 2008 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 def __init__(self, exit_code, timed_out, stdout, stderr): | 324 def __init__(self, exit_code, timed_out, stdout, stderr): |
325 self.exit_code = exit_code | 325 self.exit_code = exit_code |
326 self.timed_out = timed_out | 326 self.timed_out = timed_out |
327 self.stdout = stdout | 327 self.stdout = stdout |
328 self.stderr = stderr | 328 self.stderr = stderr |
329 self.failed = None | 329 self.failed = None |
330 | 330 |
331 | 331 |
332 class TestCase(object): | 332 class TestCase(object): |
333 | 333 |
334 def __init__(self, context, path): | 334 def __init__(self, context, path, mode): |
335 self.path = path | 335 self.path = path |
336 self.context = context | 336 self.context = context |
337 self.duration = None | 337 self.duration = None |
| 338 self.mode = mode |
338 | 339 |
339 def IsNegative(self): | 340 def IsNegative(self): |
340 return False | 341 return False |
341 | 342 |
342 def CompareTime(self, other): | 343 def CompareTime(self, other): |
343 return cmp(other.duration, self.duration) | 344 return cmp(other.duration, self.duration) |
344 | 345 |
345 def DidFail(self, output): | 346 def DidFail(self, output): |
346 if output.failed is None: | 347 if output.failed is None: |
347 output.failed = self.IsFailureOutput(output) | 348 output.failed = self.IsFailureOutput(output) |
348 return output.failed | 349 return output.failed |
349 | 350 |
350 def IsFailureOutput(self, output): | 351 def IsFailureOutput(self, output): |
351 return output.exit_code != 0 | 352 return output.exit_code != 0 |
352 | 353 |
353 def GetSource(self): | 354 def GetSource(self): |
354 return "(no source available)" | 355 return "(no source available)" |
355 | 356 |
356 def RunCommand(self, command): | 357 def RunCommand(self, command): |
357 full_command = self.context.processor(command) | 358 full_command = self.context.processor(command) |
358 output = Execute(full_command, self.context, self.context.timeout) | 359 output = Execute(full_command, |
| 360 self.context, |
| 361 self.context.GetTimeout(self.mode)) |
359 self.Cleanup() | 362 self.Cleanup() |
360 return TestOutput(self, full_command, output) | 363 return TestOutput(self, |
| 364 full_command, |
| 365 output, |
| 366 self.context.store_unexpected_output) |
361 | 367 |
362 def BeforeRun(self): | 368 def BeforeRun(self): |
363 pass | 369 pass |
364 | 370 |
365 def AfterRun(self): | 371 def AfterRun(self, result): |
366 pass | 372 pass |
367 | 373 |
368 def Run(self): | 374 def Run(self): |
369 self.BeforeRun() | 375 self.BeforeRun() |
370 try: | 376 try: |
371 result = self.RunCommand(self.GetCommand()) | 377 result = self.RunCommand(self.GetCommand()) |
372 finally: | 378 finally: |
373 self.AfterRun() | 379 self.AfterRun(result) |
374 return result | 380 return result |
375 | 381 |
376 def Cleanup(self): | 382 def Cleanup(self): |
377 return | 383 return |
378 | 384 |
379 | 385 |
380 class TestOutput(object): | 386 class TestOutput(object): |
381 | 387 |
382 def __init__(self, test, command, output): | 388 def __init__(self, test, command, output, store_unexpected_output): |
383 self.test = test | 389 self.test = test |
384 self.command = command | 390 self.command = command |
385 self.output = output | 391 self.output = output |
| 392 self.store_unexpected_output = store_unexpected_output |
386 | 393 |
387 def UnexpectedOutput(self): | 394 def UnexpectedOutput(self): |
388 if self.HasCrashed(): | 395 if self.HasCrashed(): |
389 outcome = CRASH | 396 outcome = CRASH |
390 elif self.HasTimedOut(): | 397 elif self.HasTimedOut(): |
391 outcome = TIMEOUT | 398 outcome = TIMEOUT |
392 elif self.HasFailed(): | 399 elif self.HasFailed(): |
393 outcome = FAIL | 400 outcome = FAIL |
394 else: | 401 else: |
395 outcome = PASS | 402 outcome = PASS |
396 return not outcome in self.test.outcomes | 403 return not outcome in self.test.outcomes |
397 | 404 |
| 405 def HasPreciousOutput(self): |
| 406 return self.UnexpectedOutput() and self.store_unexpected_output |
| 407 |
398 def HasCrashed(self): | 408 def HasCrashed(self): |
399 if utils.IsWindows(): | 409 if utils.IsWindows(): |
400 return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.outpu
t.exit_code) | 410 return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.outpu
t.exit_code) |
401 else: | 411 else: |
402 # Timed out tests will have exit_code -signal.SIGTERM. | 412 # Timed out tests will have exit_code -signal.SIGTERM. |
403 if self.output.timed_out: | 413 if self.output.timed_out: |
404 return False | 414 return False |
405 return self.output.exit_code < 0 and \ | 415 return self.output.exit_code < 0 and \ |
406 self.output.exit_code != -signal.SIGABRT | 416 self.output.exit_code != -signal.SIGABRT |
407 | 417 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 | 560 |
551 class TestSuite(object): | 561 class TestSuite(object): |
552 | 562 |
553 def __init__(self, name): | 563 def __init__(self, name): |
554 self.name = name | 564 self.name = name |
555 | 565 |
556 def GetName(self): | 566 def GetName(self): |
557 return self.name | 567 return self.name |
558 | 568 |
559 | 569 |
| 570 # Use this to run several variants of the tests, e.g.: |
| 571 # VARIANT_FLAGS = [[], ['--always_compact', '--noflush_code']] |
| 572 VARIANT_FLAGS = [[]] |
| 573 |
| 574 |
560 class TestRepository(TestSuite): | 575 class TestRepository(TestSuite): |
561 | 576 |
562 def __init__(self, path): | 577 def __init__(self, path): |
563 normalized_path = abspath(path) | 578 normalized_path = abspath(path) |
564 super(TestRepository, self).__init__(basename(normalized_path)) | 579 super(TestRepository, self).__init__(basename(normalized_path)) |
565 self.path = normalized_path | 580 self.path = normalized_path |
566 self.is_loaded = False | 581 self.is_loaded = False |
567 self.config = None | 582 self.config = None |
568 | 583 |
569 def GetConfiguration(self, context): | 584 def GetConfiguration(self, context): |
570 if self.is_loaded: | 585 if self.is_loaded: |
571 return self.config | 586 return self.config |
572 self.is_loaded = True | 587 self.is_loaded = True |
573 file = None | 588 file = None |
574 try: | 589 try: |
575 (file, pathname, description) = imp.find_module('testcfg', [ self.path ]) | 590 (file, pathname, description) = imp.find_module('testcfg', [ self.path ]) |
576 module = imp.load_module('testcfg', file, pathname, description) | 591 module = imp.load_module('testcfg', file, pathname, description) |
577 self.config = module.GetConfiguration(context, self.path) | 592 self.config = module.GetConfiguration(context, self.path) |
578 finally: | 593 finally: |
579 if file: | 594 if file: |
580 file.close() | 595 file.close() |
581 return self.config | 596 return self.config |
582 | 597 |
583 def GetBuildRequirements(self, path, context): | 598 def GetBuildRequirements(self, path, context): |
584 return self.GetConfiguration(context).GetBuildRequirements() | 599 return self.GetConfiguration(context).GetBuildRequirements() |
585 | 600 |
586 def ListTests(self, current_path, path, context, mode): | 601 def AddTestsToList(self, result, current_path, path, context, mode): |
587 return self.GetConfiguration(context).ListTests(current_path, path, mode) | 602 for v in VARIANT_FLAGS: |
| 603 tests = self.GetConfiguration(context).ListTests(current_path, path, mode) |
| 604 for t in tests: t.variant_flags = v |
| 605 result += tests |
| 606 |
588 | 607 |
589 def GetTestStatus(self, context, sections, defs): | 608 def GetTestStatus(self, context, sections, defs): |
590 self.GetConfiguration(context).GetTestStatus(sections, defs) | 609 self.GetConfiguration(context).GetTestStatus(sections, defs) |
591 | 610 |
592 | 611 |
593 class LiteralTestSuite(TestSuite): | 612 class LiteralTestSuite(TestSuite): |
594 | 613 |
595 def __init__(self, tests): | 614 def __init__(self, tests): |
596 super(LiteralTestSuite, self).__init__('root') | 615 super(LiteralTestSuite, self).__init__('root') |
597 self.tests = tests | 616 self.tests = tests |
598 | 617 |
599 def GetBuildRequirements(self, path, context): | 618 def GetBuildRequirements(self, path, context): |
600 (name, rest) = CarCdr(path) | 619 (name, rest) = CarCdr(path) |
601 result = [ ] | 620 result = [ ] |
602 for test in self.tests: | 621 for test in self.tests: |
603 if not name or name.match(test.GetName()): | 622 if not name or name.match(test.GetName()): |
604 result += test.GetBuildRequirements(rest, context) | 623 result += test.GetBuildRequirements(rest, context) |
605 return result | 624 return result |
606 | 625 |
607 def ListTests(self, current_path, path, context, mode): | 626 def ListTests(self, current_path, path, context, mode): |
608 (name, rest) = CarCdr(path) | 627 (name, rest) = CarCdr(path) |
609 result = [ ] | 628 result = [ ] |
610 for test in self.tests: | 629 for test in self.tests: |
611 test_name = test.GetName() | 630 test_name = test.GetName() |
612 if not name or name.match(test_name): | 631 if not name or name.match(test_name): |
613 full_path = current_path + [test_name] | 632 full_path = current_path + [test_name] |
614 result += test.ListTests(full_path, path, context, mode) | 633 test.AddTestsToList(result, full_path, path, context, mode) |
615 return result | 634 return result |
616 | 635 |
617 def GetTestStatus(self, context, sections, defs): | 636 def GetTestStatus(self, context, sections, defs): |
618 for test in self.tests: | 637 for test in self.tests: |
619 test.GetTestStatus(context, sections, defs) | 638 test.GetTestStatus(context, sections, defs) |
620 | 639 |
621 | 640 |
622 SUFFIX = {'debug': '_g', 'release': ''} | 641 SUFFIX = { |
| 642 'debug' : '_g', |
| 643 'release' : '' } |
| 644 FLAGS = { |
| 645 'debug' : ['--enable-slow-asserts', '--debug-code', '--verify-heap'], |
| 646 'release' : []} |
| 647 TIMEOUT_SCALEFACTOR = { |
| 648 'debug' : 4, |
| 649 'release' : 1 } |
623 | 650 |
624 | 651 |
625 class Context(object): | 652 class Context(object): |
626 | 653 |
627 def __init__(self, workspace, buildspace, verbose, vm, timeout, processor, sup
press_dialogs): | 654 def __init__(self, workspace, buildspace, verbose, vm, timeout, processor, sup
press_dialogs, store_unexpected_output): |
628 self.workspace = workspace | 655 self.workspace = workspace |
629 self.buildspace = buildspace | 656 self.buildspace = buildspace |
630 self.verbose = verbose | 657 self.verbose = verbose |
631 self.vm_root = vm | 658 self.vm_root = vm |
632 self.timeout = timeout | 659 self.timeout = timeout |
633 self.processor = processor | 660 self.processor = processor |
634 self.suppress_dialogs = suppress_dialogs | 661 self.suppress_dialogs = suppress_dialogs |
| 662 self.store_unexpected_output = store_unexpected_output |
635 | 663 |
636 def GetVm(self, mode): | 664 def GetVm(self, mode): |
637 name = self.vm_root + SUFFIX[mode] | 665 name = self.vm_root + SUFFIX[mode] |
638 if utils.IsWindows() and not name.endswith('.exe'): | 666 if utils.IsWindows() and not name.endswith('.exe'): |
639 name = name + '.exe' | 667 name = name + '.exe' |
640 return name | 668 return name |
641 | 669 |
| 670 def GetVmCommand(self, testcase, mode): |
| 671 return [self.GetVm(mode)] + self.GetVmFlags(testcase, mode) |
| 672 |
| 673 def GetVmFlags(self, testcase, mode): |
| 674 return testcase.variant_flags + FLAGS[mode] |
| 675 |
| 676 def GetTimeout(self, mode): |
| 677 return self.timeout * TIMEOUT_SCALEFACTOR[mode] |
| 678 |
642 def RunTestCases(cases_to_run, progress, tasks): | 679 def RunTestCases(cases_to_run, progress, tasks): |
643 progress = PROGRESS_INDICATORS[progress](cases_to_run) | 680 progress = PROGRESS_INDICATORS[progress](cases_to_run) |
644 return progress.Run(tasks) | 681 return progress.Run(tasks) |
645 | 682 |
646 | 683 |
647 def BuildRequirements(context, requirements, mode, scons_flags): | 684 def BuildRequirements(context, requirements, mode, scons_flags): |
648 command_line = (['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)] | 685 command_line = (['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)] |
649 + requirements | 686 + requirements |
650 + scons_flags) | 687 + scons_flags) |
651 output = ExecuteNoCapture(command_line, context) | 688 output = ExecuteNoCapture(command_line, context) |
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 result.add_option("--warn-unused", help="Report unused rules", | 1151 result.add_option("--warn-unused", help="Report unused rules", |
1115 default=False, action="store_true") | 1152 default=False, action="store_true") |
1116 result.add_option("-j", help="The number of parallel tasks to run", | 1153 result.add_option("-j", help="The number of parallel tasks to run", |
1117 default=1, type="int") | 1154 default=1, type="int") |
1118 result.add_option("--time", help="Print timing information after running", | 1155 result.add_option("--time", help="Print timing information after running", |
1119 default=False, action="store_true") | 1156 default=False, action="store_true") |
1120 result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for cra
shing tests", | 1157 result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for cra
shing tests", |
1121 dest="suppress_dialogs", default=True, action="store_true") | 1158 dest="suppress_dialogs", default=True, action="store_true") |
1122 result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for c
rashing tests", | 1159 result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for c
rashing tests", |
1123 dest="suppress_dialogs", action="store_false") | 1160 dest="suppress_dialogs", action="store_false") |
1124 result.add_option("--shell", help="Path to V8 shell", default="shell"); | 1161 result.add_option("--shell", help="Path to V8 shell", default="shell") |
| 1162 result.add_option("--store-unexpected-output", |
| 1163 help="Store the temporary JS files from tests that fails", |
| 1164 dest="store_unexpected_output", default=True, action="store_true") |
| 1165 result.add_option("--no-store-unexpected-output", |
| 1166 help="Deletes the temporary JS files from tests that fails", |
| 1167 dest="store_unexpected_output", action="store_false") |
1125 return result | 1168 return result |
1126 | 1169 |
1127 | 1170 |
1128 def ProcessOptions(options): | 1171 def ProcessOptions(options): |
1129 global VERBOSE | 1172 global VERBOSE |
1130 VERBOSE = options.verbose | 1173 VERBOSE = options.verbose |
1131 options.mode = options.mode.split(',') | 1174 options.mode = options.mode.split(',') |
1132 for mode in options.mode: | 1175 for mode in options.mode: |
1133 if not mode in ['debug', 'release']: | 1176 if not mode in ['debug', 'release']: |
1134 print "Unknown mode %s" % mode | 1177 print "Unknown mode %s" % mode |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1251 paths.append(path) | 1294 paths.append(path) |
1252 | 1295 |
1253 # Check for --valgrind option. If enabled, we overwrite the special | 1296 # Check for --valgrind option. If enabled, we overwrite the special |
1254 # command flag with a command that uses the run-valgrind.py script. | 1297 # command flag with a command that uses the run-valgrind.py script. |
1255 if options.valgrind: | 1298 if options.valgrind: |
1256 run_valgrind = join(workspace, "tools", "run-valgrind.py") | 1299 run_valgrind = join(workspace, "tools", "run-valgrind.py") |
1257 options.special_command = "python -u " + run_valgrind + " @" | 1300 options.special_command = "python -u " + run_valgrind + " @" |
1258 | 1301 |
1259 shell = abspath(options.shell) | 1302 shell = abspath(options.shell) |
1260 buildspace = dirname(shell) | 1303 buildspace = dirname(shell) |
| 1304 |
1261 context = Context(workspace, buildspace, VERBOSE, | 1305 context = Context(workspace, buildspace, VERBOSE, |
1262 shell, | 1306 shell, |
1263 options.timeout, | 1307 options.timeout, |
1264 GetSpecialCommandProcessor(options.special_command), | 1308 GetSpecialCommandProcessor(options.special_command), |
1265 options.suppress_dialogs) | 1309 options.suppress_dialogs, |
| 1310 options.store_unexpected_output) |
1266 # First build the required targets | 1311 # First build the required targets |
1267 if not options.no_build: | 1312 if not options.no_build: |
1268 reqs = [ ] | 1313 reqs = [ ] |
1269 for path in paths: | 1314 for path in paths: |
1270 reqs += root.GetBuildRequirements(path, context) | 1315 reqs += root.GetBuildRequirements(path, context) |
1271 reqs = list(set(reqs)) | 1316 reqs = list(set(reqs)) |
1272 if len(reqs) > 0: | 1317 if len(reqs) > 0: |
1273 if options.j != 1: | 1318 if options.j != 1: |
1274 options.scons_flags += ['-j', str(options.j)] | 1319 options.scons_flags += ['-j', str(options.j)] |
1275 if not BuildRequirements(context, reqs, options.mode, options.scons_flags)
: | 1320 if not BuildRequirements(context, reqs, options.mode, options.scons_flags)
: |
1276 return 1 | 1321 return 1 |
1277 | 1322 |
1278 # Just return if we are only building the targets for running the tests. | 1323 # Just return if we are only building the targets for running the tests. |
1279 if options.build_only: | 1324 if options.build_only: |
1280 return 0 | 1325 return 0 |
1281 | 1326 |
1282 # Get status for tests | 1327 # Get status for tests |
1283 sections = [ ] | 1328 sections = [ ] |
1284 defs = { } | 1329 defs = { } |
1285 root.GetTestStatus(context, sections, defs) | 1330 root.GetTestStatus(context, sections, defs) |
1286 config = Configuration(sections, defs) | 1331 config = Configuration(sections, defs) |
1287 | 1332 |
1288 # List the tests | 1333 # List the tests |
1289 all_cases = [ ] | 1334 all_cases = [ ] |
1290 all_unused = [ ] | 1335 all_unused = [ ] |
1291 unclassified_tests = [ ] | 1336 unclassified_tests = [ ] |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1361 for entry in timed_tests[:20]: | 1406 for entry in timed_tests[:20]: |
1362 t = FormatTime(entry.duration) | 1407 t = FormatTime(entry.duration) |
1363 sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel())) | 1408 sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel())) |
1364 index += 1 | 1409 index += 1 |
1365 | 1410 |
1366 return result | 1411 return result |
1367 | 1412 |
1368 | 1413 |
1369 if __name__ == '__main__': | 1414 if __name__ == '__main__': |
1370 sys.exit(Main()) | 1415 sys.exit(Main()) |
OLD | NEW |