OLD | NEW |
1 # Copyright (c) 2010 Google Inc. All rights reserved. | 1 # Copyright (c) 2010 Google Inc. All rights reserved. |
2 # | 2 # |
3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
5 # met: | 5 # met: |
6 # | 6 # |
7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 fallback_path = port.baseline_search_path() | 361 fallback_path = port.baseline_search_path() |
362 if fallback_path not in builders_to_fallback_paths.values(): | 362 if fallback_path not in builders_to_fallback_paths.values(): |
363 builders_to_fallback_paths[builder] = fallback_path | 363 builders_to_fallback_paths[builder] = fallback_path |
364 return builders_to_fallback_paths.keys() | 364 return builders_to_fallback_paths.keys() |
365 | 365 |
366 def _rebaseline_commands(self, test_prefix_list, options): | 366 def _rebaseline_commands(self, test_prefix_list, options): |
367 path_to_webkit_patch = self._tool.path() | 367 path_to_webkit_patch = self._tool.path() |
368 cwd = self._tool.scm().checkout_root | 368 cwd = self._tool.scm().checkout_root |
369 copy_baseline_commands = [] | 369 copy_baseline_commands = [] |
370 rebaseline_commands = [] | 370 rebaseline_commands = [] |
| 371 lines_to_remove = {} |
371 port = self._tool.port_factory.get() | 372 port = self._tool.port_factory.get() |
372 | 373 |
373 for test_prefix in test_prefix_list: | 374 for test_prefix in test_prefix_list: |
374 for test in port.tests([test_prefix]): | 375 for test in port.tests([test_prefix]): |
375 for builder in self._builders_to_fetch_from(test_prefix_list[tes
t_prefix]): | 376 for builder in self._builders_to_fetch_from(test_prefix_list[tes
t_prefix]): |
376 actual_failures_suffixes = self._suffixes_for_actual_failure
s(test, builder, test_prefix_list[test_prefix][builder]) | 377 actual_failures_suffixes = self._suffixes_for_actual_failure
s(test, builder, test_prefix_list[test_prefix][builder]) |
377 if not actual_failures_suffixes: | 378 if not actual_failures_suffixes: |
| 379 # If we're not going to rebaseline the test because it's
passing on this |
| 380 # builder, we still want to remove the line from TestExp
ectations. |
| 381 if test not in lines_to_remove: |
| 382 lines_to_remove[test] = [] |
| 383 lines_to_remove[test].append(builder) |
378 continue | 384 continue |
379 | 385 |
380 suffixes = ','.join(actual_failures_suffixes) | 386 suffixes = ','.join(actual_failures_suffixes) |
381 cmd_line = ['--suffixes', suffixes, '--builder', builder, '-
-test', test] | 387 cmd_line = ['--suffixes', suffixes, '--builder', builder, '-
-test', test] |
382 if options.results_directory: | 388 if options.results_directory: |
383 cmd_line.extend(['--results-directory', options.results_
directory]) | 389 cmd_line.extend(['--results-directory', options.results_
directory]) |
384 if options.verbose: | 390 if options.verbose: |
385 cmd_line.append('--verbose') | 391 cmd_line.append('--verbose') |
386 copy_baseline_commands.append(tuple([[path_to_webkit_patch,
'copy-existing-baselines-internal'] + cmd_line, cwd])) | 392 copy_baseline_commands.append(tuple([[path_to_webkit_patch,
'copy-existing-baselines-internal'] + cmd_line, cwd])) |
387 rebaseline_commands.append(tuple([[path_to_webkit_patch, 're
baseline-test-internal'] + cmd_line, cwd])) | 393 rebaseline_commands.append(tuple([[path_to_webkit_patch, 're
baseline-test-internal'] + cmd_line, cwd])) |
388 return copy_baseline_commands, rebaseline_commands | 394 return copy_baseline_commands, rebaseline_commands, lines_to_remove |
389 | 395 |
390 def _serial_commands(self, command_results): | 396 def _serial_commands(self, command_results): |
391 files_to_add = set() | 397 files_to_add = set() |
392 files_to_delete = set() | 398 files_to_delete = set() |
393 lines_to_remove = {} | 399 lines_to_remove = {} |
394 for output in [result[1].split('\n') for result in command_results]: | 400 for output in [result[1].split('\n') for result in command_results]: |
395 file_added = False | 401 file_added = False |
396 for line in output: | 402 for line in output: |
397 try: | 403 try: |
398 if line: | 404 if line: |
(...skipping 29 matching lines...) Expand all Loading... |
428 cmd_line = ['--no-modify-scm', '--suffixes', ','.join(all_suffixes),
test] | 434 cmd_line = ['--no-modify-scm', '--suffixes', ','.join(all_suffixes),
test] |
429 if verbose: | 435 if verbose: |
430 cmd_line.append('--verbose') | 436 cmd_line.append('--verbose') |
431 | 437 |
432 path_to_webkit_patch = self._tool.path() | 438 path_to_webkit_patch = self._tool.path() |
433 cwd = self._tool.scm().checkout_root | 439 cwd = self._tool.scm().checkout_root |
434 optimize_commands.append(tuple([[path_to_webkit_patch, 'optimize-bas
elines'] + cmd_line, cwd])) | 440 optimize_commands.append(tuple([[path_to_webkit_patch, 'optimize-bas
elines'] + cmd_line, cwd])) |
435 return optimize_commands | 441 return optimize_commands |
436 | 442 |
437 def _update_expectations_files(self, lines_to_remove): | 443 def _update_expectations_files(self, lines_to_remove): |
438 # FIXME: This routine is way too expensive. We're creating N ports and N
TestExpectations | 444 # FIXME: This routine is way too expensive. We're creating O(n ports) Te
stExpectations objects. |
439 # objects and (re-)writing the actual expectations file N times, for eac
h test we update. | 445 # This is slow and uses a lot of memory. |
440 # We should be able to update everything in memory, once, and then write
the file out a single time. | 446 tests = lines_to_remove.keys() |
| 447 to_remove = [] |
| 448 |
| 449 # This is so we remove lines for builders that skip this test, e.g. Andr
oid skips most |
| 450 # tests and we don't want to leave stray [ Android ] lines in TestExpect
ations.. |
| 451 # FIXME: Is this necessary at all now that _rebaseline_commands includes
the builders that |
| 452 # used to be skipped because the result wasn't failing on tip of tree? |
| 453 for port_name in self._tool.port_factory.all_port_names(): |
| 454 port = self._tool.port_factory.get(port_name) |
| 455 generic_expectations = TestExpectations(port, tests=tests, include_o
verrides=False) |
| 456 full_expectations = TestExpectations(port, tests=tests, include_over
rides=True) |
| 457 for test in tests: |
| 458 if self._port_skips_test(port, test, generic_expectations, full_
expectations): |
| 459 for test_configuration in port.all_test_configurations(): |
| 460 if test_configuration.version == port.test_configuration
().version: |
| 461 to_remove.append((test, test_configuration)) |
| 462 |
441 for test in lines_to_remove: | 463 for test in lines_to_remove: |
442 for builder in lines_to_remove[test]: | 464 for builder in lines_to_remove[test]: |
443 port = self._tool.port_factory.get_from_builder_name(builder) | 465 port = self._tool.port_factory.get_from_builder_name(builder) |
444 path = port.path_to_generic_test_expectations_file() | |
445 expectations = TestExpectations(port, include_overrides=False) | |
446 for test_configuration in port.all_test_configurations(): | 466 for test_configuration in port.all_test_configurations(): |
447 if test_configuration.version == port.test_configuration().v
ersion: | 467 if test_configuration.version == port.test_configuration().v
ersion: |
448 expectationsString = expectations.remove_configuration_f
rom_test(test, test_configuration) | 468 to_remove.append((test, test_configuration)) |
449 self._tool.filesystem.write_text_file(path, expectationsString) | |
450 | 469 |
451 for port_name in self._tool.port_factory.all_port_names(): | 470 port = self._tool.port_factory.get() |
452 port = self._tool.port_factory.get(port_name) | 471 expectations = TestExpectations(port, include_overrides=False) |
453 generic_expectations = TestExpectations(port, tests=[test], incl
ude_overrides=False) | 472 expectationsString = expectations.remove_configurations(to_remove) |
454 if self._port_skips_test(port, test, generic_expectations): | 473 path = port.path_to_generic_test_expectations_file() |
455 for test_configuration in port.all_test_configurations(): | 474 self._tool.filesystem.write_text_file(path, expectationsString) |
456 if test_configuration.version == port.test_configuration
().version: | |
457 expectationsString = generic_expectations.remove_con
figuration_from_test(test, test_configuration) | |
458 generic_path = port.path_to_generic_test_expectations_file() | |
459 self._tool.filesystem.write_text_file(generic_path, expectat
ionsString) | |
460 | 475 |
461 def _port_skips_test(self, port, test, generic_expectations): | 476 def _port_skips_test(self, port, test, generic_expectations, full_expectatio
ns): |
462 fs = port.host.filesystem | 477 fs = port.host.filesystem |
463 if port.default_smoke_test_only(): | 478 if port.default_smoke_test_only(): |
464 smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests') | 479 smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests') |
465 if fs.exists(smoke_test_filename) and test not in fs.read_text_file(
smoke_test_filename): | 480 if fs.exists(smoke_test_filename) and test not in fs.read_text_file(
smoke_test_filename): |
466 return True | 481 return True |
467 | 482 |
468 full_expectations = TestExpectations(port, tests=[test], include_overrid
es=True) | |
469 return (SKIP in full_expectations.get_expectations(test) and | 483 return (SKIP in full_expectations.get_expectations(test) and |
470 SKIP not in generic_expectations.get_expectations(test)) | 484 SKIP not in generic_expectations.get_expectations(test)) |
471 | 485 |
472 def _run_in_parallel_and_update_scm(self, commands): | 486 def _run_in_parallel_and_update_scm(self, commands): |
473 command_results = self._tool.executive.run_in_parallel(commands) | 487 command_results = self._tool.executive.run_in_parallel(commands) |
474 log_output = '\n'.join(result[2] for result in command_results).replace(
'\n\n', '\n') | 488 log_output = '\n'.join(result[2] for result in command_results).replace(
'\n\n', '\n') |
475 for line in log_output.split('\n'): | 489 for line in log_output.split('\n'): |
476 if line: | 490 if line: |
477 print >> sys.stderr, line # FIXME: Figure out how to log proper
ly. | 491 print >> sys.stderr, line # FIXME: Figure out how to log proper
ly. |
478 | 492 |
479 files_to_add, files_to_delete, lines_to_remove = self._serial_commands(c
ommand_results) | 493 files_to_add, files_to_delete, lines_to_remove = self._serial_commands(c
ommand_results) |
480 if files_to_delete: | 494 if files_to_delete: |
481 self._tool.scm().delete_list(files_to_delete) | 495 self._tool.scm().delete_list(files_to_delete) |
482 if files_to_add: | 496 if files_to_add: |
483 self._tool.scm().add_list(files_to_add) | 497 self._tool.scm().add_list(files_to_add) |
484 if lines_to_remove: | 498 return lines_to_remove |
485 self._update_expectations_files(lines_to_remove) | |
486 | 499 |
487 def _rebaseline(self, options, test_prefix_list): | 500 def _rebaseline(self, options, test_prefix_list): |
488 for test, builders_to_check in sorted(test_prefix_list.items()): | 501 for test, builders_to_check in sorted(test_prefix_list.items()): |
489 _log.info("Rebaselining %s" % test) | 502 _log.info("Rebaselining %s" % test) |
490 for builder, suffixes in sorted(builders_to_check.items()): | 503 for builder, suffixes in sorted(builders_to_check.items()): |
491 _log.debug(" %s: %s" % (builder, ",".join(suffixes))) | 504 _log.debug(" %s: %s" % (builder, ",".join(suffixes))) |
492 | 505 |
493 copy_baseline_commands, rebaseline_commands = self._rebaseline_commands(
test_prefix_list, options) | 506 copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = sel
f._rebaseline_commands(test_prefix_list, options) |
| 507 lines_to_remove = {} |
| 508 |
494 if copy_baseline_commands: | 509 if copy_baseline_commands: |
495 self._run_in_parallel_and_update_scm(copy_baseline_commands) | 510 self._run_in_parallel_and_update_scm(copy_baseline_commands) |
496 if rebaseline_commands: | 511 if rebaseline_commands: |
497 self._run_in_parallel_and_update_scm(rebaseline_commands) | 512 lines_to_remove = self._run_in_parallel_and_update_scm(rebaseline_co
mmands) |
| 513 |
| 514 for test in extra_lines_to_remove: |
| 515 if test in lines_to_remove: |
| 516 lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_r
emove[test] |
| 517 else: |
| 518 lines_to_remove[test] = extra_lines_to_remove[test] |
| 519 |
| 520 if lines_to_remove: |
| 521 self._update_expectations_files(lines_to_remove) |
| 522 |
498 if options.optimize: | 523 if options.optimize: |
499 self._run_in_parallel_and_update_scm(self._optimize_baselines(test_p
refix_list, options.verbose)) | 524 self._run_in_parallel_and_update_scm(self._optimize_baselines(test_p
refix_list, options.verbose)) |
500 | 525 |
501 def _suffixes_for_actual_failures(self, test, builder_name, existing_suffixe
s): | 526 def _suffixes_for_actual_failures(self, test, builder_name, existing_suffixe
s): |
502 actual_results = self.builder_data()[builder_name].actual_results(test) | 527 actual_results = self.builder_data()[builder_name].actual_results(test) |
503 if not actual_results: | 528 if not actual_results: |
504 return set() | 529 return set() |
505 return set(existing_suffixes) & TestExpectations.suffixes_for_actual_exp
ectations_string(actual_results) | 530 return set(existing_suffixes) & TestExpectations.suffixes_for_actual_exp
ectations_string(actual_results) |
506 | 531 |
507 | 532 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 | 883 |
859 try: | 884 try: |
860 old_branch_name = tool.scm().current_branch() | 885 old_branch_name = tool.scm().current_branch() |
861 tool.scm().delete_branch(self.AUTO_REBASELINE_BRANCH_NAME) | 886 tool.scm().delete_branch(self.AUTO_REBASELINE_BRANCH_NAME) |
862 tool.scm().create_clean_branch(self.AUTO_REBASELINE_BRANCH_NAME) | 887 tool.scm().create_clean_branch(self.AUTO_REBASELINE_BRANCH_NAME) |
863 | 888 |
864 # If the tests are passing everywhere, then this list will be empty.
We don't need | 889 # If the tests are passing everywhere, then this list will be empty.
We don't need |
865 # to rebaseline, but we'll still need to update TestExpectations. | 890 # to rebaseline, but we'll still need to update TestExpectations. |
866 if test_prefix_list: | 891 if test_prefix_list: |
867 self._rebaseline(options, test_prefix_list) | 892 self._rebaseline(options, test_prefix_list) |
868 # If a test is not failing on the bot, we don't try to rebaseline it
, but we still | |
869 # want to remove the NeedsRebaseline line. | |
870 self._update_expectations_files(lines_to_remove) | |
871 | 893 |
872 tool.scm().commit_locally_with_message(self.commit_message(author, r
evision, bugs)) | 894 tool.scm().commit_locally_with_message(self.commit_message(author, r
evision, bugs)) |
873 | 895 |
874 # FIXME: It would be nice if we could dcommit the patch without uplo
ading, but still | 896 # FIXME: It would be nice if we could dcommit the patch without uplo
ading, but still |
875 # go through all the precommit hooks. For rebaselines with lots of f
iles, uploading | 897 # go through all the precommit hooks. For rebaselines with lots of f
iles, uploading |
876 # takes a long time and sometimes fails, but we don't want to commit
if, e.g. the | 898 # takes a long time and sometimes fails, but we don't want to commit
if, e.g. the |
877 # tree is closed. | 899 # tree is closed. |
878 did_finish = self._run_git_cl_command(options, ['upload', '-f']) | 900 did_finish = self._run_git_cl_command(options, ['upload', '-f']) |
879 | 901 |
880 if did_finish: | 902 if did_finish: |
(...skipping 26 matching lines...) Expand all Loading... |
907 if options.verbose: | 929 if options.verbose: |
908 rebaseline_command.append('--verbose') | 930 rebaseline_command.append('--verbose') |
909 # Use call instead of run_command so that stdout doesn't get swa
llowed. | 931 # Use call instead of run_command so that stdout doesn't get swa
llowed. |
910 tool.executive.call(rebaseline_command) | 932 tool.executive.call(rebaseline_command) |
911 except: | 933 except: |
912 traceback.print_exc(file=sys.stderr) | 934 traceback.print_exc(file=sys.stderr) |
913 # Sometimes git crashes and leaves us on a detached head. | 935 # Sometimes git crashes and leaves us on a detached head. |
914 tool.scm().checkout_branch(old_branch_name) | 936 tool.scm().checkout_branch(old_branch_name) |
915 | 937 |
916 time.sleep(self.SLEEP_TIME_IN_SECONDS) | 938 time.sleep(self.SLEEP_TIME_IN_SECONDS) |
OLD | NEW |