Chromium Code Reviews| 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 63 | 63 |
| 64 def __init__(self, options=None): | 64 def __init__(self, options=None): |
| 65 super(AbstractRebaseliningCommand, self).__init__(options=options) | 65 super(AbstractRebaseliningCommand, self).__init__(options=options) |
| 66 self._baseline_suffix_list = BASELINE_SUFFIX_LIST | 66 self._baseline_suffix_list = BASELINE_SUFFIX_LIST |
| 67 self.expectation_line_changes = ChangeSet() | 67 self.expectation_line_changes = ChangeSet() |
| 68 self._tool = None | 68 self._tool = None |
| 69 | 69 |
| 70 def _print_expectation_line_changes(self): | 70 def _print_expectation_line_changes(self): |
| 71 print(json.dumps(self.expectation_line_changes.to_dict())) | 71 print(json.dumps(self.expectation_line_changes.to_dict())) |
| 72 | 72 |
| 73 def _baseline_directory(self, builder_name): | |
| 74 port = self._tool.port_factory.get_from_builder_name(builder_name) | |
| 75 return port.baseline_version_dir() | |
| 76 | |
| 77 def _test_root(self, test_name): | |
| 78 return self._tool.filesystem.splitext(test_name)[0] | |
| 79 | |
| 80 def _file_name_for_actual_result(self, test_name, suffix): | |
| 81 return "%s-actual.%s" % (self._test_root(test_name), suffix) | |
| 82 | |
| 83 def _file_name_for_expected_result(self, test_name, suffix): | |
| 84 return "%s-expected.%s" % (self._test_root(test_name), suffix) | |
| 85 | |
| 73 | 86 |
| 74 class ChangeSet(object): | 87 class ChangeSet(object): |
| 75 """A record of TestExpectation lines to remove. | 88 """A record of TestExpectation lines to remove. |
| 76 | 89 |
| 77 TODO(qyearsley): Remove this class, track list of lines to remove directly | 90 TODO(qyearsley): Remove this class, track list of lines to remove directly |
| 78 in an attribute of AbstractRebaseliningCommand. | 91 in an attribute of AbstractRebaseliningCommand. |
| 79 """ | 92 """ |
| 80 def __init__(self, lines_to_remove=None): | 93 def __init__(self, lines_to_remove=None): |
| 81 self.lines_to_remove = lines_to_remove or {} | 94 self.lines_to_remove = lines_to_remove or {} |
| 82 | 95 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 def __init__(self): | 133 def __init__(self): |
| 121 super(BaseInternalRebaselineCommand, self).__init__(options=[ | 134 super(BaseInternalRebaselineCommand, self).__init__(options=[ |
| 122 self.results_directory_option, | 135 self.results_directory_option, |
| 123 self.suffixes_option, | 136 self.suffixes_option, |
| 124 optparse.make_option("--builder", help="Builder to pull new baseline s from."), | 137 optparse.make_option("--builder", help="Builder to pull new baseline s from."), |
| 125 optparse.make_option("--test", help="Test to rebaseline."), | 138 optparse.make_option("--test", help="Test to rebaseline."), |
| 126 optparse.make_option("--build-number", default=None, type="int", | 139 optparse.make_option("--build-number", default=None, type="int", |
| 127 help="Optional build number; if not given, the latest build is used."), | 140 help="Optional build number; if not given, the latest build is used."), |
| 128 ]) | 141 ]) |
| 129 | 142 |
| 130 def _baseline_directory(self, builder_name): | |
| 131 port = self._tool.port_factory.get_from_builder_name(builder_name) | |
| 132 return port.baseline_version_dir() | |
| 133 | |
| 134 def _test_root(self, test_name): | |
| 135 return self._tool.filesystem.splitext(test_name)[0] | |
| 136 | |
| 137 def _file_name_for_actual_result(self, test_name, suffix): | |
| 138 return "%s-actual.%s" % (self._test_root(test_name), suffix) | |
| 139 | |
| 140 def _file_name_for_expected_result(self, test_name, suffix): | |
| 141 return "%s-expected.%s" % (self._test_root(test_name), suffix) | |
| 142 | |
| 143 | 143 |
| 144 class CopyExistingBaselinesInternal(BaseInternalRebaselineCommand): | 144 class CopyExistingBaselinesInternal(BaseInternalRebaselineCommand): |
| 145 name = "copy-existing-baselines-internal" | 145 name = "copy-existing-baselines-internal" |
| 146 help_text = ("Copy existing baselines down one level in the baseline order t o ensure " | 146 help_text = ("Copy existing baselines down one level in the baseline order t o ensure " |
| 147 "new baselines don't break existing passing platforms.") | 147 "new baselines don't break existing passing platforms.") |
| 148 | 148 |
| 149 @memoized | 149 @memoized |
| 150 def _immediate_predecessors_in_fallback(self, path_to_rebaseline): | 150 def _immediate_predecessors_in_fallback(self, path_to_rebaseline): |
| 151 port_names = self._tool.port_factory.all_port_names() | 151 port_names = self._tool.port_factory.all_port_names() |
| 152 immediate_predecessors = [] | 152 immediate_predecessors = [] |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 class RebaselineTest(BaseInternalRebaselineCommand): | 216 class RebaselineTest(BaseInternalRebaselineCommand): |
| 217 name = "rebaseline-test-internal" | 217 name = "rebaseline-test-internal" |
| 218 help_text = "Rebaseline a single test from a buildbot. Only intended for use by other webkit-patch commands." | 218 help_text = "Rebaseline a single test from a buildbot. Only intended for use by other webkit-patch commands." |
| 219 | 219 |
| 220 def _save_baseline(self, data, target_baseline): | 220 def _save_baseline(self, data, target_baseline): |
| 221 if not data: | 221 if not data: |
| 222 _log.debug("No baseline data to save.") | 222 _log.debug("No baseline data to save.") |
| 223 return | 223 return |
| 224 | 224 |
| 225 filesystem = self._tool.filesystem | 225 filesystem = self._tool.filesystem |
| 226 if is_all_pass_testharness_result(data): | |
| 227 _log.debug("The new baseline is a passing testharness result with " | |
| 228 "no console warnings or errors, so it will not be saved." ) | |
| 229 if filesystem.exists(target_baseline): | |
| 230 filesystem.remove(target_baseline) | |
| 231 return | |
| 232 | |
| 233 filesystem.maybe_make_directory(filesystem.dirname(target_baseline)) | 226 filesystem.maybe_make_directory(filesystem.dirname(target_baseline)) |
| 234 filesystem.write_binary_file(target_baseline, data) | 227 filesystem.write_binary_file(target_baseline, data) |
| 235 | 228 |
| 236 def _rebaseline_test(self, builder_name, test_name, suffix, results_url): | 229 def _rebaseline_test(self, builder_name, test_name, suffix, results_url): |
| 237 baseline_directory = self._baseline_directory(builder_name) | 230 baseline_directory = self._baseline_directory(builder_name) |
| 238 | 231 |
| 239 source_baseline = "%s/%s" % (results_url, self._file_name_for_actual_res ult(test_name, suffix)) | 232 source_baseline = "%s/%s" % (results_url, self._file_name_for_actual_res ult(test_name, suffix)) |
| 240 target_baseline = self._tool.filesystem.join(baseline_directory, self._f ile_name_for_expected_result(test_name, suffix)) | 233 target_baseline = self._tool.filesystem.join(baseline_directory, self._f ile_name_for_expected_result(test_name, suffix)) |
| 241 | 234 |
| 242 _log.debug("Retrieving source %s for target %s.", source_baseline, targe t_baseline) | 235 _log.debug("Retrieving source %s for target %s.", source_baseline, targe t_baseline) |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 | 510 |
| 518 if lines_to_remove: | 511 if lines_to_remove: |
| 519 self._update_expectations_files(lines_to_remove) | 512 self._update_expectations_files(lines_to_remove) |
| 520 | 513 |
| 521 if options.optimize: | 514 if options.optimize: |
| 522 # TODO(wkorman): Consider changing temporary branch to base off of H EAD rather than | 515 # TODO(wkorman): Consider changing temporary branch to base off of H EAD rather than |
| 523 # origin/master to ensure we run baseline optimization processes wit h the same code as | 516 # origin/master to ensure we run baseline optimization processes wit h the same code as |
| 524 # auto-rebaseline itself. | 517 # auto-rebaseline itself. |
| 525 self._run_in_parallel(self._optimize_baselines(test_prefix_list, opt ions.verbose)) | 518 self._run_in_parallel(self._optimize_baselines(test_prefix_list, opt ions.verbose)) |
| 526 | 519 |
| 520 self._remove_all_pass_testharness_baselines(test_prefix_list) | |
| 521 | |
| 527 self._tool.scm().add_all(pathspec=self._layout_tests_dir()) | 522 self._tool.scm().add_all(pathspec=self._layout_tests_dir()) |
| 528 | 523 |
| 524 def _remove_all_pass_testharness_baselines(self, test_prefix_list): | |
| 525 """Removes all of the all-PASS baselines for the given builders and test s. | |
| 526 | |
| 527 In general, for testharness.js tests, the absence of a baseline | |
| 528 indicates that the test is expected to pass. When rebaselining, | |
| 529 new all-PASS baselines may be downloaded, but they should not be kept. | |
|
wkorman
2016/10/25 00:14:20
Is removing restoring the repo to the baselines-do
qyearsley
2016/10/25 00:33:04
I think it could be either removing an existing fi
| |
| 530 """ | |
| 531 filesystem = self._tool.filesystem | |
| 532 baseline_paths = self._all_baseline_paths(test_prefix_list) | |
| 533 for path in baseline_paths: | |
| 534 if not (filesystem.exists(path) and | |
| 535 filesystem.splitext(path)[1] == '.txt'): | |
| 536 continue | |
| 537 contents = filesystem.read_text_file(path) | |
|
wkorman
2016/10/25 00:14:20
How many of these do we expect there to be typical
qyearsley
2016/10/25 00:33:04
Right -- hypothetically there could be hundreds of
| |
| 538 if is_all_pass_testharness_result(contents): | |
| 539 _log.info('Removing all-PASS testharness baseline: %s', path) | |
| 540 filesystem.remove(path) | |
| 541 | |
| 542 def _all_baseline_paths(self, test_prefix_list): | |
| 543 """Return file paths for all baselines for the given tests and builders. | |
| 544 | |
| 545 Args: | |
| 546 test_prefix_list: A dict mapping test prefixes, which could be | |
| 547 directories or full test paths, to builds to baseline suffixes. | |
| 548 TODO(qyearsley): If a class is added to replace test_prefix_list , | |
| 549 then this can be made a method on that class. | |
| 550 | |
| 551 Returns: | |
| 552 A list of absolute paths to baseline files. | |
|
qyearsley
2016/10/25 00:33:04
Currently this actually returns potential places w
wkorman
2016/10/25 00:37:17
Seems reasonable, this method is only used in this
qyearsley
2016/10/25 20:13:34
I was thinking of filtering out files that don't e
| |
| 553 """ | |
| 554 filesystem = self._tool.filesystem | |
| 555 baseline_paths = [] | |
| 556 port = self._tool.port_factory.get() | |
| 557 | |
| 558 for test_prefix in test_prefix_list: | |
| 559 tests = port.tests([test_prefix]) | |
| 560 all_suffixes = set() | |
| 561 | |
| 562 for build, suffixes in test_prefix_list[test_prefix].iteritems(): | |
| 563 all_suffixes.update(suffixes) | |
| 564 port_baseline_dir = self._baseline_directory(build.builder_name) | |
| 565 baseline_paths.extend([ | |
| 566 filesystem.join(port_baseline_dir, self._file_name_for_expec ted_result(test, suffix)) | |
| 567 for test in tests for suffix in suffixes | |
| 568 ]) | |
| 569 | |
| 570 baseline_paths.extend([ | |
| 571 filesystem.join(self._layout_tests_dir(), self._file_name_for_ex pected_result(test, suffix)) | |
| 572 for test in tests for suffix in all_suffixes | |
| 573 ]) | |
| 574 | |
| 575 return baseline_paths | |
| 576 | |
| 529 def _layout_tests_dir(self): | 577 def _layout_tests_dir(self): |
| 530 return self._tool.port_factory.get().layout_tests_dir() | 578 return self._tool.port_factory.get().layout_tests_dir() |
| 531 | 579 |
| 532 def _suffixes_for_actual_failures(self, test, build, existing_suffixes): | 580 def _suffixes_for_actual_failures(self, test, build, existing_suffixes): |
| 533 """Gets the baseline suffixes for actual mismatch failures in some resul ts. | 581 """Gets the baseline suffixes for actual mismatch failures in some resul ts. |
| 534 | 582 |
| 535 Args: | 583 Args: |
| 536 test: A full test path string. | 584 test: A full test path string. |
| 537 build: A Build object. | 585 build: A Build object. |
| 538 existing_suffixes: A collection of all suffixes to consider. | 586 existing_suffixes: A collection of all suffixes to consider. |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 657 for test in args: | 705 for test in args: |
| 658 if test not in test_prefix_list: | 706 if test not in test_prefix_list: |
| 659 test_prefix_list[test] = {} | 707 test_prefix_list[test] = {} |
| 660 build = Build(builder) | 708 build = Build(builder) |
| 661 test_prefix_list[test][build] = suffixes_to_update | 709 test_prefix_list[test][build] = suffixes_to_update |
| 662 | 710 |
| 663 if options.verbose: | 711 if options.verbose: |
| 664 _log.debug("rebaseline-json: " + str(test_prefix_list)) | 712 _log.debug("rebaseline-json: " + str(test_prefix_list)) |
| 665 | 713 |
| 666 self.rebaseline(options, test_prefix_list) | 714 self.rebaseline(options, test_prefix_list) |
| OLD | NEW |