Diff
Modified: trunk/Tools/ChangeLog (118835 => 118836)
--- trunk/Tools/ChangeLog 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/ChangeLog 2012-05-29 21:30:41 UTC (rev 118836)
@@ -1,3 +1,71 @@
+2012-05-29 Dirk Pranke <[email protected]>
+
+ garden-o-matic should rebaseline baselines in parallel
+ https://bugs.webkit.org/show_bug.cgi?id=87451
+
+ Reviewed by Ojan Vafai.
+
+ This modifies garden-o-matic so that we will fetch all
+ of the baselines in parallel from the bots, and then
+ optimize the baselines serially (since that should be fairly
+ quick and we get into trouble if we optimize in parallel due
+ to concurrent access to the source control system).
+
+ This change adds a flag to webkit-patch rebaseline-test (--print-scm-changes)
+ so that the files that need to be modified in the SCM are returned to
+ garden-o-matic rather than actually added or removed. This is done so that
+ we can run multiple rebaseline-tests in parallel (we can't modify the SCM
+ concurrently). In order to safely return the files (as a JSON dict) I
+ needed to shift all of the logging in rebaseline-test to use the logging
+ module (and hence log to stderr).
+
+ I also had to stub out a line in chromium.py that would get confused if
+ the skia overrides file didn't exist in a mock checkout.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ (Executive.popen):
+ (Executive):
+ (Executive.run_in_parallel):
+ (_run_command_thunk):
+ * Scripts/webkitpy/common/system/executive_mock.py:
+ (MockExecutive.run_in_parallel):
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ (ExecutiveTest.test_run_in_parallel):
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ (ChromiumPort._expectations_file_contents):
+ * Scripts/webkitpy/tool/commands/rebaseline.py:
+ (AbstractRebaseliningCommand.__init__):
+ (RebaselineTest.__init__):
+ (RebaselineTest._copy_existing_baseline):
+ (RebaselineTest._save_baseline):
+ (RebaselineTest):
+ (RebaselineTest._add_to_scm):
+ (RebaselineTest._rebaseline_test):
+ (RebaselineTest.execute):
+ (RebaselineExpectations._rebaseline_port):
+ (RebaselineExpectations.execute):
+ (Rebaseline._builder_to_pull_from):
+ (Rebaseline.execute):
+ * Scripts/webkitpy/tool/commands/rebaseline_unittest.py:
+ (test_rebaseline_updates_expectations_file):
+ (test_rebaseline_test):
+ (test_rebaseline_test_and_print_scm_changes):
+ (test_rebaseline_and_copy_test):
+ (test_rebaseline_and_copy_test_no_existing_result):
+ (test_rebaseline_and_copy_test_with_lion_result):
+ (test_rebaseline_and_copy_no_overwrite_test):
+ (test_rebaseline_expectations):
+ * Scripts/webkitpy/tool/servers/gardeningserver.py:
+ (GardeningHTTPRequestHandler._rebaseline_commands):
+ (GardeningHTTPRequestHandler):
+ (GardeningHTTPRequestHandler._files_to_add):
+ (GardeningHTTPRequestHandler._optimize_baselines):
+ (GardeningHTTPRequestHandler.rebaselineall):
+ * Scripts/webkitpy/tool/servers/gardeningserver_unittest.py:
+ (GardeningServerTest._post_to_path):
+ (GardeningServerTest.test_rebaselineall):
+ (GardeningServerTest.test_rebaselineall.run_command):
+
2012-05-29 Benjamin Poulain <[email protected]>
Fix the type of dispatch_time() offset
Modified: trunk/Tools/Scripts/webkitpy/common/system/executive.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/common/system/executive.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/common/system/executive.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -451,3 +451,15 @@
def popen(self, *args, **kwargs):
return subprocess.Popen(*args, **kwargs)
+
+ def run_in_parallel(self, command_lines_and_cwds, processes=None):
+ """Runs a list of (cmd_line list, cwd string) tuples in parallel and returns a list of (retcode, stdout, stderr) tuples."""
+ return multiprocessing.Pool(processes=processes).map(_run_command_thunk, command_lines_and_cwds)
+
+
+def _run_command_thunk(cmd_line_and_cwd):
+ # Note that this needs to be a bare module (and hence Picklable) method to work with multiprocessing.Pool.
+ (cmd_line, cwd) = cmd_line_and_cwd
+ proc = subprocess.Popen(cmd_line, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+ return (proc.returncode, stdout, stderr)
Modified: trunk/Tools/Scripts/webkitpy/common/system/executive_mock.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/common/system/executive_mock.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/common/system/executive_mock.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -108,6 +108,11 @@
self._proc = MockProcess()
return self._proc
+ def run_in_parallel(self, commands):
+ command_outputs = []
+ for cmd_line, cwd in commands:
+ command_outputs.append([0, self.run_command(cmd_line, cwd=cwd), ''])
+ return command_outputs
class MockExecutive2(object):
@staticmethod
Modified: trunk/Tools/Scripts/webkitpy/common/system/executive_unittest.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/common/system/executive_unittest.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/common/system/executive_unittest.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -31,6 +31,7 @@
import signal
import subprocess
import sys
+import time
import unittest
# Since we execute this script directly as part of the unit tests, we need to ensure
@@ -216,7 +217,19 @@
pids = executive.running_pids()
self.assertTrue(os.getpid() in pids)
+ def test_run_in_parallel(self):
+ NUM_PROCESSES = 4
+ DELAY_SECS = 0.25
+ cmd_line = [sys.executable, '-c', 'import time; time.sleep(%f); print "hello"' % DELAY_SECS]
+ cwd = os.getcwd()
+ commands = [tuple([cmd_line, cwd])] * NUM_PROCESSES
+ start = time.time()
+ command_outputs = Executive().run_in_parallel(commands, processes=NUM_PROCESSES)
+ done = time.time()
+ self.assertTrue(done - start < NUM_PROCESSES * DELAY_SECS)
+ self.assertEquals([output[1] for output in command_outputs], ["hello\n"] * NUM_PROCESSES)
+
def main(platform, stdin, stdout, cmd, args):
if platform == 'win32' and hasattr(stdout, 'fileno'):
import msvcrt
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -327,9 +327,12 @@
(filetype, filepath))
return (self._filesystem.read_text_file(filepath) or '')
else:
- _log.warning(
- "%s test_expectations overrides file '%s' does not exist" %
- (filetype, filepath))
+ # FIXME: This allows this to work with mock checkouts;
+ # This probably shouldn't be used with a mock checkout, though.
+ if not 'mock-checkout' in filepath:
+ _log.warning(
+ "%s test_expectations overrides file '%s' does not exist" %
+ (filetype, filepath))
return ''
def test_expectations_overrides(self):
Modified: trunk/Tools/Scripts/webkitpy/tool/commands/rebaseline.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/tool/commands/rebaseline.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/tool/commands/rebaseline.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -26,6 +26,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import json
+import logging
import optparse
import os.path
import re
@@ -51,16 +53,19 @@
_baseline_suffix_list = ['png', 'wav', 'txt']
+_log = logging.getLogger(__name__)
+
# FIXME: Should TestResultWriter know how to compute this string?
def _baseline_name(fs, test_name, suffix):
return fs.splitext(test_name)[0] + TestResultWriter.FILENAME_SUFFIX_EXPECTED + "." + suffix
class AbstractRebaseliningCommand(AbstractDeclarativeCommand):
- def __init__(self):
- options = [
+ def __init__(self, options=None):
+ options = options or []
+ options.extend([
optparse.make_option('--suffixes', default=','.join(_baseline_suffix_list), action='',
- help='file types to rebaseline')]
+ help='file types to rebaseline')])
AbstractDeclarativeCommand.__init__(self, options=options)
self._baseline_suffix_list = _baseline_suffix_list
@@ -70,6 +75,14 @@
help_text = "Rebaseline a single test from a buildbot. (Currently works only with build.chromium.org buildbots.)"
argument_names = "BUILDER_NAME TEST_NAME [PLATFORMS_TO_MOVE_EXISTING_BASELINES_TO]"
+ def __init__(self):
+ options = [
+ optparse.make_option("--print-scm-changes", action="" help="Print modifcations to the scm (as a json dict) rather than actually modifying the scm"),
+ ]
+ AbstractRebaseliningCommand.__init__(self, options=options)
+ self._print_scm_changes = False
+ self._scm_changes = {}
+
def _results_url(self, builder_name):
# FIXME: Generalize this command to work with non-build.chromium.org builders.
builder = self._tool.chromium_buildbot().builder_with_name(builder_name)
@@ -89,12 +102,12 @@
port = self._tool.port_factory.get(platform)
old_baseline = port.expected_filename(test_name, "." + suffix)
if not self._tool.filesystem.exists(old_baseline):
- print("No existing baseline for %s." % test_name)
+ _log.info("No existing baseline for %s." % test_name)
continue
new_baseline = self._tool.filesystem.join(port.baseline_path(), self._file_name_for_expected_result(test_name, suffix))
if self._tool.filesystem.exists(new_baseline):
- print("Existing baseline at %s, not copying over it." % new_baseline)
+ _log.info("Existing baseline at %s, not copying over it." % new_baseline)
continue
old_baselines.append(old_baseline)
@@ -104,11 +117,11 @@
old_baseline = old_baselines[i]
new_baseline = new_baselines[i]
- print("Copying baseline from %s to %s." % (old_baseline, new_baseline))
+ _log.info("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)
if not self._tool.scm().exists(new_baseline):
- self._tool.scm().add(new_baseline)
+ self._add_to_scm(new_baseline)
def _save_baseline(self, data, target_baseline):
if not data:
@@ -117,8 +130,14 @@
filesystem.maybe_make_directory(filesystem.dirname(target_baseline))
filesystem.write_binary_file(target_baseline, data)
if not self._tool.scm().exists(target_baseline):
- self._tool.scm().add(target_baseline)
+ self._add_to_scm(target_baseline)
+ def _add_to_scm(self, path):
+ if self._print_scm_changes:
+ self._scm_changes['add'].append(path)
+ else:
+ self._tool.scm().add(path)
+
def _update_expectations_file(self, builder_name, test_name):
port = self._tool.port_factory.get_from_builder_name(builder_name)
expectations = TestExpectations(port)
@@ -148,7 +167,7 @@
if platforms_to_move_existing_baselines_to:
self._copy_existing_baseline(platforms_to_move_existing_baselines_to, test_name, suffix)
- print "Retrieving %s." % source_baseline
+ _log.info("Retrieving %s." % source_baseline)
self._save_baseline(self._tool.web.get_binary(source_baseline, convert_404_to_None=True), target_baseline)
def _rebaseline_test_and_update_expectations(self, builder_name, test_name, platforms_to_move_existing_baselines_to):
@@ -158,12 +177,16 @@
def execute(self, options, args, tool):
self._baseline_suffix_list = options.suffixes.split(',')
+ self._print_scm_changes = options.print_scm_changes
+ self._scm_changes = {'add': [], 'rm': []}
if len(args) > 2:
platforms_to_move_existing_baselines_to = args[2:]
else:
platforms_to_move_existing_baselines_to = None
self._rebaseline_test_and_update_expectations(args[0], args[1], platforms_to_move_existing_baselines_to)
+ if self._print_scm_changes:
+ print json.dumps(self._scm_changes)
class OptimizeBaselines(AbstractRebaseliningCommand):
@@ -257,10 +280,10 @@
builder_name = builders.builder_name_for_port_name(port_name)
if not builder_name:
return
- print "Retrieving results for %s from %s." % (port_name, builder_name)
+ _log.info("Retrieving results for %s from %s." % (port_name, builder_name))
for test_name in self._tests_to_rebaseline(self._tool.port_factory.get(port_name)):
self._touched_test_names.add(test_name)
- print " %s" % test_name
+ _log.info(" %s" % test_name)
# FIXME: need to extract the correct list of suffixes here.
self._run_webkit_patch(['rebaseline-test', builder_name, test_name])
@@ -273,7 +296,7 @@
if not options.optimize:
return
for test_name in self._touched_test_names:
- print "Optimizing baselines for %s." % test_name
+ _log.info("Optimizing baselines for %s." % test_name)
self._run_webkit_patch(['optimize-baselines', test_name])
@@ -285,7 +308,7 @@
def _builder_to_pull_from(self):
builder_statuses = self._tool.buildbot.builder_statuses()
red_statuses = [status for status in builder_statuses if not status["is_green"]]
- print "%s failing" % (pluralize("builder", len(red_statuses)))
+ _log.info("%s failing" % (pluralize("builder", len(red_statuses))))
builder_choices = [status["name"] for status in red_statuses]
chosen_name = self._tool.user.prompt_with_list("Which builder to pull results from:", builder_choices)
# FIXME: prompt_with_list should really take a set of objects and a set of names and then return the object.
@@ -315,7 +338,7 @@
results_url = self._results_url_for_test(build, test)
# Port operates with absolute paths.
expected_file = port.expected_filename(test, '.txt')
- print test
+ _log.info(test)
self._replace_expectation_with_remote_result(expected_file, results_url)
# FIXME: We should handle new results too.
Modified: trunk/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -55,11 +55,11 @@
tool.filesystem.write_text_file(os.path.join(lion_port.layout_tests_dir(), "fast/css/large-list-of-rules-crash.html"), "Dummy test contents")
tool.filesystem.write_text_file(os.path.join(lion_port.layout_tests_dir(), "userscripts/another-test.html"), "Dummy test contents")
- expected_stdout = """Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.png.
+ expected_logs = """Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.png.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.wav.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt.
"""
- OutputCapture().assert_outputs(self, command._rebaseline_test_and_update_expectations, ["Webkit Mac10.7", "userscripts/another-test.html", None], expected_stdout=expected_stdout)
+ OutputCapture().assert_outputs(self, command._rebaseline_test_and_update_expectations, ["Webkit Mac10.7", "userscripts/another-test.html", None], expected_logs=expected_logs)
new_expectations = tool.filesystem.read_text_file(lion_port.path_to_test_expectations_file())
self.assertEqual(new_expectations, """BUGB MAC LINUX XP DEBUG : fast/dom/Window/window-postmessage-clone-really-deep-array.html = PASS
@@ -75,11 +75,11 @@
tool.filesystem.write_text_file(lion_port.path_to_test_expectations_file(), "BUGX MAC : userscripts/another-test.html = IMAGE\nBUGZ LINUX : userscripts/another-test.html = IMAGE\n")
tool.filesystem.write_text_file(os.path.join(lion_port.layout_tests_dir(), "userscripts/another-test.html"), "Dummy test contents")
- expected_stdout = """Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.png.
+ expected_logs = """Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.png.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.wav.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt.
"""
- OutputCapture().assert_outputs(self, command._rebaseline_test_and_update_expectations, ["Webkit Mac10.7", "userscripts/another-test.html", None], expected_stdout=expected_stdout)
+ OutputCapture().assert_outputs(self, command._rebaseline_test_and_update_expectations, ["Webkit Mac10.7", "userscripts/another-test.html", None], expected_logs=expected_logs)
new_expectations = tool.filesystem.read_text_file(lion_port.path_to_test_expectations_file())
self.assertEqual(new_expectations, "BUGX LEOPARD SNOWLEOPARD : userscripts/another-test.html = IMAGE\nBUGZ LINUX : userscripts/another-test.html = IMAGE\n")
@@ -87,9 +87,19 @@
def test_rebaseline_test(self):
command = RebaselineTest()
command.bind_to_tool(MockTool())
- expected_stdout = "Retrieving http://example.com/f/builders/Webkit Linux/results/layout-test-results/userscripts/another-test-actual.txt.\n"
- OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Linux", "userscripts/another-test.html", None, "txt"], expected_stdout=expected_stdout)
+ expected_logs = "Retrieving http://example.com/f/builders/Webkit Linux/results/layout-test-results/userscripts/another-test-actual.txt.\n"
+ OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Linux", "userscripts/another-test.html", None, "txt"], expected_logs=expected_logs)
+ def test_rebaseline_test_and_print_scm_changes(self):
+ command = RebaselineTest()
+ command.bind_to_tool(MockTool())
+ expected_logs = "Retrieving http://example.com/f/builders/Webkit Linux/results/layout-test-results/userscripts/another-test-actual.txt.\n"
+ command._print_scm_changes = True
+ command._scm_changes = {'add': [], 'rm': []}
+ command._tool._scm.exists = lambda x: False
+ OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Linux", "userscripts/another-test.html", None, "txt"], expected_logs=expected_logs)
+ self.assertEquals(command._scm_changes, {'add': ['/mock-checkout/LayoutTests/platform/chromium-linux/userscripts/another-test-expected.txt'], 'rm': []})
+
def test_rebaseline_and_copy_test(self):
command = RebaselineTest()
tool = MockTool()
@@ -98,20 +108,20 @@
lion_port = tool.port_factory.get_from_builder_name("Webkit Mac10.7")
tool.filesystem.write_text_file(os.path.join(lion_port.layout_tests_dir(), "userscripts/another-test-expected.txt"), "Dummy expected result")
- expected_stdout = """Copying baseline from /mock-checkout/LayoutTests/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt.
+ expected_logs = """Copying baseline from /mock-checkout/LayoutTests/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt.
"""
- OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard"], "txt"], expected_stdout=expected_stdout)
+ OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard"], "txt"], expected_logs=expected_logs)
def test_rebaseline_and_copy_test_no_existing_result(self):
command = RebaselineTest()
tool = MockTool()
command.bind_to_tool(tool)
- expected_stdout = """No existing baseline for userscripts/another-test.html.
+ expected_logs = """No existing baseline for userscripts/another-test.html.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt.
"""
- OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard"], "txt"], expected_stdout=expected_stdout)
+ OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard"], "txt"], expected_logs=expected_logs)
def test_rebaseline_and_copy_test_with_lion_result(self):
command = RebaselineTest()
@@ -121,11 +131,11 @@
lion_port = tool.port_factory.get_from_builder_name("Webkit Mac10.7")
tool.filesystem.write_text_file(os.path.join(lion_port.baseline_path(), "userscripts/another-test-expected.txt"), "Dummy expected result")
- expected_stdout = """Copying baseline from /mock-checkout/LayoutTests/platform/chromium-mac/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt.
+ expected_logs = """Copying baseline from /mock-checkout/LayoutTests/platform/chromium-mac/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt.
Copying baseline from /mock-checkout/LayoutTests/platform/chromium-mac/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-leopard/userscripts/another-test-expected.txt.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt.
"""
- OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard", "chromium-mac-leopard"], "txt"], expected_stdout=expected_stdout)
+ OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard", "chromium-mac-leopard"], "txt"], expected_logs=expected_logs)
def test_rebaseline_and_copy_no_overwrite_test(self):
command = RebaselineTest()
@@ -138,10 +148,10 @@
snowleopard_port = tool.port_factory.get_from_builder_name("Webkit Mac10.6")
tool.filesystem.write_text_file(os.path.join(snowleopard_port.baseline_path(), "userscripts/another-test-expected.txt"), "Dummy expected result")
- expected_stdout = """Existing baseline at /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt, not copying over it.
+ expected_logs = """Existing baseline at /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt, not copying over it.
Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt.
"""
- OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard"], "txt"], expected_stdout=expected_stdout)
+ OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", ["chromium-mac-snowleopard"], "txt"], expected_logs=expected_logs)
def test_rebaseline_expectations(self):
command = RebaselineExpectations()
@@ -155,7 +165,7 @@
# Don't enable logging until after we create the mock expectation files as some Port.__init__'s run subcommands.
tool.executive = MockExecutive(should_log=True)
- expected_stdout = """Retrieving results for chromium-linux-x86 from Webkit Linux 32.
+ expected_logs = """Retrieving results for chromium-linux-x86 from Webkit Linux 32.
userscripts/another-test.html
userscripts/images.svg
Retrieving results for chromium-linux-x86_64 from Webkit Linux.
@@ -200,9 +210,9 @@
"""
command._tests_to_rebaseline = lambda port: ['userscripts/another-test.html', 'userscripts/images.svg']
- OutputCapture().assert_outputs(self, command.execute, [MockOptions(optimize=False), [], tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ OutputCapture().assert_outputs(self, command.execute, [MockOptions(optimize=False), [], tool], expected_logs=expected_logs, expected_stderr=expected_stderr)
- expected_stdout_with_optimize = expected_stdout + (
+ expected_logs_with_optimize = expected_logs + (
"Optimizing baselines for userscripts/another-test.html.\n"
"Optimizing baselines for userscripts/images.svg.\n")
expected_stderr_with_optimize = expected_stderr + (
@@ -210,4 +220,4 @@
"MOCK run_command: ['echo', 'optimize-baselines', 'userscripts/images.svg'], cwd=/mock-checkout\n")
command._tests_to_rebaseline = lambda port: ['userscripts/another-test.html', 'userscripts/images.svg']
- OutputCapture().assert_outputs(self, command.execute, [MockOptions(optimize=True), [], tool], expected_stdout=expected_stdout_with_optimize, expected_stderr=expected_stderr_with_optimize)
+ OutputCapture().assert_outputs(self, command.execute, [MockOptions(optimize=True), [], tool], expected_logs=expected_logs_with_optimize, expected_stderr=expected_stderr_with_optimize)
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -23,6 +23,8 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import BaseHTTPServer
+import logging
+import json
import os
from webkitpy.common.memoized import memoized
@@ -33,6 +35,9 @@
from webkitpy.layout_tests.port import builders
+_log = logging.getLogger(__name__)
+
+
class BuildCoverageExtrapolator(object):
def __init__(self, test_configuration_converter):
self._test_configuration_converter = test_configuration_converter
@@ -171,15 +176,43 @@
builders_to_fallback_paths[builder] = fallback_path
return builders_to_fallback_paths.keys()
- def rebaselineall(self):
- # FIXME: Optimize this to run in parallel, cache zips, etc.
- test_list = self._read_entity_body_as_json()
+ def _rebaseline_commands(self, test_list):
+ path_to_webkit_patch = self.server.tool.path()
+ cwd = self.server.tool.scm().checkout_root
+ commands = []
for test in test_list:
+ for builder in self._builders_to_fetch_from(test_list[test]):
+ suffixes = ','.join(test_list[test][builder])
+ cmd_line = [path_to_webkit_patch, 'rebaseline-test', '--print-scm-changes', '--suffixes', suffixes, builder, test]
+ commands.append(tuple([cmd_line, cwd]))
+ return commands
+
+ def _files_to_add(self, command_results):
+ files_to_add = set()
+ for output in [result[1] for result in command_results]:
+ try:
+ files_to_add.update(json.loads(output)['add'])
+ except ValueError, e:
+ _log.warning('"%s" is not a JSON object, ignoring' % output)
+
+ return list(files_to_add)
+
+ def _optimize_baselines(self, test_list):
+ # We don't run this in parallel because modifying the SCM in parallel is unreliable.
+ for test in test_list:
all_suffixes = set()
- builders = self._builders_to_fetch_from(test_list[test])
- for builder in builders:
- suffixes = test_list[test][builder]
- all_suffixes.update(suffixes)
- self._run_webkit_patch(['rebaseline-test', '--suffixes', ','.join(suffixes), builder, test])
+ for builder in self._builders_to_fetch_from(test_list[test]):
+ all_suffixes.update(test_list[test][builder])
self._run_webkit_patch(['optimize-baselines', '--suffixes', ','.join(all_suffixes), test])
+
+ def rebaselineall(self):
+ test_list = self._read_entity_body_as_json()
+
+ commands = self._rebaseline_commands(test_list)
+ command_results = self.server.tool.executive.run_in_parallel(commands)
+
+ files_to_add = self._files_to_add(command_results)
+ self.server.tool.scm().add_list(list(files_to_add))
+
+ self._optimize_baselines(test_list)
self._serve_text('success')
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py (118835 => 118836)
--- trunk/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py 2012-05-29 21:20:30 UTC (rev 118835)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py 2012-05-29 21:30:41 UTC (rev 118836)
@@ -27,6 +27,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import json
+import sys
import unittest
from webkitpy.common.system.outputcapture import OutputCapture
@@ -170,8 +171,8 @@
class GardeningServerTest(unittest.TestCase):
- def _post_to_path(self, path, body=None, expected_stderr=None, expected_stdout=None):
- handler = TestGardeningHTTPRequestHandler(MockServer())
+ def _post_to_path(self, path, body=None, expected_stderr=None, expected_stdout=None, server=None):
+ handler = TestGardeningHTTPRequestHandler(server or MockServer())
handler.path = path
handler.body = body
OutputCapture().assert_outputs(self, handler.do_POST, expected_stderr=expected_stderr, expected_stdout=expected_stdout)
@@ -186,10 +187,19 @@
"MOCK builder": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
"MOCK builder (Debug)": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier", "debug"])},
}
- expected_stderr = "MOCK run_command: ['echo', 'rebaseline-test', '--suffixes', u'%s', u'%s', u'user-scripts/another-test.html'], cwd=/mock-checkout\nMOCK run_command: ['echo', 'optimize-baselines', '--suffixes', u'%s', u'user-scripts/another-test.html'], cwd=/mock-checkout\n"
+ expected_stderr = "MOCK run_command: ['echo', 'rebaseline-test', '--print-scm-changes', '--suffixes', u'%s', u'%s', u'user-scripts/another-test.html'], cwd=/mock-checkout\nMOCK run_command: ['echo', 'optimize-baselines', '--suffixes', u'%s', u'user-scripts/another-test.html'], cwd=/mock-checkout\n"
expected_stdout = "== Begin Response ==\nsuccess\n== End Response ==\n"
- self._post_to_path("/rebaselineall", body='{"user-scripts/another-test.html":{"MOCK builder": ["txt","png"]}}', expected_stderr=expected_stderr % ('txt,png', 'MOCK builder', 'txt,png'), expected_stdout=expected_stdout)
+ server = MockServer()
+ self.output = ['{"add": [], "rm": []}', '']
+
+ def run_command(args, cwd=None, **kwargs):
+ print >> sys.stderr, "MOCK run_command: %s, cwd=%s" % (args, cwd)
+ return self.output.pop(0)
+
+ server.tool.executive.run_command = run_command
+ self._post_to_path("/rebaselineall", body='{"user-scripts/another-test.html":{"MOCK builder": ["txt","png"]}}', expected_stderr=expected_stderr % ('txt,png', 'MOCK builder', 'txt,png'), expected_stdout=expected_stdout, server=server)
+
self._post_to_path("/rebaselineall", body='{"user-scripts/another-test.html":{"MOCK builder (Debug)": ["txt","png"]}}', expected_stderr=expected_stderr % ('txt,png', 'MOCK builder (Debug)', 'txt,png'), expected_stdout=expected_stdout)
self._post_to_path("/rebaselineall", body='{"user-scripts/another-test.html":{"MOCK builder (Debug)": ["txt","png"], "MOCK builder": ["txt"]}}', expected_stderr=expected_stderr % ('txt', 'MOCK builder', 'txt'), expected_stdout=expected_stdout)