summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py')
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py268
1 files changed, 0 insertions, 268 deletions
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
deleted file mode 100644
index 2924a6f..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
+++ /dev/null
@@ -1,268 +0,0 @@
-# Copyright (c) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Starts a local HTTP server which displays layout test failures (given a test
-results directory), provides comparisons of expected and actual results (both
-images and text) and allows one-click rebaselining of tests."""
-from __future__ import with_statement
-
-import codecs
-import datetime
-import mimetypes
-import os
-import os.path
-import shutil
-import threading
-import time
-import urlparse
-import BaseHTTPServer
-
-from optparse import make_option
-from wsgiref.handlers import format_date_time
-
-from webkitpy.common import system
-from webkitpy.layout_tests.port import factory
-from webkitpy.layout_tests.port.webkit import WebKitPort
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.thirdparty import simplejson
-
-STATE_NEEDS_REBASELINE = 'needs_rebaseline'
-STATE_REBASELINE_FAILED = 'rebaseline_failed'
-STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded'
-
-class RebaselineHTTPServer(BaseHTTPServer.HTTPServer):
- def __init__(self, httpd_port, results_directory, results_json, platforms_json):
- BaseHTTPServer.HTTPServer.__init__(self, ("", httpd_port), RebaselineHTTPRequestHandler)
- self.results_directory = results_directory
- self.results_json = results_json
- self.platforms_json = platforms_json
-
-
-class RebaselineHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- STATIC_FILE_NAMES = frozenset([
- "index.html",
- "loupe.js",
- "main.js",
- "main.css",
- "queue.js",
- "util.js",
- ])
-
- STATIC_FILE_DIRECTORY = os.path.join(
- os.path.dirname(__file__), "data", "rebaselineserver")
-
- def do_GET(self):
- self._handle_request()
-
- def do_POST(self):
- self._handle_request()
-
- def _handle_request(self):
- # Parse input.
- if "?" in self.path:
- path, query_string = self.path.split("?", 1)
- self.query = urlparse.parse_qs(query_string)
- else:
- path = self.path
- self.query = {}
- function_or_file_name = path[1:] or "index.html"
-
- # See if a static file matches.
- if function_or_file_name in RebaselineHTTPRequestHandler.STATIC_FILE_NAMES:
- self._serve_static_file(function_or_file_name)
- return
-
- # See if a class method matches.
- function_name = function_or_file_name.replace(".", "_")
- if not hasattr(self, function_name):
- self.send_error(404, "Unknown function %s" % function_name)
- return
- if function_name[0] == "_":
- self.send_error(
- 401, "Not allowed to invoke private or protected methods")
- return
- function = getattr(self, function_name)
- function()
-
- def _serve_static_file(self, static_path):
- self._serve_file(os.path.join(
- RebaselineHTTPRequestHandler.STATIC_FILE_DIRECTORY, static_path))
-
- def quitquitquit(self):
- self.send_response(200)
- self.send_header("Content-type", "text/plain")
- self.end_headers()
- self.wfile.write("Quit.\n")
-
- # Shutdown has to happen on another thread from the server's thread,
- # otherwise there's a deadlock
- threading.Thread(target=lambda: self.server.shutdown()).start()
-
- def test_result(self):
- test_name, _ = os.path.splitext(self.query['test'][0])
- mode = self.query['mode'][0]
- if mode == 'expected-image':
- file_name = test_name + '-expected.png'
- elif mode == 'actual-image':
- file_name = test_name + '-actual.png'
- if mode == 'expected-checksum':
- file_name = test_name + '-expected.checksum'
- elif mode == 'actual-checksum':
- file_name = test_name + '-actual.checksum'
- elif mode == 'diff-image':
- file_name = test_name + '-diff.png'
- if mode == 'expected-text':
- file_name = test_name + '-expected.txt'
- elif mode == 'actual-text':
- file_name = test_name + '-actual.txt'
- elif mode == 'diff-text':
- file_name = test_name + '-diff.txt'
-
- file_path = os.path.join(self.server.results_directory, file_name)
-
- # Let results be cached for 60 seconds, so that they can be pre-fetched
- # by the UI
- self._serve_file(file_path, cacheable_seconds=60)
-
- def results_json(self):
- self._serve_json(self.server.results_json)
-
- def platforms_json(self):
- self._serve_json(self.server.platforms_json)
-
- def _serve_json(self, json):
- self.send_response(200)
- self.send_header('Content-type', 'application/json')
- self.end_headers()
- simplejson.dump(json, self.wfile)
-
- def _serve_file(self, file_path, cacheable_seconds=0):
- if not os.path.exists(file_path):
- self.send_error(404, "File not found")
- return
- with codecs.open(file_path, "rb") as static_file:
- self.send_response(200)
- self.send_header("Content-Length", os.path.getsize(file_path))
- mime_type, encoding = mimetypes.guess_type(file_path)
- if mime_type:
- self.send_header("Content-type", mime_type)
-
- if cacheable_seconds:
- expires_time = (datetime.datetime.now() +
- datetime.timedelta(0, cacheable_seconds))
- expires_formatted = format_date_time(
- time.mktime(expires_time.timetuple()))
- self.send_header("Expires", expires_formatted)
- self.end_headers()
-
- shutil.copyfileobj(static_file, self.wfile)
-
-
-def _get_test_baselines(test_file, layout_tests_directory, platforms, filesystem):
- class AllPlatformsPort(WebKitPort):
- def __init__(self):
- WebKitPort.__init__(self, filesystem=filesystem)
- self._platforms_by_directory = dict(
- [(self._webkit_baseline_path(p), p) for p in platforms])
-
- def baseline_search_path(self):
- return self._platforms_by_directory.keys()
-
- def platform_from_directory(self, directory):
- return self._platforms_by_directory[directory]
-
- all_platforms_port = AllPlatformsPort()
-
- test_baselines = {}
- for baseline_extension in ('.txt', '.checksum', '.png'):
- test_path = filesystem.join(layout_tests_directory, test_file)
- baselines = all_platforms_port.expected_baselines(
- test_path, baseline_extension, all_baselines=True)
- for platform_directory, expected_filename in baselines:
- if not platform_directory:
- continue
- if platform_directory == layout_tests_directory:
- platform = 'base'
- else:
- platform = all_platforms_port.platform_from_directory(
- platform_directory)
- if platform not in test_baselines:
- test_baselines[platform] = []
- test_baselines[platform].append(baseline_extension)
-
- for platform, extensions in test_baselines.items():
- test_baselines[platform] = tuple(extensions)
-
- return test_baselines
-
-class RebaselineServer(AbstractDeclarativeCommand):
- name = "rebaseline-server"
- help_text = __doc__
- argument_names = "/path/to/results/directory"
-
- def __init__(self):
- options = [
- make_option("--httpd-port", action="store", type="int", default=8127, help="Port to use for the the rebaseline HTTP server"),
- ]
- AbstractDeclarativeCommand.__init__(self, options=options)
-
- def execute(self, options, args, tool):
- results_directory = args[0]
- filesystem = system.filesystem.FileSystem()
-
- print 'Parsing unexpected_results.json...'
- results_json_path = filesystem.join(
- results_directory, 'unexpected_results.json')
- with codecs.open(results_json_path, "r") as results_json_file:
- results_json_file = file(results_json_path)
- results_json = simplejson.load(results_json_file)
-
- port = factory.get()
- layout_tests_directory = port.layout_tests_dir()
- platforms = filesystem.listdir(
- filesystem.join(layout_tests_directory, 'platform'))
-
- print 'Gathering current baselines...'
- for test_file, test_json in results_json['tests'].items():
- test_json['state'] = STATE_NEEDS_REBASELINE
- test_json['baselines'] = _get_test_baselines(
- test_file, layout_tests_directory, platforms, filesystem)
-
- print "Starting server at http://localhost:%d/" % options.httpd_port
- print ("Use the 'Exit' link in the UI, http://localhost:%d/"
- "quitquitquit or Ctrl-C to stop") % options.httpd_port
-
- httpd = RebaselineHTTPServer(
- httpd_port=options.httpd_port,
- results_directory=results_directory,
- results_json=results_json,
- platforms_json={
- 'platforms': platforms,
- 'defaultPlatform': port.name(),
- })
- httpd.serve_forever()