Index: Tools/Scripts/webkitpy/tool/commands/rebaseline.py |
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py |
index 852c136a6cd6c8cbc7e441271d8b85563a2a9d06..d6adf3b1b7e895e72c1e88b9a6a894bd6b66bfc5 100644 |
--- a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py |
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py |
@@ -368,6 +368,7 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): |
cwd = self._tool.scm().checkout_root |
copy_baseline_commands = [] |
rebaseline_commands = [] |
+ lines_to_remove = {} |
port = self._tool.port_factory.get() |
for test_prefix in test_prefix_list: |
@@ -375,6 +376,11 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): |
for builder in self._builders_to_fetch_from(test_prefix_list[test_prefix]): |
actual_failures_suffixes = self._suffixes_for_actual_failures(test, builder, test_prefix_list[test_prefix][builder]) |
if not actual_failures_suffixes: |
+ # If we're not going to rebaseline the test because it's passing on this |
+ # builder, we still want to remove the line from TestExpectations. |
+ if test not in lines_to_remove: |
+ lines_to_remove[test] = [] |
+ lines_to_remove[test].append(builder) |
continue |
suffixes = ','.join(actual_failures_suffixes) |
@@ -385,7 +391,7 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): |
cmd_line.append('--verbose') |
copy_baseline_commands.append(tuple([[path_to_webkit_patch, 'copy-existing-baselines-internal'] + cmd_line, cwd])) |
rebaseline_commands.append(tuple([[path_to_webkit_patch, 'rebaseline-test-internal'] + cmd_line, cwd])) |
- return copy_baseline_commands, rebaseline_commands |
+ return copy_baseline_commands, rebaseline_commands, lines_to_remove |
def _serial_commands(self, command_results): |
files_to_add = set() |
@@ -435,37 +441,45 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): |
return optimize_commands |
def _update_expectations_files(self, lines_to_remove): |
- # FIXME: This routine is way too expensive. We're creating N ports and N TestExpectations |
- # objects and (re-)writing the actual expectations file N times, for each test we update. |
- # We should be able to update everything in memory, once, and then write the file out a single time. |
+ # FIXME: This routine is way too expensive. We're creating O(n ports) TestExpectations objects. |
+ # This is slow and uses a lot of memory. |
+ tests = lines_to_remove.keys() |
+ to_remove = [] |
+ |
+ # This is so we remove lines for builders that skip this test, e.g. Android skips most |
+ # tests and we don't want to leave stray [ Android ] lines in TestExpectations.. |
+ # FIXME: Is this necessary at all now that _rebaseline_commands includes the builders that |
+ # used to be skipped because the result wasn't failing on tip of tree? |
+ for port_name in self._tool.port_factory.all_port_names(): |
+ port = self._tool.port_factory.get(port_name) |
+ generic_expectations = TestExpectations(port, tests=tests, include_overrides=False) |
+ full_expectations = TestExpectations(port, tests=tests, include_overrides=True) |
+ for test in tests: |
+ if self._port_skips_test(port, test, generic_expectations, full_expectations): |
+ for test_configuration in port.all_test_configurations(): |
+ if test_configuration.version == port.test_configuration().version: |
+ to_remove.append((test, test_configuration)) |
+ |
for test in lines_to_remove: |
for builder in lines_to_remove[test]: |
port = self._tool.port_factory.get_from_builder_name(builder) |
- path = port.path_to_generic_test_expectations_file() |
- expectations = TestExpectations(port, include_overrides=False) |
for test_configuration in port.all_test_configurations(): |
if test_configuration.version == port.test_configuration().version: |
- expectationsString = expectations.remove_configuration_from_test(test, test_configuration) |
- self._tool.filesystem.write_text_file(path, expectationsString) |
+ to_remove.append((test, test_configuration)) |
- for port_name in self._tool.port_factory.all_port_names(): |
- port = self._tool.port_factory.get(port_name) |
- generic_expectations = TestExpectations(port, tests=[test], include_overrides=False) |
- if self._port_skips_test(port, test, generic_expectations): |
- for test_configuration in port.all_test_configurations(): |
- if test_configuration.version == port.test_configuration().version: |
- expectationsString = generic_expectations.remove_configuration_from_test(test, test_configuration) |
- generic_path = port.path_to_generic_test_expectations_file() |
- self._tool.filesystem.write_text_file(generic_path, expectationsString) |
+ port = self._tool.port_factory.get() |
+ expectations = TestExpectations(port, include_overrides=False) |
+ expectationsString = expectations.remove_configurations(to_remove) |
+ path = port.path_to_generic_test_expectations_file() |
+ self._tool.filesystem.write_text_file(path, expectationsString) |
- def _port_skips_test(self, port, test, generic_expectations): |
+ def _port_skips_test(self, port, test, generic_expectations, full_expectations): |
fs = port.host.filesystem |
if port.default_smoke_test_only(): |
smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests') |
if fs.exists(smoke_test_filename) and test not in fs.read_text_file(smoke_test_filename): |
return True |
- full_expectations = TestExpectations(port, tests=[test], include_overrides=True) |
return (SKIP in full_expectations.get_expectations(test) and |
SKIP not in generic_expectations.get_expectations(test)) |
@@ -481,8 +495,7 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): |
self._tool.scm().delete_list(files_to_delete) |
if files_to_add: |
self._tool.scm().add_list(files_to_add) |
- if lines_to_remove: |
- self._update_expectations_files(lines_to_remove) |
+ return lines_to_remove |
def _rebaseline(self, options, test_prefix_list): |
for test, builders_to_check in sorted(test_prefix_list.items()): |
@@ -490,11 +503,23 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): |
for builder, suffixes in sorted(builders_to_check.items()): |
_log.debug(" %s: %s" % (builder, ",".join(suffixes))) |
- copy_baseline_commands, rebaseline_commands = self._rebaseline_commands(test_prefix_list, options) |
+ copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = self._rebaseline_commands(test_prefix_list, options) |
+ lines_to_remove = {} |
+ |
if copy_baseline_commands: |
self._run_in_parallel_and_update_scm(copy_baseline_commands) |
if rebaseline_commands: |
- self._run_in_parallel_and_update_scm(rebaseline_commands) |
+ lines_to_remove = self._run_in_parallel_and_update_scm(rebaseline_commands) |
+ |
+ for test in extra_lines_to_remove: |
+ if test in lines_to_remove: |
+ lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_remove[test] |
+ else: |
+ lines_to_remove[test] = extra_lines_to_remove[test] |
+ |
+ if lines_to_remove: |
+ self._update_expectations_files(lines_to_remove) |
+ |
if options.optimize: |
self._run_in_parallel_and_update_scm(self._optimize_baselines(test_prefix_list, options.verbose)) |
@@ -865,9 +890,6 @@ class AutoRebaseline(AbstractParallelRebaselineCommand): |
# to rebaseline, but we'll still need to update TestExpectations. |
if test_prefix_list: |
self._rebaseline(options, test_prefix_list) |
- # If a test is not failing on the bot, we don't try to rebaseline it, but we still |
- # want to remove the NeedsRebaseline line. |
- self._update_expectations_files(lines_to_remove) |
tool.scm().commit_locally_with_message(self.commit_message(author, revision, bugs)) |