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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 N ports and N TestExpectations |
439 # objects and (re-)writing the actual expectations file N times, for eac h test we update. | 445 # objects and (re-)writing the actual expectations file N times, for eac h test we update. |
440 # We should be able to update everything in memory, once, and then write the file out a single time. | 446 # We should be able to update everything in memory, once, and then write the file out a single time. |
Dirk Pranke
2014/06/01 21:25:33
I think this is you fixing this FIXME, yes?
ojan
2014/06/02 01:41:15
Mostly. I updated it.
| |
447 tests = lines_to_remove.keys() | |
448 to_remove = [] | |
449 | |
450 for port_name in self._tool.port_factory.all_port_names(): | |
451 port = self._tool.port_factory.get(port_name) | |
452 generic_expectations = TestExpectations(port, tests=tests, include_o verrides=False) | |
eseidel
2014/06/01 04:03:42
Why don't we just always load TestExpectations wit
ojan
2014/06/01 04:26:33
That might work. I think that should be a separate
Dirk Pranke
2014/06/01 21:25:33
I think Eric's idea is a reasonable suggestion, bu
ojan
2014/06/02 01:41:15
+1
| |
453 full_expectations = TestExpectations(port, tests=tests, include_over rides=True) | |
454 for test in tests: | |
455 if self._port_skips_test(port, test, generic_expectations, full_ expectations): | |
456 for test_configuration in port.all_test_configurations(): | |
457 if test_configuration.version == port.test_configuration ().version: | |
458 to_remove.append((test, test_configuration)) | |
Dirk Pranke
2014/06/01 21:25:33
It seems like lines 454-458 could use a comment ex
ojan
2014/06/02 01:41:15
Yeah...I'm not 100% sure what this was for either.
| |
459 | |
441 for test in lines_to_remove: | 460 for test in lines_to_remove: |
442 for builder in lines_to_remove[test]: | 461 for builder in lines_to_remove[test]: |
443 port = self._tool.port_factory.get_from_builder_name(builder) | 462 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(): | 463 for test_configuration in port.all_test_configurations(): |
447 if test_configuration.version == port.test_configuration().v ersion: | 464 if test_configuration.version == port.test_configuration().v ersion: |
448 expectationsString = expectations.remove_configuration_f rom_test(test, test_configuration) | 465 to_remove.append((test, test_configuration)) |
449 self._tool.filesystem.write_text_file(path, expectationsString) | |
450 | 466 |
451 for port_name in self._tool.port_factory.all_port_names(): | 467 port = self._tool.port_factory.get() |
452 port = self._tool.port_factory.get(port_name) | 468 expectations = TestExpectations(port, include_overrides=False) |
453 generic_expectations = TestExpectations(port, tests=[test], incl ude_overrides=False) | 469 expectationsString = expectations.remove_configurations(to_remove) |
454 if self._port_skips_test(port, test, generic_expectations): | 470 path = port.path_to_generic_test_expectations_file() |
455 for test_configuration in port.all_test_configurations(): | 471 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 | 472 |
461 def _port_skips_test(self, port, test, generic_expectations): | 473 def _port_skips_test(self, port, test, generic_expectations, full_expectatio ns): |
462 fs = port.host.filesystem | 474 fs = port.host.filesystem |
463 if port.default_smoke_test_only(): | 475 if port.default_smoke_test_only(): |
464 smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests') | 476 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): | 477 if fs.exists(smoke_test_filename) and test not in fs.read_text_file( smoke_test_filename): |
466 return True | 478 return True |
467 | 479 |
468 full_expectations = TestExpectations(port, tests=[test], include_overrid es=True) | |
469 return (SKIP in full_expectations.get_expectations(test) and | 480 return (SKIP in full_expectations.get_expectations(test) and |
470 SKIP not in generic_expectations.get_expectations(test)) | 481 SKIP not in generic_expectations.get_expectations(test)) |
471 | 482 |
472 def _run_in_parallel_and_update_scm(self, commands): | 483 def _run_in_parallel_and_update_scm(self, commands, extra_lines_to_remove={} ): |
Dirk Pranke
2014/06/01 21:25:33
Is extra_lines_to_remove used in this routine? I d
ojan
2014/06/02 01:41:15
Whoops. Sorry, this was a leftover from an earlier
| |
473 command_results = self._tool.executive.run_in_parallel(commands) | 484 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') | 485 log_output = '\n'.join(result[2] for result in command_results).replace( '\n\n', '\n') |
475 for line in log_output.split('\n'): | 486 for line in log_output.split('\n'): |
476 if line: | 487 if line: |
477 print >> sys.stderr, line # FIXME: Figure out how to log proper ly. | 488 print >> sys.stderr, line # FIXME: Figure out how to log proper ly. |
478 | 489 |
479 files_to_add, files_to_delete, lines_to_remove = self._serial_commands(c ommand_results) | 490 files_to_add, files_to_delete, lines_to_remove = self._serial_commands(c ommand_results) |
491 | |
480 if files_to_delete: | 492 if files_to_delete: |
481 self._tool.scm().delete_list(files_to_delete) | 493 self._tool.scm().delete_list(files_to_delete) |
482 if files_to_add: | 494 if files_to_add: |
483 self._tool.scm().add_list(files_to_add) | 495 self._tool.scm().add_list(files_to_add) |
484 if lines_to_remove: | 496 return lines_to_remove |
485 self._update_expectations_files(lines_to_remove) | |
486 | 497 |
487 def _rebaseline(self, options, test_prefix_list): | 498 def _rebaseline(self, options, test_prefix_list): |
488 for test, builders_to_check in sorted(test_prefix_list.items()): | 499 for test, builders_to_check in sorted(test_prefix_list.items()): |
489 _log.info("Rebaselining %s" % test) | 500 _log.info("Rebaselining %s" % test) |
490 for builder, suffixes in sorted(builders_to_check.items()): | 501 for builder, suffixes in sorted(builders_to_check.items()): |
491 _log.debug(" %s: %s" % (builder, ",".join(suffixes))) | 502 _log.debug(" %s: %s" % (builder, ",".join(suffixes))) |
492 | 503 |
493 copy_baseline_commands, rebaseline_commands = self._rebaseline_commands( test_prefix_list, options) | 504 copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = sel f._rebaseline_commands(test_prefix_list, options) |
505 lines_to_remove = {} | |
506 | |
494 if copy_baseline_commands: | 507 if copy_baseline_commands: |
495 self._run_in_parallel_and_update_scm(copy_baseline_commands) | 508 self._run_in_parallel_and_update_scm(copy_baseline_commands) |
496 if rebaseline_commands: | 509 if rebaseline_commands: |
497 self._run_in_parallel_and_update_scm(rebaseline_commands) | 510 lines_to_remove = self._run_in_parallel_and_update_scm(rebaseline_co mmands) |
511 | |
512 for test in extra_lines_to_remove: | |
513 if test in lines_to_remove: | |
514 lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_r emove[test] | |
515 else: | |
516 lines_to_remove[test] = extra_lines_to_remove[test] | |
517 | |
518 if lines_to_remove: | |
519 self._update_expectations_files(lines_to_remove) | |
520 | |
498 if options.optimize: | 521 if options.optimize: |
499 self._run_in_parallel_and_update_scm(self._optimize_baselines(test_p refix_list, options.verbose)) | 522 self._run_in_parallel_and_update_scm(self._optimize_baselines(test_p refix_list, options.verbose)) |
500 | 523 |
501 def _suffixes_for_actual_failures(self, test, builder_name, existing_suffixe s): | 524 def _suffixes_for_actual_failures(self, test, builder_name, existing_suffixe s): |
502 actual_results = self.builder_data()[builder_name].actual_results(test) | 525 actual_results = self.builder_data()[builder_name].actual_results(test) |
503 if not actual_results: | 526 if not actual_results: |
504 return set() | 527 return set() |
505 return set(existing_suffixes) & TestExpectations.suffixes_for_actual_exp ectations_string(actual_results) | 528 return set(existing_suffixes) & TestExpectations.suffixes_for_actual_exp ectations_string(actual_results) |
506 | 529 |
507 | 530 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
858 | 881 |
859 try: | 882 try: |
860 old_branch_name = tool.scm().current_branch() | 883 old_branch_name = tool.scm().current_branch() |
861 tool.scm().delete_branch(self.AUTO_REBASELINE_BRANCH_NAME) | 884 tool.scm().delete_branch(self.AUTO_REBASELINE_BRANCH_NAME) |
862 tool.scm().create_clean_branch(self.AUTO_REBASELINE_BRANCH_NAME) | 885 tool.scm().create_clean_branch(self.AUTO_REBASELINE_BRANCH_NAME) |
863 | 886 |
864 # If the tests are passing everywhere, then this list will be empty. We don't need | 887 # 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. | 888 # to rebaseline, but we'll still need to update TestExpectations. |
866 if test_prefix_list: | 889 if test_prefix_list: |
867 self._rebaseline(options, test_prefix_list) | 890 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 | 891 |
872 tool.scm().commit_locally_with_message(self.commit_message(author, r evision, bugs)) | 892 tool.scm().commit_locally_with_message(self.commit_message(author, r evision, bugs)) |
873 | 893 |
874 # FIXME: It would be nice if we could dcommit the patch without uplo ading, but still | 894 # 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 | 895 # 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 | 896 # takes a long time and sometimes fails, but we don't want to commit if, e.g. the |
877 # tree is closed. | 897 # tree is closed. |
878 did_finish = self._run_git_cl_command(options, ['upload', '-f']) | 898 did_finish = self._run_git_cl_command(options, ['upload', '-f']) |
879 | 899 |
880 if did_finish: | 900 if did_finish: |
(...skipping 26 matching lines...) Expand all Loading... | |
907 if options.verbose: | 927 if options.verbose: |
908 rebaseline_command.append('--verbose') | 928 rebaseline_command.append('--verbose') |
909 # Use call instead of run_command so that stdout doesn't get swa llowed. | 929 # Use call instead of run_command so that stdout doesn't get swa llowed. |
910 tool.executive.call(rebaseline_command) | 930 tool.executive.call(rebaseline_command) |
911 except: | 931 except: |
912 traceback.print_exc(file=sys.stderr) | 932 traceback.print_exc(file=sys.stderr) |
913 # Sometimes git crashes and leaves us on a detached head. | 933 # Sometimes git crashes and leaves us on a detached head. |
914 tool.scm().checkout_branch(old_branch_name) | 934 tool.scm().checkout_branch(old_branch_name) |
915 | 935 |
916 time.sleep(self.SLEEP_TIME_IN_SECONDS) | 936 time.sleep(self.SLEEP_TIME_IN_SECONDS) |
OLD | NEW |