Commit 4b31acdd authored by Quinten Yearsley's avatar Quinten Yearsley Committed by Commit Bot

Extract "internal" rebaseline commands to separate files.

This is a continuation of changes in http://crbug.com/616967; the purpose
is to make it so that in general there's one class per file, and files
aren't too large.

This CL also makes a couple of minor clean-up changes in the classes
that are moved, e.g. changing method order, but this CL doesn't
include any changes to behavior.

Bug: 616967
Change-Id: I4f6aade879d0f660d3f35668448028e8ef0651b0
Reviewed-on: https://chromium-review.googlesource.com/521787
Commit-Queue: Quinten Yearsley <qyearsley@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#476465}
parent 4432cf04
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
from webkitpy.common.memoized import memoized
from webkitpy.layout_tests.models.test_expectations import SKIP
from webkitpy.layout_tests.models.test_expectations import TestExpectations
from webkitpy.tool.commands.rebaseline import AbstractRebaseliningCommand
_log = logging.getLogger(__name__)
class CopyExistingBaselines(AbstractRebaseliningCommand):
name = 'copy-existing-baselines-internal'
help_text = ('Copy existing baselines down one level in the baseline '
'order to ensure new baselines don\'t break existing passing '
'platforms.')
def __init__(self):
super(CopyExistingBaselines, self).__init__(options=[
self.test_option,
self.suffixes_option,
self.port_name_option,
self.results_directory_option,
])
def execute(self, options, args, tool):
self._tool = tool
port_name = options.port_name
for suffix in options.suffixes.split(','):
self._copy_existing_baseline(port_name, options.test, suffix)
def _copy_existing_baseline(self, port_name, test_name, suffix):
"""Copies the baseline for the given builder to all "predecessor" directories."""
baseline_directory = self._tool.port_factory.get(port_name).baseline_version_dir()
ports = [self._port_for_primary_baseline(baseline)
for baseline in self._immediate_predecessors_in_fallback(baseline_directory)]
old_baselines = []
new_baselines = []
# Need to gather all the baseline paths before modifying the filesystem since
# the modifications can affect the results of port.expected_filename.
for port in ports:
old_baseline = port.expected_filename(test_name, '.' + suffix)
if not self._tool.filesystem.exists(old_baseline):
_log.debug('No existing baseline for %s.', test_name)
continue
new_baseline = self._tool.filesystem.join(
port.baseline_version_dir(),
self._file_name_for_expected_result(test_name, suffix))
if self._tool.filesystem.exists(new_baseline):
_log.debug('Existing baseline at %s, not copying over it.', new_baseline)
continue
generic_expectations = TestExpectations(port, tests=[test_name], include_overrides=False)
full_expectations = TestExpectations(port, tests=[test_name], include_overrides=True)
# TODO(qyearsley): Change Port.skips_test so that this can be simplified.
if SKIP in full_expectations.get_expectations(test_name):
_log.debug('%s is skipped (perhaps temporarily) on %s.', test_name, port.name())
continue
if port.skips_test(test_name, generic_expectations, full_expectations):
_log.debug('%s is skipped on %s.', test_name, port.name())
continue
old_baselines.append(old_baseline)
new_baselines.append(new_baseline)
for i in range(len(old_baselines)):
old_baseline = old_baselines[i]
new_baseline = new_baselines[i]
_log.debug('Copying baseline from %s to %s.', old_baseline, new_baseline)
self._tool.filesystem.maybe_make_directory(self._tool.filesystem.dirname(new_baseline))
self._tool.filesystem.copyfile(old_baseline, new_baseline)
def _port_for_primary_baseline(self, baseline):
"""Returns a Port object for the given baseline directory base name."""
for port in [self._tool.port_factory.get(port_name) for port_name in self._tool.port_factory.all_port_names()]:
if self._tool.filesystem.basename(port.baseline_version_dir()) == baseline:
return port
raise Exception('Failed to find port for primary baseline %s.' % baseline)
@memoized
def _immediate_predecessors_in_fallback(self, path_to_rebaseline):
"""Returns the predecessor directories in the baseline fall-back graph.
The platform-specific fall-back baseline directories form a tree, where
when we search for baselines we normally fall back to parents nodes in
the tree. The "immediate predecessors" are the children nodes of the
given node.
For example, if the baseline fall-back graph includes:
"mac10.9" -> "mac10.10/"
"mac10.10/" -> "mac/"
"retina/" -> "mac/"
Then, the "immediate predecessors" are:
"mac/": ["mac10.10/", "retina/"]
"mac10.10/": ["mac10.9/"]
"mac10.9/", "retina/": []
Args:
path_to_rebaseline: The absolute path to a baseline directory.
Returns:
A list of directory names (not full paths) of directories that are
"immediate predecessors" of the given baseline path.
"""
port_names = self._tool.port_factory.all_port_names()
immediate_predecessors = []
for port_name in port_names:
port = self._tool.port_factory.get(port_name)
baseline_search_path = port.baseline_search_path()
try:
index = baseline_search_path.index(path_to_rebaseline)
if index:
immediate_predecessors.append(self._tool.filesystem.basename(baseline_search_path[index - 1]))
except ValueError:
# baseline_search_path.index() throws a ValueError if the item isn't in the list.
pass
return immediate_predecessors
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import optparse
from webkitpy.tool.commands.rebaseline_unittest import BaseTestCase
from webkitpy.tool.commands.copy_existing_baselines import CopyExistingBaselines
class TestCopyExistingBaselines(BaseTestCase):
command_constructor = CopyExistingBaselines
def options(self, **kwargs):
options_dict = {
'results_directory': None,
'suffixes': 'txt',
'verbose': False,
'port_name': None,
}
options_dict.update(kwargs)
return optparse.Values(options_dict)
def baseline_path(self, path_from_layout_test_dir):
port = self.tool.port_factory.get()
return self.tool.filesystem.join(port.layout_tests_dir(), path_from_layout_test_dir)
# The tests in this class all depend on the fall-back path graph
# that is set up in |TestPort.FALLBACK_PATHS|.
def test_copy_baseline_mac_newer_to_older_version(self):
# The test-mac-mac10.11 baseline is copied over to the test-mac-mac10.10
# baseline directory because test-mac-mac10.10 is the "immediate
# predecessor" in the fall-back graph.
self._write(
self.baseline_path('platform/test-mac-mac10.11/failures/expected/image-expected.txt'),
'original test-mac-mac10.11 result')
self.assertFalse(self.tool.filesystem.exists(
self.baseline_path('platform/test-mac-mac10.10/failures/expected/image-expected.txt')))
self.command.execute(self.options(port_name='test-mac-mac10.11', test='failures/expected/image.html'), [], self.tool)
self.assertEqual(
self._read(self.baseline_path('platform/test-mac-mac10.11/failures/expected/image-expected.txt')),
'original test-mac-mac10.11 result')
self.assertEqual(
self._read(self.baseline_path('platform/test-mac-mac10.10/failures/expected/image-expected.txt')),
'original test-mac-mac10.11 result')
def test_copy_baseline_to_multiple_immediate_predecessors(self):
# The test-win-win10 baseline is copied over to the test-linux-trusty
# and test-win-win7 baseline paths, since both of these are "immediate
# predecessors".
self._write(
self.baseline_path('platform/test-win-win10/failures/expected/image-expected.txt'),
'original test-win-win10 result')
self.assertFalse(self.tool.filesystem.exists(
self.baseline_path('platform/test-linux-trusty/failures/expected/image-expected.txt')))
self.command.execute(self.options(port_name='test-win-win10', test='failures/expected/image.html'), [], self.tool)
self.assertEqual(
self._read(self.baseline_path('platform/test-win-win10/failures/expected/image-expected.txt')),
'original test-win-win10 result')
self.assertEqual(
self._read(self.baseline_path('platform/test-linux-trusty/failures/expected/image-expected.txt')),
'original test-win-win10 result')
self.assertEqual(
self._read(self.baseline_path('platform/test-linux-trusty/failures/expected/image-expected.txt')),
'original test-win-win10 result')
def test_no_copy_existing_baseline(self):
# If a baseline exists already for an "immediate predecessor" baseline
# directory, (e.g. test-linux-trusty), then no "immediate successor"
# baselines (e.g. test-win-win10) are copied over.
self._write(
self.baseline_path('platform/test-win-win10/failures/expected/image-expected.txt'),
'original test-win-win10 result')
self._write(
self.baseline_path('platform/test-linux-trusty/failures/expected/image-expected.txt'),
'original test-linux-trusty result')
self.command.execute(self.options(port_name='test-win-win10', test='failures/expected/image.html'), [], self.tool)
self.assertEqual(
self._read(self.baseline_path('platform/test-win-win10/failures/expected/image-expected.txt')),
'original test-win-win10 result')
self.assertEqual(
self._read(self.baseline_path('platform/test-linux-trusty/failures/expected/image-expected.txt')),
'original test-linux-trusty result')
def test_no_copy_skipped_test(self):
# If a test is skipped on some platform, no baselines are copied over
# to that directory. In this example, the test is skipped on linux,
# so the test-win-win10 baseline is not copied over.
port = self.tool.port_factory.get('test-win-win10')
self._write(
self.baseline_path('platform/test-win-win10/failures/expected/image-expected.txt'),
'original test-win-win10 result')
self._write(
port.path_to_generic_test_expectations_file(),
('[ Win ] failures/expected/image.html [ Failure ]\n'
'[ Linux ] failures/expected/image.html [ Skip ]\n'))
self.command.execute(self.options(port_name='test-win-win10', test='failures/expected/image.html'), [], self.tool)
self.assertFalse(
self.tool.filesystem.exists(self.baseline_path('platform/test-linux-trusty/failures/expected/image-expected.txt')))
def test_port_for_primary_baseline(self):
# Testing a protected method - pylint: disable=protected-access
self.assertEqual(self.command._port_for_primary_baseline('test-linux-trusty').name(), 'test-linux-trusty')
self.assertEqual(self.command._port_for_primary_baseline('test-mac-mac10.11').name(), 'test-mac-mac10.11')
def test_port_for_primary_baseline_not_found(self):
# Testing a protected method - pylint: disable=protected-access
with self.assertRaises(Exception):
self.command._port_for_primary_baseline('test-foo-foo4.7')
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import logging
from webkitpy.tool.commands.rebaseline import AbstractRebaseliningCommand
_log = logging.getLogger(__name__)
class RebaselineTest(AbstractRebaseliningCommand):
name = 'rebaseline-test-internal'
help_text = 'Rebaseline a single test from a single builder.'
def __init__(self):
super(RebaselineTest, self).__init__(options=[
self.test_option,
self.suffixes_option,
self.port_name_option,
self.builder_option,
self.build_number_option,
self.results_directory_option,
])
def execute(self, options, args, tool):
self._tool = tool
self._rebaseline_test_and_update_expectations(options)
self._print_expectation_line_changes()
def _rebaseline_test_and_update_expectations(self, options):
self._baseline_suffix_list = options.suffixes.split(',')
port_name = options.port_name or self._tool.builders.port_name_for_builder_name(options.builder)
port = self._tool.port_factory.get(port_name)
if port.reference_files(options.test):
if 'png' in self._baseline_suffix_list:
_log.warning('Cannot rebaseline image result for reftest: %s', options.test)
return
assert self._baseline_suffix_list == ['txt']
if options.results_directory:
results_url = 'file://' + options.results_directory
else:
results_url = self._tool.buildbot.results_url(options.builder, build_number=options.build_number)
for suffix in self._baseline_suffix_list:
self._rebaseline_test(port_name, options.test, suffix, results_url)
self.expectation_line_changes.remove_line(
test=options.test,
port_name=port_name)
def _save_baseline(self, data, target_baseline):
if not data:
_log.debug('No baseline data to save.')
return
filesystem = self._tool.filesystem
self._tool.filesystem.maybe_make_directory(filesystem.dirname(target_baseline))
self._tool.filesystem.write_binary_file(target_baseline, data)
def _rebaseline_test(self, port_name, test_name, suffix, results_url):
"""Downloads a baseline file and saves it to the filesystem.
Args:
port_name: The port that the baseline is for. This determines
the directory that the baseline is saved to.
test_name: The name of the test being rebaselined.
suffix: The baseline file extension (e.g. png); together with the
test name and results_url this determines what file to download.
results_url: Base URL to download the actual result from.
"""
baseline_directory = self._tool.port_factory.get(port_name).baseline_version_dir()
source_baseline = '%s/%s' % (results_url, self._file_name_for_actual_result(test_name, suffix))
target_baseline = self._tool.filesystem.join(baseline_directory, self._file_name_for_expected_result(test_name, suffix))
_log.debug('Retrieving source %s for target %s.', source_baseline, target_baseline)
self._save_baseline(
self._tool.web.get_binary(source_baseline, return_none_on_404=True),
target_baseline)
def _print_expectation_line_changes(self):
print json.dumps(self.expectation_line_changes.to_dict())
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import optparse
from webkitpy.common.system.executive_mock import MockExecutive
from webkitpy.common.system.output_capture import OutputCapture
from webkitpy.tool.commands.rebaseline_test import RebaselineTest
from webkitpy.tool.commands.rebaseline_unittest import BaseTestCase
class TestRebaselineTest(BaseTestCase):
command_constructor = RebaselineTest
@staticmethod
def options(**kwargs):
return optparse.Values(dict({
'builder': 'MOCK Mac10.11',
'port_name': None,
'test': 'userscripts/another-test.html',
'suffixes': 'txt',
'results_directory': None,
'build_number': None
}, **kwargs))
def test_rebaseline_test_internal_with_port_that_lacks_buildbot(self):
self.tool.executive = MockExecutive()
port = self.tool.port_factory.get('test-win-win7')
self._write(
port.host.filesystem.join(
port.layout_tests_dir(),
'platform/test-win-win10/failures/expected/image-expected.txt'),
'original win10 result')
oc = OutputCapture()
try:
options = optparse.Values({
'optimize': True,
'builder': 'MOCK Win10',
'port_name': None,
'suffixes': 'txt',
'verbose': True,
'test': 'failures/expected/image.html',
'results_directory': None,
'build_number': None
})
oc.capture_output()
self.command.execute(options, [], self.tool)
finally:
out, _, _ = oc.restore_output()
self.assertMultiLineEqual(
self._read(self.tool.filesystem.join(
port.layout_tests_dir(),
'platform/test-win-win10/failures/expected/image-expected.txt')),
'MOCK Web result, convert 404 to None=True')
self.assertFalse(self.tool.filesystem.exists(self.tool.filesystem.join(
port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt')))
self.assertMultiLineEqual(
out, '{"remove-lines": [{"test": "failures/expected/image.html", "port_name": "test-win-win10"}]}\n')
def test_baseline_directory(self):
self.assertMultiLineEqual(
self.command.baseline_directory('MOCK Mac10.11'),
'/test.checkout/LayoutTests/platform/test-mac-mac10.11')
self.assertMultiLineEqual(
self.command.baseline_directory('MOCK Mac10.10'),
'/test.checkout/LayoutTests/platform/test-mac-mac10.10')
self.assertMultiLineEqual(
self.command.baseline_directory('MOCK Trusty'),
'/test.checkout/LayoutTests/platform/test-linux-trusty')
self.assertMultiLineEqual(
self.command.baseline_directory('MOCK Precise'),
'/test.checkout/LayoutTests/platform/test-linux-precise')
def test_rebaseline_updates_expectations_file_noop(self):
# pylint: disable=protected-access
self._zero_out_test_expectations()
self._write(
self.mac_expectations_path,
('Bug(B) [ Mac Linux Win7 Debug ] fast/dom/Window/window-postmessage-clone-really-deep-array.html [ Pass ]\n'
'Bug(A) [ Debug ] : fast/css/large-list-of-rules-crash.html [ Failure ]\n'))
self._write('fast/dom/Window/window-postmessage-clone-really-deep-array.html', 'Dummy test contents')
self._write('fast/css/large-list-of-rules-crash.html', 'Dummy test contents')
self._write('userscripts/another-test.html', 'Dummy test contents')
self.command._rebaseline_test_and_update_expectations(self.options(suffixes='png,wav,txt'))
self.assertItemsEqual(self.tool.web.urls_fetched,
[self.WEB_PREFIX + '/userscripts/another-test-actual.png',
self.WEB_PREFIX + '/userscripts/another-test-actual.wav',
self.WEB_PREFIX + '/userscripts/another-test-actual.txt'])
new_expectations = self._read(self.mac_expectations_path)
self.assertMultiLineEqual(
new_expectations,
('Bug(B) [ Mac Linux Win7 Debug ] fast/dom/Window/window-postmessage-clone-really-deep-array.html [ Pass ]\n'
'Bug(A) [ Debug ] : fast/css/large-list-of-rules-crash.html [ Failure ]\n'))
def test_rebaseline_test(self):
# pylint: disable=protected-access
self.command._rebaseline_test('test-linux-trusty', 'userscripts/another-test.html', 'txt', self.WEB_PREFIX)
self.assertItemsEqual(
self.tool.web.urls_fetched, [self.WEB_PREFIX + '/userscripts/another-test-actual.txt'])
def test_rebaseline_test_with_results_directory(self):
# pylint: disable=protected-access
self._write('userscripts/another-test.html', 'test data')
self._write(
self.mac_expectations_path,
('Bug(x) [ Mac ] userscripts/another-test.html [ Failure ]\n'
'bug(z) [ Linux ] userscripts/another-test.html [ Failure ]\n'))
self.command._rebaseline_test_and_update_expectations(self.options(results_directory='/tmp'))
self.assertItemsEqual(self.tool.web.urls_fetched, ['file:///tmp/userscripts/another-test-actual.txt'])
def test_rebaseline_reftest(self):
# pylint: disable=protected-access
self._write('userscripts/another-test.html', 'test data')
self._write('userscripts/another-test-expected.html', 'generic result')
OutputCapture().assert_outputs(
self, self.command._rebaseline_test_and_update_expectations, args=[self.options(suffixes='png')],
expected_logs='Cannot rebaseline image result for reftest: userscripts/another-test.html\n')
self.assertDictEqual(self.command.expectation_line_changes.to_dict(), {'remove-lines': []})
......@@ -29,10 +29,11 @@
"""Webkit-patch is a tool with multiple sub-commands with different purposes.
Historically, it had commands related to dealing with bugzilla, and posting
and comitting patches to WebKit. More recently, it has commands for printing
expectations, fetching new test baselines, starting a commit-announcer IRC bot,
etc. These commands don't necessarily have anything to do with each other.
Historically, it had commands related to dealing with bugzilla and posting
and committing patches to WebKit. More recently, it has commands for printing
expectations, fetching new test baselines, etc.
These commands don't necessarily have anything to do with each other.
"""
import logging
......@@ -43,6 +44,7 @@ from webkitpy.common.host import Host
from webkitpy.tool.commands.analyze_baselines import AnalyzeBaselines
from webkitpy.tool.commands.auto_rebaseline import AutoRebaseline
from webkitpy.tool.commands.command import HelpPrintingOptionParser
from webkitpy.tool.commands.copy_existing_baselines import CopyExistingBaselines
from webkitpy.tool.commands.flaky_tests import FlakyTests
from webkitpy.tool.commands.help_command import HelpCommand
from webkitpy.tool.commands.layout_tests_server import LayoutTestsServer
......@@ -51,12 +53,11 @@ from webkitpy.tool.commands.pretty_diff import PrettyDiff
from webkitpy.tool.commands.queries import CrashLog
from webkitpy.tool.commands.queries import PrintBaselines
from webkitpy.tool.commands.queries import PrintExpectations
from webkitpy.tool.commands.rebaseline import CopyExistingBaselinesInternal
from webkitpy.tool.commands.rebaseline import Rebaseline
from webkitpy.tool.commands.rebaseline import RebaselineExpectations
from webkitpy.tool.commands.rebaseline import RebaselineTest
from webkitpy.tool.commands.rebaseline_cl import RebaselineCL
from webkitpy.tool.commands.rebaseline_server import RebaselineServer
from webkitpy.tool.commands.rebaseline_test import RebaselineTest
_log = logging.getLogger(__name__)
......@@ -81,7 +82,7 @@ class WebKitPatch(Host):
self.commands = [
AnalyzeBaselines(),
AutoRebaseline(),
CopyExistingBaselinesInternal(),
CopyExistingBaselines(),
CrashLog(),
FlakyTests(),
LayoutTestsServer(),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment