summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/layout_tests/port
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/layout_tests/port')
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/__init__.py49
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/apache_http_server.py37
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/base.py645
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py260
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py327
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py293
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py293
-rwxr-xr-xWebKitTools/Scripts/webkitpy/layout_tests/port/http_server.py97
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/http_server_base.py11
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py439
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/path_utils.py395
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/test.py144
-rw-r--r--WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py103
13 files changed, 1994 insertions, 1099 deletions
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/__init__.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/__init__.py
index 1730085..3509675 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/__init__.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/__init__.py
@@ -27,24 +27,39 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Platform-specific utilities and pseudo-constants
+"""Port-specific entrypoints for the layout tests test infrastructure."""
-Any functions whose implementations or values differ from one platform to
-another should be defined in their respective <platform>.py
-modules. The appropriate one of those will be imported into this module to
-provide callers with a common, platform-independent interface.
-
-This file should only ever be imported by layout_package.path_utils.
-"""
import sys
-# We may not support the version of Python that a user has installed (Cygwin
-# especially has had problems), but we'll allow the platform utils to be
-# included in any case so we don't get an import error.
-if sys.platform in ('cygwin', 'win32'):
- from chromium_win import *
-elif sys.platform == 'darwin':
- from chromium_mac import *
-elif sys.platform in ('linux', 'linux2', 'freebsd7', 'openbsd4'):
- from chromium_linux import *
+
+def get(port_name=None, options=None):
+ """Returns an object implementing the Port interface. If
+ port_name is None, this routine attempts to guess at the most
+ appropriate port on this platform."""
+ port_to_use = port_name
+ if port_to_use is None:
+ if sys.platform == 'win32':
+ port_to_use = 'chromium-win'
+ elif sys.platform == 'linux2':
+ port_to_use = 'chromium-linux'
+ elif sys.platform == 'darwin':
+ port_to_use = 'chromium-mac'
+
+ if port_to_use == 'test':
+ import test
+ return test.TestPort(port_name, options)
+ elif port_to_use.startswith('mac'):
+ import mac
+ return mac.MacPort(port_name, options)
+ elif port_to_use.startswith('chromium-mac'):
+ import chromium_mac
+ return chromium_mac.ChromiumMacPort(port_name, options)
+ elif port_to_use.startswith('chromium-linux'):
+ import chromium_linux
+ return chromium_linux.ChromiumLinuxPort(port_name, options)
+ elif port_to_use.startswith('chromium-win'):
+ import chromium_win
+ return chromium_win.ChromiumWinPort(port_name, options)
+
+ raise NotImplementedError('unsupported port: %s' % port_to_use)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/apache_http_server.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/apache_http_server.py
index 1fb0367..9ff3671 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/apache_http_server.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/apache_http_server.py
@@ -37,19 +37,19 @@ import subprocess
import sys
import http_server_base
-import path_utils
-import port
class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
- def __init__(self, output_dir):
+ def __init__(self, port_obj, output_dir):
"""Args:
+ port_obj: handle to the platform-specific routines
output_dir: the absolute path to the layout test result directory
"""
+ http_server_base.HttpServerBase.__init__(self, port_obj)
self._output_dir = output_dir
self._httpd_proc = None
- path_utils.maybe_make_directory(output_dir)
+ port_obj.maybe_make_directory(output_dir)
self.mappings = [{'port': 8000},
{'port': 8080},
@@ -59,15 +59,14 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
# The upstream .conf file assumed the existence of /tmp/WebKit for
# placing apache files like the lock file there.
self._runtime_path = os.path.join("/tmp", "WebKit")
- path_utils.maybe_make_directory(self._runtime_path)
+ port_obj.maybe_make_directory(self._runtime_path)
# The PID returned when Apache is started goes away (due to dropping
# privileges?). The proper controlling PID is written to a file in the
# apache runtime directory.
self._pid_file = os.path.join(self._runtime_path, 'httpd.pid')
- test_dir = path_utils.path_from_base('third_party', 'WebKit',
- 'LayoutTests')
+ test_dir = self._port_obj.layout_tests_dir()
js_test_resources_dir = self._cygwin_safe_join(test_dir, "fast", "js",
"resources")
mime_types_path = self._cygwin_safe_join(test_dir, "http", "conf",
@@ -78,7 +77,7 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
error_log = self._cygwin_safe_join(output_dir, "error_log.txt")
document_root = self._cygwin_safe_join(test_dir, "http", "tests")
- executable = port.apache_executable_path()
+ executable = self._port_obj._path_to_apache()
if self._is_cygwin():
executable = self._get_cygwin_path(executable)
@@ -95,7 +94,8 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
os.environ.get("USER", ""))]
if self._is_cygwin():
- cygbin = path_utils.path_from_base('third_party', 'cygwin', 'bin')
+ cygbin = self._port_obj._path_from_base('third_party', 'cygwin',
+ 'bin')
# Not entirely sure why, but from cygwin we need to run the
# httpd command through bash.
self._start_cmd = [
@@ -146,7 +146,7 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
test_dir: absolute path to the LayoutTests directory.
output_dir: absolute path to the layout test results directory.
"""
- httpd_config = port.apache_config_file_path()
+ httpd_config = self._port_obj._path_to_apache_config_file()
httpd_config_copy = os.path.join(output_dir, "httpd.conf")
httpd_conf = open(httpd_config).read()
if self._is_cygwin():
@@ -156,22 +156,11 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
# plus the relative paths to the .so files listed in the .conf
# file. We have apache/cygwin checked into our tree so
# people don't have to install it into their cygwin.
- cygusr = path_utils.path_from_base('third_party', 'cygwin', 'usr')
+ cygusr = self._port_obj._path_from_base('third_party', 'cygwin',
+ 'usr')
httpd_conf = httpd_conf.replace('ServerRoot "/usr"',
'ServerRoot "%s"' % self._get_cygwin_path(cygusr))
- # TODO(ojan): Instead of writing an extra file, checkin a conf file
- # upstream. Or, even better, upstream/delete all our chrome http
- # tests so we don't need this special-cased DocumentRoot and then
- # just use the upstream
- # conf file.
- chrome_document_root = path_utils.path_from_base('webkit', 'data',
- 'layout_tests')
- if self._is_cygwin():
- chrome_document_root = self._get_cygwin_path(chrome_document_root)
- httpd_conf = (httpd_conf +
- self._get_virtual_host_config(chrome_document_root, 8081))
-
f = open(httpd_config_copy, 'wb')
f.write(httpd_conf)
f.close()
@@ -226,4 +215,4 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
httpd_pid = None
if os.path.exists(self._pid_file):
httpd_pid = int(open(self._pid_file).readline())
- path_utils.shut_down_http_server(httpd_pid)
+ self._port_obj._shut_down_http_server(httpd_pid)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
new file mode 100644
index 0000000..ce06b44
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
@@ -0,0 +1,645 @@
+#!/usr/bin/env python
+# 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 Google name 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.
+
+"""Abstract base class of Port-specific entrypoints for the layout tests
+test infrastructure (the Port and Driver classes)."""
+
+import cgi
+import difflib
+import errno
+import os
+import subprocess
+import sys
+
+import apache_http_server
+import http_server
+import websocket_server
+
+# Python bug workaround. See Port.wdiff_text() for an explanation.
+_wdiff_available = True
+
+
+# FIXME: This class should merge with webkitpy.webkit_port at some point.
+class Port(object):
+ """Abstract class for Port-specific hooks for the layout_test package.
+ """
+
+ def __init__(self, port_name=None, options=None):
+ self._name = port_name
+ self._options = options
+ self._helper = None
+ self._http_server = None
+ self._webkit_base_dir = None
+ self._websocket_server = None
+
+ def baseline_path(self):
+ """Return the absolute path to the directory to store new baselines
+ in for this port."""
+ raise NotImplementedError('Port.baseline_path')
+
+ def baseline_search_path(self):
+ """Return a list of absolute paths to directories to search under for
+ baselines. The directories are searched in order."""
+ raise NotImplementedError('Port.baseline_search_path')
+
+ def check_sys_deps(self):
+ """If the port needs to do some runtime checks to ensure that the
+ tests can be run successfully, they should be done here.
+
+ Returns whether the system is properly configured."""
+ raise NotImplementedError('Port.check_sys_deps')
+
+ def compare_text(self, actual_text, expected_text):
+ """Return whether or not the two strings are *not* equal. This
+ routine is used to diff text output.
+
+ While this is a generic routine, we include it in the Port
+ interface so that it can be overriden for testing purposes."""
+ return actual_text != expected_text
+
+ def diff_image(self, actual_filename, expected_filename, diff_filename):
+ """Compare two image files and produce a delta image file.
+
+ Return 1 if the two files are different, 0 if they are the same.
+ Also produce a delta image of the two images and write that into
+ |diff_filename|.
+
+ While this is a generic routine, we include it in the Port
+ interface so that it can be overriden for testing purposes."""
+ executable = self._path_to_image_diff()
+ cmd = [executable, '--diff', actual_filename, expected_filename,
+ diff_filename]
+ result = 1
+ try:
+ result = subprocess.call(cmd)
+ except OSError, e:
+ if e.errno == errno.ENOENT or e.errno == errno.EACCES:
+ _compare_available = False
+ else:
+ raise e
+ except ValueError:
+ # work around a race condition in Python 2.4's implementation
+ # of subprocess.Popen. See http://bugs.python.org/issue1199282 .
+ pass
+ return result
+
+ def diff_text(self, actual_text, expected_text,
+ actual_filename, expected_filename):
+ """Returns a string containing the diff of the two text strings
+ in 'unified diff' format.
+
+ While this is a generic routine, we include it in the Port
+ interface so that it can be overriden for testing purposes."""
+ diff = difflib.unified_diff(expected_text.splitlines(True),
+ actual_text.splitlines(True),
+ expected_filename,
+ actual_filename)
+ return ''.join(diff)
+
+ def expected_baselines(self, filename, suffix, all_baselines=False):
+ """Given a test name, finds where the baseline results are located.
+
+ Args:
+ filename: absolute filename to test file
+ suffix: file suffix of the expected results, including dot; e.g.
+ '.txt' or '.png'. This should not be None, but may be an empty
+ string.
+ all_baselines: If True, return an ordered list of all baseline paths
+ for the given platform. If False, return only the first one.
+ Returns
+ a list of ( platform_dir, results_filename ), where
+ platform_dir - abs path to the top of the results tree (or test
+ tree)
+ results_filename - relative path from top of tree to the results
+ file
+ (os.path.join of the two gives you the full path to the file,
+ unless None was returned.)
+ Return values will be in the format appropriate for the current
+ platform (e.g., "\\" for path separators on Windows). If the results
+ file is not found, then None will be returned for the directory,
+ but the expected relative pathname will still be returned.
+
+ This routine is generic but lives here since it is used in
+ conjunction with the other baseline and filename routines that are
+ platform specific.
+ """
+ testname = os.path.splitext(self.relative_test_filename(filename))[0]
+
+ baseline_filename = testname + '-expected' + suffix
+
+ baseline_search_path = self.baseline_search_path()
+
+ baselines = []
+ for platform_dir in baseline_search_path:
+ if os.path.exists(os.path.join(platform_dir, baseline_filename)):
+ baselines.append((platform_dir, baseline_filename))
+
+ if not all_baselines and baselines:
+ return baselines
+
+ # If it wasn't found in a platform directory, return the expected
+ # result in the test directory, even if no such file actually exists.
+ platform_dir = self.layout_tests_dir()
+ if os.path.exists(os.path.join(platform_dir, baseline_filename)):
+ baselines.append((platform_dir, baseline_filename))
+
+ if baselines:
+ return baselines
+
+ return [(None, baseline_filename)]
+
+ def expected_filename(self, filename, suffix):
+ """Given a test name, returns an absolute path to its expected results.
+
+ If no expected results are found in any of the searched directories,
+ the directory in which the test itself is located will be returned.
+ The return value is in the format appropriate for the platform
+ (e.g., "\\" for path separators on windows).
+
+ Args:
+ filename: absolute filename to test file
+ suffix: file suffix of the expected results, including dot; e.g. '.txt'
+ or '.png'. This should not be None, but may be an empty string.
+ platform: the most-specific directory name to use to build the
+ search list of directories, e.g., 'chromium-win', or
+ 'chromium-mac-leopard' (we follow the WebKit format)
+
+ This routine is generic but is implemented here to live alongside
+ the other baseline and filename manipulation routines.
+ """
+ platform_dir, baseline_filename = self.expected_baselines(
+ filename, suffix)[0]
+ if platform_dir:
+ return os.path.join(platform_dir, baseline_filename)
+ return os.path.join(self.layout_tests_dir(), baseline_filename)
+
+ def filename_to_uri(self, filename):
+ """Convert a test file to a URI."""
+ LAYOUTTEST_HTTP_DIR = "http/tests/"
+ LAYOUTTEST_WEBSOCKET_DIR = "websocket/tests/"
+
+ relative_path = self.relative_test_filename(filename)
+ port = None
+ use_ssl = False
+
+ if relative_path.startswith(LAYOUTTEST_HTTP_DIR):
+ # http/tests/ run off port 8000 and ssl/ off 8443
+ relative_path = relative_path[len(LAYOUTTEST_HTTP_DIR):]
+ port = 8000
+ elif relative_path.startswith(LAYOUTTEST_WEBSOCKET_DIR):
+ # websocket/tests/ run off port 8880 and 9323
+ # Note: the root is /, not websocket/tests/
+ port = 8880
+
+ # Make http/tests/local run as local files. This is to mimic the
+ # logic in run-webkit-tests.
+ #
+ # TODO(dpranke): remove the media reference and the SSL reference?
+ if (port and not relative_path.startswith("local/") and
+ not relative_path.startswith("media/")):
+ if relative_path.startswith("ssl/"):
+ port += 443
+ protocol = "https"
+ else:
+ protocol = "http"
+ return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
+
+ if sys.platform in ('cygwin', 'win32'):
+ return "file:///" + self.get_absolute_path(filename)
+ return "file://" + self.get_absolute_path(filename)
+
+ def get_absolute_path(self, filename):
+ """Return the absolute path in unix format for the given filename.
+
+ This routine exists so that platforms that don't use unix filenames
+ can convert accordingly."""
+ return os.path.abspath(filename)
+
+ def layout_tests_dir(self):
+ """Return the absolute path to the top of the LayoutTests directory."""
+ return self.path_from_webkit_base('LayoutTests')
+
+ def maybe_make_directory(self, *path):
+ """Creates the specified directory if it doesn't already exist."""
+ try:
+ os.makedirs(os.path.join(*path))
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ def name(self):
+ """Return the name of the port (e.g., 'mac', 'chromium-win-xp').
+
+ Note that this is different from the test_platform_name(), which
+ may be different (e.g., 'win-xp' instead of 'chromium-win-xp'."""
+ return self._name
+
+ def num_cores(self):
+ """Return the number of cores/cpus available on this machine.
+
+ This routine is used to determine the default amount of parallelism
+ used by run-chromium-webkit-tests."""
+ raise NotImplementedError('Port.num_cores')
+
+ def path_from_webkit_base(self, *comps):
+ """Returns the full path to path made by joining the top of the
+ WebKit source tree and the list of path components in |*comps|."""
+ if not self._webkit_base_dir:
+ abspath = os.path.abspath(__file__)
+ self._webkit_base_dir = abspath[0:abspath.find('WebKitTools')]
+ return os.path.join(self._webkit_base_dir, *comps)
+
+ def remove_directory(self, *path):
+ """Recursively removes a directory, even if it's marked read-only.
+
+ Remove the directory located at *path, if it exists.
+
+ shutil.rmtree() doesn't work on Windows if any of the files
+ or directories are read-only, which svn repositories and
+ some .svn files are. We need to be able to force the files
+ to be writable (i.e., deletable) as we traverse the tree.
+
+ Even with all this, Windows still sometimes fails to delete a file,
+ citing a permission error (maybe something to do with antivirus
+ scans or disk indexing). The best suggestion any of the user
+ forums had was to wait a bit and try again, so we do that too.
+ It's hand-waving, but sometimes it works. :/
+ """
+ file_path = os.path.join(*path)
+ if not os.path.exists(file_path):
+ return
+
+ win32 = False
+ if sys.platform == 'win32':
+ win32 = True
+ # Some people don't have the APIs installed. In that case we'll do
+ # without.
+ try:
+ win32api = __import__('win32api')
+ win32con = __import__('win32con')
+ except ImportError:
+ win32 = False
+
+ def remove_with_retry(rmfunc, path):
+ os.chmod(path, stat.S_IWRITE)
+ if win32:
+ win32api.SetFileAttributes(path,
+ win32con.FILE_ATTRIBUTE_NORMAL)
+ try:
+ return rmfunc(path)
+ except EnvironmentError, e:
+ if e.errno != errno.EACCES:
+ raise
+ print 'Failed to delete %s: trying again' % repr(path)
+ time.sleep(0.1)
+ return rmfunc(path)
+ else:
+
+ def remove_with_retry(rmfunc, path):
+ if os.path.islink(path):
+ return os.remove(path)
+ else:
+ return rmfunc(path)
+
+ for root, dirs, files in os.walk(file_path, topdown=False):
+ # For POSIX: making the directory writable guarantees
+ # removability. Windows will ignore the non-read-only
+ # bits in the chmod value.
+ os.chmod(root, 0770)
+ for name in files:
+ remove_with_retry(os.remove, os.path.join(root, name))
+ for name in dirs:
+ remove_with_retry(os.rmdir, os.path.join(root, name))
+
+ remove_with_retry(os.rmdir, file_path)
+
+ def test_platform_name(self):
+ return self._name
+
+ def relative_test_filename(self, filename):
+ """Relative unix-style path for a filename under the LayoutTests
+ directory. Filenames outside the LayoutTests directory should raise
+ an error."""
+ return filename[len(self.layout_tests_dir()) + 1:]
+
+ def results_directory(self):
+ """Absolute path to the place to store the test results."""
+ raise NotImplemented('Port.results_directory')
+
+ def setup_test_run(self):
+ """This routine can be overridden to perform any port-specific
+ work that shouuld be done at the beginning of a test run."""
+ pass
+
+ def show_html_results_file(self, results_filename):
+ """This routine should display the HTML file pointed at by
+ results_filename in a users' browser."""
+ raise NotImplementedError('Port.show_html_results_file')
+
+ def start_driver(self, png_path, options):
+ """Starts a new test Driver and returns a handle to the object."""
+ raise NotImplementedError('Port.start_driver')
+
+ def start_helper(self):
+ """Start a layout test helper if needed on this port. The test helper
+ is used to reconfigure graphics settings and do other things that
+ may be necessary to ensure a known test configuration."""
+ raise NotImplementedError('Port.start_helper')
+
+ def start_http_server(self):
+ """Start a web server if it is available. Do nothing if
+ it isn't. This routine is allowed to (and may) fail if a server
+ is already running."""
+ if self._options.use_apache:
+ self._http_server = apache_http_server.LayoutTestApacheHttpd(self,
+ self._options.results_directory)
+ else:
+ self._http_server = http_server.Lighttpd(self,
+ self._options.results_directory)
+ self._http_server.start()
+
+ def start_websocket_server(self):
+ """Start a websocket server if it is available. Do nothing if
+ it isn't. This routine is allowed to (and may) fail if a server
+ is already running."""
+ self._websocket_server = websocket_server.PyWebSocket(self,
+ self._options.results_directory)
+ self._websocket_server.start()
+
+ def stop_helper(self):
+ """Shut down the test helper if it is running. Do nothing if
+ it isn't, or it isn't available."""
+ raise NotImplementedError('Port.stop_helper')
+
+ def stop_http_server(self):
+ """Shut down the http server if it is running. Do nothing if
+ it isn't, or it isn't available."""
+ if self._http_server:
+ self._http_server.stop()
+
+ def stop_websocket_server(self):
+ """Shut down the websocket server if it is running. Do nothing if
+ it isn't, or it isn't available."""
+ if self._websocket_server:
+ self._websocket_server.stop()
+
+ def test_expectations(self):
+ """Returns the test expectations for this port.
+
+ Basically this string should contain the equivalent of a
+ test_expectations file. See test_expectations.py for more details."""
+ raise NotImplementedError('Port.test_expectations')
+
+ def test_base_platform_names(self):
+ """Return a list of the 'base' platforms on your port. The base
+ platforms represent different architectures, operating systems,
+ or implementations (as opposed to different versions of a single
+ platform). For example, 'mac' and 'win' might be different base
+ platforms, wherease 'mac-tiger' and 'mac-leopard' might be
+ different platforms. This routine is used by the rebaselining tool
+ and the dashboards, and the strings correspond to the identifiers
+ in your test expectations (*not* necessarily the platform names
+ themselves)."""
+ raise NotImplementedError('Port.base_test_platforms')
+
+ def test_platform_name(self):
+ """Returns the string that corresponds to the given platform name
+ in the test expectations. This may be the same as name(), or it
+ may be different. For example, chromium returns 'mac' for
+ 'chromium-mac'."""
+ raise NotImplementedError('Port.test_platform_name')
+
+ def test_platforms(self):
+ """Returns the list of test platform identifiers as used in the
+ test_expectations and on dashboards, the rebaselining tool, etc.
+
+ Note that this is not necessarily the same as the list of ports,
+ which must be globally unique (e.g., both 'chromium-mac' and 'mac'
+ might return 'mac' as a test_platform name'."""
+ raise NotImplementedError('Port.platforms')
+
+ def version(self):
+ """Returns a string indicating the version of a given platform, e.g.
+ '-leopard' or '-xp'.
+
+ This is used to help identify the exact port when parsing test
+ expectations, determining search paths, and logging information."""
+ raise NotImplementedError('Port.version')
+
+ def wdiff_text(self, actual_filename, expected_filename):
+ """Returns a string of HTML indicating the word-level diff of the
+ contents of the two filenames. Returns an empty string if word-level
+ diffing isn't available."""
+ executable = self._path_to_wdiff()
+ cmd = [executable,
+ '--start-delete=##WDIFF_DEL##',
+ '--end-delete=##WDIFF_END##',
+ '--start-insert=##WDIFF_ADD##',
+ '--end-insert=##WDIFF_END##',
+ expected_filename,
+ actual_filename]
+ global _wdiff_available
+ result = ''
+ try:
+ # Python's Popen has a bug that causes any pipes opened to a
+ # process that can't be executed to be leaked. Since this
+ # code is specifically designed to tolerate exec failures
+ # to gracefully handle cases where wdiff is not installed,
+ # the bug results in a massive file descriptor leak. As a
+ # workaround, if an exec failure is ever experienced for
+ # wdiff, assume it's not available. This will leak one
+ # file descriptor but that's better than leaking each time
+ # wdiff would be run.
+ #
+ # http://mail.python.org/pipermail/python-list/
+ # 2008-August/505753.html
+ # http://bugs.python.org/issue3210
+ #
+ # It also has a threading bug, so we don't output wdiff if
+ # the Popen raises a ValueError.
+ # http://bugs.python.org/issue1236
+ if _wdiff_available:
+ try:
+ wdiff = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE).communicate()[0]
+ except ValueError, e:
+ # Working around a race in Python 2.4's implementation
+ # of Popen().
+ wdiff = ''
+ wdiff = cgi.escape(wdiff)
+ wdiff = wdiff.replace('##WDIFF_DEL##', '<span class=del>')
+ wdiff = wdiff.replace('##WDIFF_ADD##', '<span class=add>')
+ wdiff = wdiff.replace('##WDIFF_END##', '</span>')
+ result = '<head><style>.del { background: #faa; } '
+ result += '.add { background: #afa; }</style></head>'
+ result += '<pre>' + wdiff + '</pre>'
+ except OSError, e:
+ if (e.errno == errno.ENOENT or e.errno == errno.EACCES or
+ e.errno == errno.ECHILD):
+ _wdiff_available = False
+ else:
+ raise e
+ return result
+
+ #
+ # PROTECTED ROUTINES
+ #
+ # The routines below should only be called by routines in this class
+ # or any of its subclasses.
+ #
+
+ def _kill_process(self, pid):
+ """Forcefully kill a process.
+
+ This routine should not be used or needed generically, but can be
+ used in helper files like http_server.py."""
+ raise NotImplementedError('Port.kill_process')
+
+ def _path_to_apache(self):
+ """Returns the full path to the apache binary.
+
+ This is needed only by ports that use the apache_http_server module."""
+ raise NotImplementedError('Port.path_to_apache')
+
+ def _path_to_apache_config_file(self):
+ """Returns the full path to the apache binary.
+
+ This is needed only by ports that use the apache_http_server module."""
+ raise NotImplementedError('Port.path_to_apache_config_file')
+
+ def _path_to_driver(self):
+ """Returns the full path to the test driver (DumpRenderTree)."""
+ raise NotImplementedError('Port.path_to_driver')
+
+ def _path_to_helper(self):
+ """Returns the full path to the layout_test_helper binary, which
+ is used to help configure the system for the test run, or None
+ if no helper is needed.
+
+ This is likely only used by start/stop_helper()."""
+ raise NotImplementedError('Port._path_to_helper')
+
+ def _path_to_image_diff(self):
+ """Returns the full path to the image_diff binary, or None if it
+ is not available.
+
+ This is likely used only by diff_image()"""
+ raise NotImplementedError('Port.path_to_image_diff')
+
+ def _path_to_lighttpd(self):
+ """Returns the path to the LigHTTPd binary.
+
+ This is needed only by ports that use the http_server.py module."""
+ raise NotImplementedError('Port._path_to_lighttpd')
+
+ def _path_to_lighttpd_modules(self):
+ """Returns the path to the LigHTTPd modules directory.
+
+ This is needed only by ports that use the http_server.py module."""
+ raise NotImplementedError('Port._path_to_lighttpd_modules')
+
+ def _path_to_lighttpd_php(self):
+ """Returns the path to the LigHTTPd PHP executable.
+
+ This is needed only by ports that use the http_server.py module."""
+ raise NotImplementedError('Port._path_to_lighttpd_php')
+
+ def _path_to_wdiff(self):
+ """Returns the full path to the wdiff binary, or None if it is
+ not available.
+
+ This is likely used only by wdiff_text()"""
+ raise NotImplementedError('Port._path_to_wdiff')
+
+ def _shut_down_http_server(self, pid):
+ """Forcefully and synchronously kills the web server.
+
+ This routine should only be called from http_server.py or its
+ subclasses."""
+ raise NotImplementedError('Port._shut_down_http_server')
+
+ def _webkit_baseline_path(self, platform):
+ """Return the full path to the top of the baseline tree for a
+ given platform."""
+ return os.path.join(self.layout_tests_dir(), 'platform',
+ platform)
+
+
+class Driver:
+ """Abstract interface for the DumpRenderTree interface."""
+
+ def __init__(self, port, png_path, options):
+ """Initialize a Driver to subsequently run tests.
+
+ Typically this routine will spawn DumpRenderTree in a config
+ ready for subsequent input.
+
+ port - reference back to the port object.
+ png_path - an absolute path for the driver to write any image
+ data for a test (as a PNG). If no path is provided, that
+ indicates that pixel test results will not be checked.
+ options - any port-specific driver options."""
+ raise NotImplementedError('Driver.__init__')
+
+ def run_test(self, uri, timeout, checksum):
+ """Run a single test and return the results.
+
+ Note that it is okay if a test times out or crashes and leaves
+ the driver in an indeterminate state. The upper layers of the program
+ are responsible for cleaning up and ensuring things are okay.
+
+ uri - a full URI for the given test
+ timeout - number of milliseconds to wait before aborting this test.
+ checksum - if present, the expected checksum for the image for this
+ test
+
+ Returns a tuple of the following:
+ crash - a boolean indicating whether the driver crashed on the test
+ timeout - a boolean indicating whehter the test timed out
+ checksum - a string containing the checksum of the image, if
+ present
+ output - any text output
+ error - any unexpected or additional (or error) text output
+
+ Note that the image itself should be written to the path that was
+ specified in the __init__() call."""
+ raise NotImplementedError('Driver.run_test')
+
+ def poll(self):
+ """Returns None if the Driver is still running. Returns the returncode
+ if it has exited."""
+ raise NotImplementedError('Driver.poll')
+
+ def returncode(self):
+ """Returns the system-specific returncode if the Driver has stopped or
+ exited."""
+ raise NotImplementedError('Driver.returncode')
+
+ def stop(self):
+ raise NotImplementedError('Driver.stop')
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py
new file mode 100644
index 0000000..70a8dea
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+# 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.
+
+"""Chromium implementations of the Port interface."""
+
+import logging
+import os
+import shutil
+import signal
+import subprocess
+import sys
+import time
+
+import base
+import http_server
+import websocket_server
+
+
+class ChromiumPort(base.Port):
+ """Abstract base class for Chromium implementations of the Port class."""
+
+ def __init__(self, port_name=None, options=None):
+ base.Port.__init__(self, port_name, options)
+ self._chromium_base_dir = None
+
+ def baseline_path(self):
+ return self._chromium_baseline_path(self._name)
+
+ def check_sys_deps(self):
+ result = True
+ test_shell_binary_path = self._path_to_driver()
+ if os.path.exists(test_shell_binary_path):
+ proc = subprocess.Popen([test_shell_binary_path,
+ '--check-layout-test-sys-deps'])
+ if proc.wait() != 0:
+ logging.error("Aborting because system dependencies check "
+ "failed.")
+ logging.error("To override, invoke with --nocheck-sys-deps")
+ result = False
+ else:
+ logging.error('test driver is not found at %s' %
+ test_shell_binary_path)
+ result = False
+
+ image_diff_path = self._path_to_image_diff()
+ if (not os.path.exists(image_diff_path) and not
+ self._options.no_pixel_tests):
+ logging.error('image diff not found at %s' % image_diff_path)
+ logging.error("To override, invoke with --no-pixel-tests")
+ result = False
+
+ return result
+
+ def compare_text(self, actual_text, expected_text):
+ return actual_text != expected_text
+
+ def path_from_chromium_base(self, *comps):
+ """Returns the full path to path made by joining the top of the
+ Chromium source tree and the list of path components in |*comps|."""
+ if not self._chromium_base_dir:
+ abspath = os.path.abspath(__file__)
+ self._chromium_base_dir = abspath[0:abspath.find('third_party')]
+ return os.path.join(self._chromium_base_dir, *comps)
+
+ def results_directory(self):
+ return self.path_from_chromium_base('webkit', self._options.target,
+ self._options.results_directory)
+
+ def setup_test_run(self):
+ # Delete the disk cache if any to ensure a clean test run.
+ test_shell_binary_path = self._path_to_driver()
+ cachedir = os.path.split(test_shell_binary_path)[0]
+ cachedir = os.path.join(cachedir, "cache")
+ if os.path.exists(cachedir):
+ shutil.rmtree(cachedir)
+
+ def show_results_html_file(self, results_filename):
+ subprocess.Popen([self._path_to_driver(),
+ self.filename_to_uri(results_filename)])
+
+ def start_driver(self, image_path, options):
+ """Starts a new Driver and returns a handle to it."""
+ return ChromiumDriver(self, image_path, options)
+
+ def start_helper(self):
+ helper_path = self._path_to_helper()
+ if helper_path:
+ logging.debug("Starting layout helper %s" % helper_path)
+ self._helper = subprocess.Popen([helper_path],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None)
+ is_ready = self._helper.stdout.readline()
+ if not is_ready.startswith('ready'):
+ logging.error("layout_test_helper failed to be ready")
+
+ def stop_helper(self):
+ if self._helper:
+ logging.debug("Stopping layout test helper")
+ self._helper.stdin.write("x\n")
+ self._helper.stdin.close()
+ self._helper.wait()
+
+ def test_base_platform_names(self):
+ return ('linux', 'mac', 'win')
+
+ def test_expectations(self, options=None):
+ """Returns the test expectations for this port.
+
+ Basically this string should contain the equivalent of a
+ test_expectations file. See test_expectations.py for more details."""
+ expectations_file = self.path_from_chromium_base('webkit', 'tools',
+ 'layout_tests', 'test_expectations.txt')
+ return file(expectations_file, "r").read()
+
+ def test_platform_names(self):
+ return self.test_base_platform_names() + ('win-xp',
+ 'win-vista', 'win-7')
+
+ #
+ # PROTECTED METHODS
+ #
+ # These routines should only be called by other methods in this file
+ # or any subclasses.
+ #
+
+ def _chromium_baseline_path(self, platform):
+ if platform is None:
+ platform = self.name()
+ return self.path_from_chromium_base('webkit', 'data', 'layout_tests',
+ 'platform', platform, 'LayoutTests')
+
+
+class ChromiumDriver(base.Driver):
+ """Abstract interface for the DumpRenderTree interface."""
+
+ def __init__(self, port, image_path, options):
+ self._port = port
+ self._options = options
+ self._target = port._options.target
+ self._image_path = image_path
+
+ cmd = []
+ # Hook for injecting valgrind or other runtime instrumentation,
+ # used by e.g. tools/valgrind/valgrind_tests.py.
+ wrapper = os.environ.get("BROWSER_WRAPPER", None)
+ if wrapper != None:
+ cmd += [wrapper]
+ if self._port._options.wrapper:
+ # This split() isn't really what we want -- it incorrectly will
+ # split quoted strings within the wrapper argument -- but in
+ # practice it shouldn't come up and the --help output warns
+ # about it anyway.
+ cmd += self._options.wrapper.split()
+ cmd += [port._path_to_driver(), '--layout-tests']
+ if options:
+ cmd += options
+ self._proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ def poll(self):
+ return self._proc.poll()
+
+ def returncode(self):
+ return self._proc.returncode
+
+ def run_test(self, uri, timeoutms, checksum):
+ output = []
+ error = []
+ crash = False
+ timeout = False
+ actual_uri = None
+ actual_checksum = None
+
+ start_time = time.time()
+ cmd = uri
+ if timeoutms:
+ cmd += ' ' + str(timeoutms)
+ if checksum:
+ cmd += ' ' + checksum
+ cmd += "\n"
+
+ self._proc.stdin.write(cmd)
+ line = self._proc.stdout.readline()
+ while line.rstrip() != "#EOF":
+ # Make sure we haven't crashed.
+ if line == '' and self.poll() is not None:
+ # This is hex code 0xc000001d, which is used for abrupt
+ # termination. This happens if we hit ctrl+c from the prompt
+ # and we happen to be waiting on the test_shell.
+ # sdoyon: Not sure for which OS and in what circumstances the
+ # above code is valid. What works for me under Linux to detect
+ # ctrl+c is for the subprocess returncode to be negative
+ # SIGINT. And that agrees with the subprocess documentation.
+ if (-1073741510 == self._proc.returncode or
+ - signal.SIGINT == self._proc.returncode):
+ raise KeyboardInterrupt
+ crash = True
+ break
+
+ # Don't include #URL lines in our output
+ if line.startswith("#URL:"):
+ actual_uri = line.rstrip()[5:]
+ if uri != actual_uri:
+ logging.fatal("Test got out of sync:\n|%s|\n|%s|" %
+ (uri, actual_uri))
+ raise AssertionError("test out of sync")
+ elif line.startswith("#MD5:"):
+ actual_checksum = line.rstrip()[5:]
+ elif line.startswith("#TEST_TIMED_OUT"):
+ timeout = True
+ # Test timed out, but we still need to read until #EOF.
+ elif actual_uri:
+ output.append(line)
+ else:
+ error.append(line)
+
+ line = self._proc.stdout.readline()
+
+ return (crash, timeout, actual_checksum, ''.join(output),
+ ''.join(error))
+
+ def stop(self):
+ if self._proc:
+ self._proc.stdin.close()
+ self._proc.stdout.close()
+ if self._proc.stderr:
+ self._proc.stderr.close()
+ if (sys.platform not in ('win32', 'cygwin') and
+ not self._proc.poll()):
+ # Closing stdin/stdout/stderr hangs sometimes on OS X.
+ null = open(os.devnull, "w")
+ subprocess.Popen(["kill", "-9",
+ str(self._proc.pid)], stderr=null)
+ null.close()
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
index 9ffc401..8fd5343 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
@@ -27,222 +27,123 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""This is the Linux implementation of the port
- package. This file should only be imported by that package."""
+"""Chromium Mac implementation of the Port interface."""
import os
+import platform
import signal
import subprocess
-import sys
-import logging
-import chromium_win
-import path_utils
+import chromium
-
-def platform_name():
- """Returns the name of the platform we're currently running on."""
- return 'chromium-linux' + platform_version()
-
-
-def platform_version():
- """Returns the version string for the platform, e.g. '-vista' or
- '-snowleopard'. If the platform does not distinguish between
- minor versions, it returns ''."""
- return ''
-
-
-def get_num_cores():
- """Returns the number of cores on the machine. For hyperthreaded machines,
- this will be double the number of actual processors."""
- num_cores = os.sysconf("SC_NPROCESSORS_ONLN")
- if isinstance(num_cores, int) and num_cores > 0:
- return num_cores
- return 1
-
-
-def baseline_path(platform=None):
- """Returns the path relative to the top of the source tree for the
- baselines for the specified platform version. If |platform| is None,
- then the version currently in use is used."""
- if platform is None:
- platform = platform_name()
- return path_utils.path_from_base('webkit', 'data', 'layout_tests',
- 'platform', platform, 'LayoutTests')
-
-
-def baseline_search_path(platform=None):
- """Returns the list of directories to search for baselines/results, in
- order of preference. Paths are relative to the top of the source tree."""
- return [baseline_path(platform),
- chromium_win.baseline_path('chromium-win'),
- path_utils.webkit_baseline_path('win'),
- path_utils.webkit_baseline_path('mac')]
-
-
-def apache_executable_path():
- """Returns the executable path to start Apache"""
- path = os.path.join("/usr", "sbin", "apache2")
- if os.path.exists(path):
- return path
- print "Unable to fine Apache executable %s" % path
- _missing_apache()
-
-
-def apache_config_file_path():
- """Returns the path to Apache config file"""
- return path_utils.path_from_base("third_party", "WebKit", "LayoutTests",
- "http", "conf", "apache2-debian-httpd.conf")
-
-
-def lighttpd_executable_path():
- """Returns the executable path to start LigHTTPd"""
- binpath = "/usr/sbin/lighttpd"
- if os.path.exists(binpath):
- return binpath
- print "Unable to find LigHTTPd executable %s" % binpath
- _missing_lighttpd()
-
-
-def lighttpd_module_path():
- """Returns the library module path for LigHTTPd"""
- modpath = "/usr/lib/lighttpd"
- if os.path.exists(modpath):
- return modpath
- print "Unable to find LigHTTPd modules %s" % modpath
- _missing_lighttpd()
-
-
-def lighttpd_php_path():
- """Returns the PHP executable path for LigHTTPd"""
- binpath = "/usr/bin/php-cgi"
- if os.path.exists(binpath):
- return binpath
- print "Unable to find PHP CGI executable %s" % binpath
- _missing_lighttpd()
-
-
-def wdiff_path():
- """Path to the WDiff executable, which we assume is already installed and
- in the user's $PATH."""
- return 'wdiff'
-
-
-def image_diff_path(target):
- """Path to the image_diff binary.
-
- Args:
- target: Build target mode (debug or release)"""
- return _path_from_build_results(target, 'image_diff')
-
-
-def layout_test_helper_path(target):
- """Path to the layout_test helper binary, if needed, empty otherwise"""
- return ''
-
-
-def test_shell_path(target):
- """Return the platform-specific binary path for our TestShell.
-
- Args:
- target: Build target mode (debug or release) """
- if target in ('Debug', 'Release'):
- try:
- debug_path = _path_from_build_results('Debug', 'test_shell')
- release_path = _path_from_build_results('Release', 'test_shell')
-
- debug_mtime = os.stat(debug_path).st_mtime
- release_mtime = os.stat(release_path).st_mtime
-
- if debug_mtime > release_mtime and target == 'Release' or \
- release_mtime > debug_mtime and target == 'Debug':
- logging.info('\x1b[31mWarning: you are not running the most '
- 'recent test_shell binary. You need to pass '
- '--debug or not to select between Debug and '
- 'Release.\x1b[0m')
- # This will fail if we don't have both a debug and release binary.
- # That's fine because, in this case, we must already be running the
- # most up-to-date one.
- except path_utils.PathNotFound:
- pass
-
- return _path_from_build_results(target, 'test_shell')
-
-
-def fuzzy_match_path():
- """Return the path to the fuzzy matcher binary."""
- return path_utils.path_from_base('third_party', 'fuzzymatch', 'fuzzymatch')
-
-
-def shut_down_http_server(server_pid):
- """Shut down the lighttpd web server. Blocks until it's fully shut down.
-
- Args:
- server_pid: The process ID of the running server.
- """
- # server_pid is not set when "http_server.py stop" is run manually.
- if server_pid is None:
- # This isn't ideal, since it could conflict with web server processes
- # not started by http_server.py, but good enough for now.
- kill_all_process('lighttpd')
- kill_all_process('apache2')
- else:
- try:
- os.kill(server_pid, signal.SIGTERM)
- #TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
- except OSError:
- # Sometimes we get a bad PID (e.g. from a stale httpd.pid file),
- # so if kill fails on the given PID, just try to 'killall' web
- # servers.
- shut_down_http_server(None)
-
-
-def kill_process(pid):
- """Forcefully kill the process.
-
- Args:
- pid: The id of the process to be killed.
- """
- os.kill(pid, signal.SIGKILL)
-
-
-def kill_all_process(process_name):
- null = open(os.devnull)
- subprocess.call(['killall', '-TERM', '-u', os.getenv('USER'),
- process_name], stderr=null)
- null.close()
-
-
-def kill_all_test_shells():
- """Kills all instances of the test_shell binary currently running."""
- kill_all_process('test_shell')
-
-#
-# Private helper functions
-#
-
-
-def _missing_lighttpd():
- print 'Please install using: "sudo apt-get install lighttpd php5-cgi"'
- print 'For complete Linux build requirements, please see:'
- print 'http://code.google.com/p/chromium/wiki/LinuxBuildInstructions'
- sys.exit(1)
-
-
-def _missing_apache():
- print ('Please install using: "sudo apt-get install apache2 '
- 'libapache2-mod-php5"')
- print 'For complete Linux build requirements, please see:'
- print 'http://code.google.com/p/chromium/wiki/LinuxBuildInstructions'
- sys.exit(1)
-
-
-def _path_from_build_results(*pathies):
- # FIXME(dkegel): use latest or warn if more than one found?
- for dir in ["sconsbuild", "out", "xcodebuild"]:
- try:
- return path_utils.path_from_base(dir, *pathies)
- except:
- pass
- raise path_utils.PathNotFound("Unable to find %s in build tree" %
- (os.path.join(*pathies)))
+
+class ChromiumLinuxPort(chromium.ChromiumPort):
+ """Chromium Linux implementation of the Port class."""
+
+ def __init__(self, port_name=None, options=None):
+ if port_name is None:
+ port_name = 'chromium-linux'
+ chromium.ChromiumPort.__init__(self, port_name, options)
+
+ def baseline_search_path(self):
+ return [self.baseline_path(),
+ self._chromium_baseline_path('chromium-win'),
+ self._webkit_baseline_path('win'),
+ self._webkit_baseline_path('mac')]
+
+ def check_sys_deps(self):
+ # We have no platform-specific dependencies to check.
+ return True
+
+ def num_cores(self):
+ num_cores = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(num_cores, int) and num_cores > 0:
+ return num_cores
+ return 1
+
+ def test_platform_name(self):
+ # We use 'linux' instead of 'chromium-linux' in test_expectations.txt.
+ return 'linux'
+
+ def version(self):
+ # We don't have different versions on linux.
+ return ''
+
+ #
+ # PROTECTED METHODS
+ #
+
+ def _build_path(self, *comps):
+ base = self.path_from_chromium_base()
+ if os.path.exists(os.path.join(base, 'sconsbuild')):
+ return self.path_from_chromium_base('sconsbuild',
+ self._options.target, *comps)
+ else:
+ return self.path_from_chromium_base('out',
+ self._options.target, *comps)
+
+ def _kill_process(self, pid):
+ """Forcefully kill the process.
+
+ Args:
+ pid: The id of the process to be killed.
+ """
+ os.kill(pid, signal.SIGKILL)
+
+ def _kill_all_process(self, process_name):
+ null = open(os.devnull)
+ subprocess.call(['killall', '-TERM', '-u', os.getenv('USER'),
+ process_name], stderr=null)
+ null.close()
+
+ def _path_to_apache(self):
+ return '/usr/sbin/apache2'
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-debian-httpd.conf')
+
+ def _path_to_lighttpd(self):
+ return "/usr/sbin/lighttpd"
+
+ def _path_to_lighttpd_modules(self):
+ return "/usr/lib/lighttpd"
+
+ def _path_to_lighttpd_php(self):
+ return "/usr/bin/php-cgi"
+
+ def _path_to_driver(self):
+ return self._build_path('test_shell')
+
+ def _path_to_helper(self):
+ return None
+
+ def _path_to_image_diff(self):
+ return self._build_path('image_diff')
+
+ def _path_to_wdiff(self):
+ return 'wdiff'
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # TODO(mmoss) This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._kill_all_process('lighttpd')
+ self._kill_all_process('apache2')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
index d0fbc01..7e7b4ca 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
@@ -27,175 +27,136 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""This is the Mac implementation of the port interface
- package. This file should only be imported by that package."""
+"""Chromium Mac implementation of the Port interface."""
import os
import platform
import signal
import subprocess
-import path_utils
-
-
-def platform_name():
- """Returns the name of the platform we're currently running on."""
- # At the moment all chromium mac results are version-independent. At some
- # point we may need to return 'chromium-mac' + PlatformVersion()
- return 'chromium-mac'
-
-
-def platform_version():
- """Returns the version string for the platform, e.g. '-vista' or
- '-snowleopard'. If the platform does not distinguish between
- minor versions, it returns ''."""
- os_version_string = platform.mac_ver()[0] # e.g. "10.5.6"
- if not os_version_string:
- return '-leopard'
-
- release_version = int(os_version_string.split('.')[1])
-
- # we don't support 'tiger' or earlier releases
- if release_version == 5:
- return '-leopard'
- elif release_version == 6:
- return '-snowleopard'
-
- return ''
-
-
-def get_num_cores():
- """Returns the number of cores on the machine. For hyperthreaded machines,
- this will be double the number of actual processors."""
- return int(os.popen2("sysctl -n hw.ncpu")[1].read())
-
-
-def baseline_path(platform=None):
- """Returns the path relative to the top of the source tree for the
- baselines for the specified platform version. If |platform| is None,
- then the version currently in use is used."""
- if platform is None:
- platform = platform_name()
- return path_utils.path_from_base('webkit', 'data', 'layout_tests',
- 'platform', platform, 'LayoutTests')
-
-# TODO: We should add leopard and snowleopard to the list of paths to check
-# once we start running the tests from snowleopard.
-
-
-def baseline_search_path(platform=None):
- """Returns the list of directories to search for baselines/results, in
- order of preference. Paths are relative to the top of the source tree."""
- return [baseline_path(platform),
- path_utils.webkit_baseline_path('mac' + platform_version()),
- path_utils.webkit_baseline_path('mac')]
-
-
-def wdiff_path():
- """Path to the WDiff executable, which we assume is already installed and
- in the user's $PATH."""
- return 'wdiff'
-
-
-def image_diff_path(target):
- """Path to the image_diff executable
-
- Args:
- target: build type - 'Debug','Release',etc."""
- return path_utils.path_from_base('xcodebuild', target, 'image_diff')
-
-
-def layout_test_helper_path(target):
- """Path to the layout_test_helper executable, if needed, empty otherwise
-
- Args:
- target: build type - 'Debug','Release',etc."""
- return path_utils.path_from_base('xcodebuild', target,
- 'layout_test_helper')
-
-
-def test_shell_path(target):
- """Path to the test_shell executable.
-
- Args:
- target: build type - 'Debug','Release',etc."""
- # TODO(pinkerton): make |target| happy with case-sensitive file systems.
- return path_utils.path_from_base('xcodebuild', target, 'TestShell.app',
- 'Contents', 'MacOS', 'TestShell')
-
-
-def apache_executable_path():
- """Returns the executable path to start Apache"""
- return os.path.join("/usr", "sbin", "httpd")
-
-
-def apache_config_file_path():
- """Returns the path to Apache config file"""
- return path_utils.path_from_base("third_party", "WebKit", "LayoutTests",
- "http", "conf", "apache2-httpd.conf")
-
-
-def lighttpd_executable_path():
- """Returns the executable path to start LigHTTPd"""
- return path_utils.path_from_base('third_party', 'lighttpd', 'mac',
- 'bin', 'lighttpd')
-
-
-def lighttpd_module_path():
- """Returns the library module path for LigHTTPd"""
- return path_utils.path_from_base('third_party', 'lighttpd', 'mac', 'lib')
-
-
-def lighttpd_php_path():
- """Returns the PHP executable path for LigHTTPd"""
- return path_utils.path_from_base('third_party', 'lighttpd', 'mac', 'bin',
- 'php-cgi')
-
-
-def shut_down_http_server(server_pid):
- """Shut down the lighttpd web server. Blocks until it's fully shut down.
-
- Args:
- server_pid: The process ID of the running server.
- """
- # server_pid is not set when "http_server.py stop" is run manually.
- if server_pid is None:
- # TODO(mmoss) This isn't ideal, since it could conflict with lighttpd
- # processes not started by http_server.py, but good enough for now.
- kill_all_process('lighttpd')
- kill_all_process('httpd')
- else:
- try:
- os.kill(server_pid, signal.SIGTERM)
- # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
- except OSError:
- # Sometimes we get a bad PID (e.g. from a stale httpd.pid file),
- # so if kill fails on the given PID, just try to 'killall' web
- # servers.
- shut_down_http_server(None)
-
-
-def kill_process(pid):
- """Forcefully kill the process.
-
- Args:
- pid: The id of the process to be killed.
- """
- os.kill(pid, signal.SIGKILL)
-
-
-def kill_all_process(process_name):
- # On Mac OS X 10.6, killall has a new constraint: -SIGNALNAME or
- # -SIGNALNUMBER must come first. Example problem:
- # $ killall -u $USER -TERM lighttpd
- # killall: illegal option -- T
- # Use of the earlier -TERM placement is just fine on 10.5.
- null = open(os.devnull)
- subprocess.call(['killall', '-TERM', '-u', os.getenv('USER'),
- process_name], stderr=null)
- null.close()
-
-
-def kill_all_test_shells():
- """Kills all instances of the test_shell binary currently running."""
- kill_all_process('TestShell')
+import chromium
+
+
+class ChromiumMacPort(chromium.ChromiumPort):
+ """Chromium Mac implementation of the Port class."""
+
+ def __init__(self, port_name=None, options=None):
+ if port_name is None:
+ port_name = 'chromium-mac'
+ chromium.ChromiumPort.__init__(self, port_name, options)
+
+ def baseline_search_path(self):
+ return [self.baseline_path(),
+ self._webkit_baseline_path('mac' + self.version()),
+ self._webkit_baseline_path('mac')]
+
+ def check_sys_deps(self):
+ # We have no specific platform dependencies.
+ return True
+
+ def num_cores(self):
+ return int(subprocess.Popen(['sysctl','-n','hw.ncpu'],
+ stdout=subprocess.PIPE).stdout.read())
+
+ def test_platform_name(self):
+ # We use 'mac' instead of 'chromium-mac'
+ return 'mac'
+
+ def version(self):
+ os_version_string = platform.mac_ver()[0] # e.g. "10.5.6"
+ if not os_version_string:
+ return '-leopard'
+ release_version = int(os_version_string.split('.')[1])
+ # we don't support 'tiger' or earlier releases
+ if release_version == 5:
+ return '-leopard'
+ elif release_version == 6:
+ return '-snowleopard'
+ return ''
+
+ #
+ # PROTECTED METHODS
+ #
+
+ def _build_path(self, *comps):
+ return self.path_from_chromium_base('xcodebuild', self._options.target,
+ *comps)
+
+ def _lighttpd_path(self, *comps):
+ return self.path_from_chromium_base('third_party', 'lighttpd',
+ 'mac', *comps)
+
+ def _kill_process(self, pid):
+ """Forcefully kill the process.
+
+ Args:
+ pid: The id of the process to be killed.
+ """
+ os.kill(pid, signal.SIGKILL)
+
+ def _kill_all_process(self, process_name):
+ """Kill any processes running under this name."""
+ # On Mac OS X 10.6, killall has a new constraint: -SIGNALNAME or
+ # -SIGNALNUMBER must come first. Example problem:
+ # $ killall -u $USER -TERM lighttpd
+ # killall: illegal option -- T
+ # Use of the earlier -TERM placement is just fine on 10.5.
+ null = open(os.devnull)
+ subprocess.call(['killall', '-TERM', '-u', os.getenv('USER'),
+ process_name], stderr=null)
+ null.close()
+
+ def _path_to_apache(self):
+ return '/usr/sbin/httpd'
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-httpd.conf')
+
+ def _path_to_lighttpd(self):
+ return self._lighttp_path('bin', 'lighttp')
+
+ def _path_to_lighttpd_modules(self):
+ return self._lighttp_path('lib')
+
+ def _path_to_lighttpd_php(self):
+ return self._lighttpd_path('bin', 'php-cgi')
+
+ def _path_to_driver(self):
+ # TODO(pinkerton): make |target| happy with case-sensitive file
+ # systems.
+ return self._build_path('TestShell.app', 'Contents', 'MacOS',
+ 'TestShell')
+
+ def _path_to_helper(self):
+ return self._build_path('layout_test_helper')
+
+ def _path_to_image_diff(self):
+ return self._build_path('image_diff')
+
+ def _path_to_wdiff(self):
+ return 'wdiff'
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # TODO(mmoss) This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._kill_all_process('lighttpd')
+ self._kill_all_process('httpd')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py
index 1e0b212..352916c 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py
@@ -27,184 +27,129 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""This is the Linux implementation of the port
- package. This file should only be imported by that package."""
+"""Chromium Win implementation of the Port interface."""
import os
+import platform
+import signal
import subprocess
import sys
-import path_utils
+import chromium
-def platform_name():
- """Returns the name of the platform we're currently running on."""
- # We're not ready for version-specific results yet. When we uncomment
- # this, we also need to add it to the BaselineSearchPath()
- return 'chromium-win' + platform_version()
-
-def platform_version():
- """Returns the version string for the platform, e.g. '-vista' or
- '-snowleopard'. If the platform does not distinguish between
- minor versions, it returns ''."""
- winver = sys.getwindowsversion()
- if winver[0] == 6 and (winver[1] == 1):
- return '-7'
- if winver[0] == 6 and (winver[1] == 0):
- return '-vista'
- if winver[0] == 5 and (winver[1] == 1 or winver[1] == 2):
- return '-xp'
- return ''
-
-
-def get_num_cores():
- """Returns the number of cores on the machine. For hyperthreaded machines,
- this will be double the number of actual processors."""
- return int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
-
-
-def baseline_path(platform=None):
- """Returns the path relative to the top of the source tree for the
- baselines for the specified platform version. If |platform| is None,
- then the version currently in use is used."""
- if platform is None:
- platform = platform_name()
- return path_utils.path_from_base('webkit', 'data', 'layout_tests',
- 'platform', platform, 'LayoutTests')
-
-
-def baseline_search_path(platform=None):
- """Returns the list of directories to search for baselines/results, in
- order of preference. Paths are relative to the top of the source tree."""
- dirs = []
- if platform is None:
- platform = platform_name()
-
- if platform == 'chromium-win-xp':
- dirs.append(baseline_path(platform))
- if platform in ('chromium-win-xp', 'chromium-win-vista'):
- dirs.append(baseline_path('chromium-win-vista'))
- dirs.append(baseline_path('chromium-win'))
- dirs.append(path_utils.webkit_baseline_path('win'))
- dirs.append(path_utils.webkit_baseline_path('mac'))
- return dirs
-
-
-def wdiff_path():
- """Path to the WDiff executable, whose binary is checked in on Win"""
- return path_utils.path_from_base('third_party', 'cygwin', 'bin',
- 'wdiff.exe')
-
-
-def image_diff_path(target):
- """Return the platform-specific binary path for the image compare util.
- We use this if we can't find the binary in the default location
- in path_utils.
-
- Args:
- target: Build target mode (debug or release)
- """
- return _find_binary(target, 'image_diff.exe')
-
-
-def layout_test_helper_path(target):
- """Return the platform-specific binary path for the layout test helper.
- We use this if we can't find the binary in the default location
- in path_utils.
-
- Args:
- target: Build target mode (debug or release)
- """
- return _find_binary(target, 'layout_test_helper.exe')
-
-
-def test_shell_path(target):
- """Return the platform-specific binary path for our TestShell.
- We use this if we can't find the binary in the default location
- in path_utils.
-
- Args:
- target: Build target mode (debug or release)
- """
- return _find_binary(target, 'test_shell.exe')
-
-
-def apache_executable_path():
- """Returns the executable path to start Apache"""
- path = path_utils.path_from_base('third_party', 'cygwin', "usr", "sbin")
- # Don't return httpd.exe since we want to use this from cygwin.
- return os.path.join(path, "httpd")
-
-
-def apache_config_file_path():
- """Returns the path to Apache config file"""
- return path_utils.path_from_base("third_party", "WebKit", "LayoutTests",
- "http", "conf", "cygwin-httpd.conf")
-
-
-def lighttpd_executable_path():
- """Returns the executable path to start LigHTTPd"""
- return path_utils.path_from_base('third_party', 'lighttpd', 'win',
- 'LightTPD.exe')
-
-
-def lighttpd_module_path():
- """Returns the library module path for LigHTTPd"""
- return path_utils.path_from_base('third_party', 'lighttpd', 'win', 'lib')
-
-
-def lighttpd_php_path():
- """Returns the PHP executable path for LigHTTPd"""
- return path_utils.path_from_base('third_party', 'lighttpd', 'win', 'php5',
- 'php-cgi.exe')
-
-
-def shut_down_http_server(server_pid):
- """Shut down the lighttpd web server. Blocks until it's fully shut down.
-
- Args:
- server_pid: The process ID of the running server.
- Unused in this implementation of the method.
- """
- subprocess.Popen(('taskkill.exe', '/f', '/im', 'LightTPD.exe'),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).wait()
- subprocess.Popen(('taskkill.exe', '/f', '/im', 'httpd.exe'),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).wait()
-
-
-def kill_process(pid):
- """Forcefully kill the process.
-
- Args:
- pid: The id of the process to be killed.
- """
- subprocess.call(('taskkill.exe', '/f', '/pid', str(pid)),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
-
-
-def kill_all_test_shells(self):
- """Kills all instances of the test_shell binary currently running."""
- subprocess.Popen(('taskkill.exe', '/f', '/im', 'test_shell.exe'),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).wait()
-
-#
-# Private helper functions.
-#
-
-
-def _find_binary(target, binary):
- """On Windows, we look for binaries that we compile in potentially
- two places: src/webkit/$target (preferably, which we get if we
- built using webkit_glue.gyp), or src/chrome/$target (if compiled some
- other way)."""
- try:
- return path_utils.path_from_base('webkit', target, binary)
- except path_utils.PathNotFound:
- try:
- return path_utils.path_from_base('chrome', target, binary)
- except path_utils.PathNotFound:
- return path_utils.path_from_base('build', target, binary)
+class ChromiumWinPort(chromium.ChromiumPort):
+ """Chromium Win implementation of the Port class."""
+
+ def __init__(self, port_name=None, options=None):
+ if port_name is None:
+ port_name = 'chromium-win' + self.version()
+ chromium.ChromiumPort.__init__(self, port_name, options)
+
+ def baseline_search_path(self):
+ dirs = []
+ if self._name == 'chromium-win-xp':
+ dirs.append(self._chromium_baseline_path(self._name))
+ if self._name in ('chromium-win-xp', 'chromium-win-vista'):
+ dirs.append(self._chromium_baseline_path('chromium-win-vista'))
+ dirs.append(self._chromium_baseline_path('chromium-win'))
+ dirs.append(self._webkit_baseline_path('win'))
+ dirs.append(self._webkit_baseline_path('mac'))
+ return dirs
+
+ def check_sys_deps(self):
+ # TODO(dpranke): implement this
+ return True
+
+ def get_absolute_path(self, filename):
+ """Return the absolute path in unix format for the given filename."""
+ abspath = os.path.abspath(filename)
+ return abspath.replace('\\', '/')
+
+ def num_cores(self):
+ return int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
+
+ def relative_test_filename(self, filename):
+ path = filename[len(self.layout_tests_dir()) + 1:]
+ return path.replace('\\', '/')
+
+ def test_platform_name(self):
+ # We return 'win-xp', not 'chromium-win-xp' here, for convenience.
+ return 'win' + self.version()
+
+ def version(self):
+ winver = sys.getwindowsversion()
+ if winver[0] == 6 and (winver[1] == 1):
+ return '-7'
+ if winver[0] == 6 and (winver[1] == 0):
+ return '-vista'
+ if winver[0] == 5 and (winver[1] == 1 or winver[1] == 2):
+ return '-xp'
+ return ''
+
+ #
+ # PROTECTED ROUTINES
+ #
+
+ def _build_path(self, *comps):
+ # FIXME(dpranke): allow for builds under 'chrome' as well.
+ return self.path_from_chromium_base('webkit', self._options.target,
+ *comps)
+
+ def _lighttpd_path(self, *comps):
+ return self.path_from_chromium_base('third_party', 'lighttpd', 'win',
+ *comps)
+
+ def _kill_process(self, pid):
+ """Forcefully kill the process.
+
+ Args:
+ pid: The id of the process to be killed.
+ """
+ subprocess.call(('taskkill.exe', '/f', '/pid', str(pid)),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ def _path_to_apache(self):
+ return self.path_from_chromium_base('third_party', 'cygwin', 'usr',
+ 'sbin', 'httpd')
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'cygwin-httpd.conf')
+
+ def _path_to_lighttpd(self):
+ return self._lighttpd_path('LightTPD.exe')
+
+ def _path_to_lighttpd_modules(self):
+ return self._lighttpd_path('lib')
+
+ def _path_to_lighttpd_php(self):
+ return self._lighttpd_path('php5', 'php-cgi.exe')
+
+ def _path_to_driver(self):
+ return self._build_path('test_shell.exe')
+
+ def _path_to_helper(self):
+ return self._build_path('layout_test_helper.exe')
+
+ def _path_to_image_diff(self):
+ return self._build_path('image_diff.exe')
+
+ def _path_to_wdiff(self):
+ return self.path_from_chromium_base('third_party', 'cygwin', 'bin',
+ 'wdiff.exe')
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ subprocess.Popen(('taskkill.exe', '/f', '/im', 'LightTPD.exe'),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).wait()
+ subprocess.Popen(('taskkill.exe', '/f', '/im', 'httpd.exe'),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).wait()
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server.py
index 99e2ea1..0315704 100755
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server.py
@@ -41,52 +41,21 @@ import time
import urllib
import http_server_base
-import path_utils
-class HttpdNotStarted(Exception): pass
-def remove_log_files(folder, starts_with):
- files = os.listdir(folder)
- for file in files:
- if file.startswith(starts_with):
- full_path = os.path.join(folder, file)
- os.remove(full_path)
+class HttpdNotStarted(Exception):
+ pass
class Lighttpd(http_server_base.HttpServerBase):
- # Webkit tests
- try:
- _webkit_tests = path_utils.path_from_base('third_party', 'WebKit',
- 'LayoutTests', 'http',
- 'tests')
- _js_test_resource = path_utils.path_from_base('third_party', 'WebKit',
- 'LayoutTests', 'fast',
- 'js', 'resources')
- except path_utils.PathNotFound:
- _webkit_tests = None
- _js_test_resource = None
-
- # Path where we can access all of the tests
- _all_tests = path_utils.path_from_base('webkit', 'data', 'layout_tests')
- # Self generated certificate for SSL server (for client cert get
- # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt)
- _pem_file = path_utils.path_from_base(
- os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem')
- # One mapping where we can get to everything
- VIRTUALCONFIG = [{'port': 8081, 'docroot': _all_tests}]
-
- if _webkit_tests:
- VIRTUALCONFIG.extend(
- # Three mappings (one with SSL enabled) for LayoutTests http tests
- [{'port': 8000, 'docroot': _webkit_tests},
- {'port': 8080, 'docroot': _webkit_tests},
- {'port': 8443, 'docroot': _webkit_tests, 'sslcert': _pem_file}])
-
- def __init__(self, output_dir, background=False, port=None,
+
+ def __init__(self, port_obj, output_dir, background=False, port=None,
root=None, register_cygwin=None, run_background=None):
"""Args:
output_dir: the absolute path to the layout test result directory
"""
+ # Webkit tests
+ http_server_base.HttpServerBase.__init__(self, port_obj)
self._output_dir = output_dir
self._process = None
self._port = port
@@ -96,6 +65,31 @@ class Lighttpd(http_server_base.HttpServerBase):
if self._port:
self._port = int(self._port)
+ try:
+ self._webkit_tests = os.path.join(
+ self._port_obj.layout_tests_dir(), 'http', 'tests')
+ self._js_test_resource = os.path.join(
+ self._port_obj.layout_tests_dir(), 'fast', 'js', 'resources')
+ except:
+ self._webkit_tests = None
+ self._js_test_resource = None
+
+ # Self generated certificate for SSL server (for client cert get
+ # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt)
+ self._pem_file = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem')
+
+ # One mapping where we can get to everything
+ self.VIRTUALCONFIG = []
+
+ if self._webkit_tests:
+ self.VIRTUALCONFIG.extend(
+ # Three mappings (one with SSL) for LayoutTests http tests
+ [{'port': 8000, 'docroot': self._webkit_tests},
+ {'port': 8080, 'docroot': self._webkit_tests},
+ {'port': 8443, 'docroot': self._webkit_tests,
+ 'sslcert': self._pem_file}])
+
def is_running(self):
return self._process != None
@@ -103,9 +97,8 @@ class Lighttpd(http_server_base.HttpServerBase):
if self.is_running():
raise 'Lighttpd already running'
- base_conf_file = path_utils.path_from_base('third_party',
- 'WebKitTools', 'Scripts', 'webkitpy', 'layout_tests',
- 'layout_package', 'lighttpd.conf')
+ base_conf_file = self._port_obj.path_from_webkit_base('WebKitTools',
+ 'Scripts', 'webkitpy', 'layout_tests', 'port', 'lighttpd.conf')
out_conf_file = os.path.join(self._output_dir, 'lighttpd.conf')
time_str = time.strftime("%d%b%Y-%H%M%S")
access_file_name = "access.log-" + time_str + ".txt"
@@ -114,8 +107,8 @@ class Lighttpd(http_server_base.HttpServerBase):
error_log = os.path.join(self._output_dir, log_file_name)
# Remove old log files. We only need to keep the last ones.
- remove_log_files(self._output_dir, "access.log-")
- remove_log_files(self._output_dir, "error.log-")
+ self.remove_log_files(self._output_dir, "access.log-")
+ self.remove_log_files(self._output_dir, "error.log-")
# Write out the config
f = file(base_conf_file, 'rb')
@@ -132,7 +125,7 @@ class Lighttpd(http_server_base.HttpServerBase):
' ".pl" => "/usr/bin/env",\n'
' ".asis" => "/bin/cat",\n'
' ".php" => "%s" )\n\n') %
- path_utils.lighttpd_php_path())
+ self._port_obj._path_to_lighttpd_php())
# Setup log files
f.write(('server.errorlog = "%s"\n'
@@ -161,7 +154,7 @@ class Lighttpd(http_server_base.HttpServerBase):
mappings = [{'port': 8000, 'docroot': self._root},
{'port': 8080, 'docroot': self._root},
{'port': 8443, 'docroot': self._root,
- 'sslcert': Lighttpd._pem_file}]
+ 'sslcert': self._pem_file}]
else:
mappings = self.VIRTUALCONFIG
for mapping in mappings:
@@ -176,12 +169,11 @@ class Lighttpd(http_server_base.HttpServerBase):
'}\n\n') % (mapping['port'], mapping['docroot']))
f.close()
- executable = path_utils.lighttpd_executable_path()
- module_path = path_utils.lighttpd_module_path()
+ executable = self._port_obj._path_to_lighttpd()
+ module_path = self._port_obj._path_to_lighttpd_modules()
start_cmd = [executable,
# Newly written config file
- '-f', path_utils.path_from_base(self._output_dir,
- 'lighttpd.conf'),
+ '-f', os.path.join(self._output_dir, 'lighttpd.conf'),
# Where it can find its module dynamic libraries
'-m', module_path]
@@ -203,12 +195,13 @@ class Lighttpd(http_server_base.HttpServerBase):
env = os.environ
if sys.platform in ('cygwin', 'win32'):
env['PATH'] = '%s;%s' % (
- path_utils.path_from_base('third_party', 'cygwin', 'bin'),
+ self._port_obj.path_from_chromium_base('third_party',
+ 'cygwin', 'bin'),
env['PATH'])
if sys.platform == 'win32' and self._register_cygwin:
- setup_mount = path_utils.path_from_base('third_party', 'cygwin',
- 'setup_mount.bat')
+ setup_mount = port.path_from_chromium_base('third_party',
+ 'cygwin', 'setup_mount.bat')
subprocess.Popen(setup_mount).wait()
logging.debug('Starting http server')
@@ -235,7 +228,7 @@ class Lighttpd(http_server_base.HttpServerBase):
httpd_pid = None
if self._process:
httpd_pid = self._process.pid
- path_utils.shut_down_http_server(httpd_pid)
+ self._port_obj._shut_down_http_server(httpd_pid)
if self._process:
self._process.wait()
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server_base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server_base.py
index 026e070..e82943e 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server_base.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_server_base.py
@@ -30,12 +30,16 @@
"""Base class with common routines between the Apache and Lighttpd servers."""
import logging
+import os
import time
import urllib
class HttpServerBase(object):
+ def __init__(self, port_obj):
+ self._port_obj = port_obj
+
def wait_for_action(self, action):
"""Repeat the action for 20 seconds or until it succeeds. Returns
whether it succeeded."""
@@ -65,3 +69,10 @@ class HttpServerBase(object):
return False
return True
+
+ def remove_log_files(self, folder, starts_with):
+ files = os.listdir(folder)
+ for file in files:
+ if file.startswith(starts_with):
+ full_path = os.path.join(folder, file)
+ os.remove(full_path)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py
new file mode 100644
index 0000000..4b73cec
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py
@@ -0,0 +1,439 @@
+#!/usr/bin/env python
+# 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 Google name 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.
+
+"""WebKit Mac implementation of the Port interface."""
+
+import fcntl
+import logging
+import os
+import pdb
+import platform
+import select
+import signal
+import subprocess
+import sys
+import time
+import webbrowser
+
+import base
+
+import webkitpy
+from webkitpy import executive
+
+class MacPort(base.Port):
+ """WebKit Mac implementation of the Port class."""
+
+ def __init__(self, port_name=None, options=None):
+ if port_name is None:
+ port_name = 'mac' + self.version()
+ base.Port.__init__(self, port_name, options)
+ self._cached_build_root = None
+
+ def baseline_search_path(self):
+ dirs = []
+ if self._name == 'mac-tiger':
+ dirs.append(self._webkit_baseline_path(self._name))
+ if self._name in ('mac-tiger', 'mac-leopard'):
+ dirs.append(self._webkit_baseline_path('mac-leopard'))
+ if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'):
+ dirs.append(self._webkit_baseline_path('mac-snowleopard'))
+ dirs.append(self._webkit_baseline_path('mac'))
+ return dirs
+
+ def check_sys_deps(self):
+ # FIXME: This should run build-dumprendertree.
+ # This should also validate that all of the tool paths are valid.
+ return True
+
+ def num_cores(self):
+ return int(os.popen2("sysctl -n hw.ncpu")[1].read())
+
+ def results_directory(self):
+ return ('/tmp/run-chromium-webkit-tests-' +
+ self._options.results_directory)
+
+ def setup_test_run(self):
+ # This port doesn't require any specific configuration.
+ pass
+
+ def show_results_html_file(self, results_filename):
+ uri = self.filename_to_uri(results_filename)
+ webbrowser.open(uri, new=1)
+
+ def start_driver(self, image_path, options):
+ """Starts a new Driver and returns a handle to it."""
+ return MacDriver(self, image_path, options)
+
+ def start_helper(self):
+ # This port doesn't use a helper process.
+ pass
+
+ def stop_helper(self):
+ # This port doesn't use a helper process.
+ pass
+
+ def test_base_platform_names(self):
+ # At the moment we don't use test platform names, but we have
+ # to return something.
+ return ('mac',)
+
+ def test_expectations(self):
+ #
+ # The WebKit mac port uses 'Skipped' files at the moment. Each
+ # file contains a list of files or directories to be skipped during
+ # the test run. The total list of tests to skipped is given by the
+ # contents of the generic Skipped file found in platform/X plus
+ # a version-specific file found in platform/X-version. Duplicate
+ # entries are allowed. This routine reads those files and turns
+ # contents into the format expected by test_expectations.
+ expectations = []
+ skipped_files = []
+ if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'):
+ skipped_files.append(os.path.join(
+ self._webkit_baseline_path(self._name), 'Skipped'))
+ skipped_files.append(os.path.join(self._webkit_baseline_path('mac'),
+ 'Skipped'))
+ for filename in skipped_files:
+ if os.path.exists(filename):
+ f = file(filename)
+ for l in f.readlines():
+ l = l.strip()
+ if not l.startswith('#') and len(l):
+ l = 'BUG_SKIPPED SKIP : ' + l + ' = FAIL'
+ if l not in expectations:
+ expectations.append(l)
+ f.close()
+
+ # TODO - figure out how to check for these dynamically
+ expectations.append('BUG_SKIPPED SKIP : fast/wcss = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : fast/xhtmlmp = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : http/tests/wml = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : mathml = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : platform/chromium = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : platform/gtk = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : platform/qt = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : platform/win = FAIL')
+ expectations.append('BUG_SKIPPED SKIP : wml = FAIL')
+
+ # TODO - figure out how to handle webarchive tests
+ expectations.append('BUG_SKIPPED SKIP : webarchive = PASS')
+ expectations.append('BUG_SKIPPED SKIP : svg/webarchive = PASS')
+ expectations.append('BUG_SKIPPED SKIP : http/tests/webarchive = PASS')
+ expectations.append('BUG_SKIPPED SKIP : svg/custom/'
+ 'image-with-prefix-in-webarchive.svg = PASS')
+
+ expectations_str = '\n'.join(expectations)
+ return expectations_str
+
+ def test_platform_name(self):
+ # At the moment we don't use test platform names, but we have
+ # to return something.
+ return 'mac'
+
+ def test_platform_names(self):
+ # At the moment we don't use test platform names, but we have
+ # to return something.
+ return ('mac',)
+
+ def version(self):
+ os_version_string = platform.mac_ver()[0] # e.g. "10.5.6"
+ if not os_version_string:
+ return '-leopard'
+ release_version = int(os_version_string.split('.')[1])
+ if release_version == 4:
+ return '-tiger'
+ elif release_version == 5:
+ return '-leopard'
+ elif release_version == 6:
+ return '-snowleopard'
+ return ''
+
+ #
+ # PROTECTED METHODS
+ #
+
+ def _build_path(self, *comps):
+ if not self._cached_build_root:
+ self._cached_build_root = executive.run_command(["webkit-build-directory", "--base"]).rstrip()
+ return os.path.join(self._cached_build_root, self._options.target, *comps)
+
+ def _kill_process(self, pid):
+ """Forcefully kill the process.
+
+ Args:
+ pid: The id of the process to be killed.
+ """
+ os.kill(pid, signal.SIGKILL)
+
+ def _kill_all_process(self, process_name):
+ # On Mac OS X 10.6, killall has a new constraint: -SIGNALNAME or
+ # -SIGNALNUMBER must come first. Example problem:
+ # $ killall -u $USER -TERM lighttpd
+ # killall: illegal option -- T
+ # Use of the earlier -TERM placement is just fine on 10.5.
+ null = open(os.devnull)
+ subprocess.call(['killall', '-TERM', '-u', os.getenv('USER'),
+ process_name], stderr=null)
+ null.close()
+
+ def _path_to_apache(self):
+ return '/usr/sbin/httpd'
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-httpd.conf')
+
+ def _path_to_driver(self):
+ return self._build_path('DumpRenderTree')
+
+ def _path_to_helper(self):
+ return None
+
+ def _path_to_image_diff(self):
+ return self._build_path('image_diff') # FIXME: This is wrong and should be "ImageDiff", but having the correct path causes other parts of the script to hang.
+
+ def _path_to_wdiff(self):
+ return 'wdiff' # FIXME: This does not exist on a default Mac OS X Leopard install.
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # TODO(mmoss) This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._kill_all_process('httpd')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
+
+
+class MacDriver(base.Driver):
+ """implementation of the DumpRenderTree interface."""
+
+ def __init__(self, port, image_path, driver_options):
+ self._port = port
+ self._driver_options = driver_options
+ self._target = port._options.target
+ self._image_path = image_path
+ self._stdout_fd = None
+ self._cmd = None
+ self._env = None
+ self._proc = None
+ self._read_buffer = ''
+
+ cmd = []
+ # Hook for injecting valgrind or other runtime instrumentation,
+ # used by e.g. tools/valgrind/valgrind_tests.py.
+ wrapper = os.environ.get("BROWSER_WRAPPER", None)
+ if wrapper != None:
+ cmd += [wrapper]
+ if self._port._options.wrapper:
+ # This split() isn't really what we want -- it incorrectly will
+ # split quoted strings within the wrapper argument -- but in
+ # practice it shouldn't come up and the --help output warns
+ # about it anyway.
+ cmd += self._options.wrapper.split()
+ # FIXME: Using arch here masks any possible file-not-found errors from a non-existant driver executable.
+ cmd += ['arch', '-i386', port._path_to_driver(), '-']
+
+ # FIXME: This is a hack around our lack of ImageDiff support for now.
+ if not self._port._options.no_pixel_tests:
+ logging.warn("This port does not yet support pixel tests.")
+ self._port._options.no_pixel_tests = True
+ #cmd.append('--pixel-tests')
+
+ #if driver_options:
+ # cmd += driver_options
+ env = os.environ
+ env['DYLD_FRAMEWORK_PATH'] = self._port._build_path()
+ self._cmd = cmd
+ self._env = env
+ self.restart()
+
+ def poll(self):
+ return self._proc.poll()
+
+ def restart(self):
+ self.stop()
+ self._proc = subprocess.Popen(self._cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=self._env)
+
+ def returncode(self):
+ return self._proc.returncode
+
+ def run_test(self, uri, timeoutms, image_hash):
+ output = []
+ error = []
+ image = ''
+ crash = False
+ timeout = False
+ actual_uri = None
+ actual_image_hash = None
+
+ if uri.startswith("file:///"):
+ cmd = uri[7:]
+ else:
+ cmd = uri
+
+ if image_hash:
+ cmd += "'" + image_hash
+ cmd += "\n"
+
+ self._proc.stdin.write(cmd)
+ self._stdout_fd = self._proc.stdout.fileno()
+ fl = fcntl.fcntl(self._stdout_fd, fcntl.F_GETFL)
+ fcntl.fcntl(self._stdout_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
+ stop_time = time.time() + (int(timeoutms) / 1000.0)
+ resp = ''
+ (timeout, line) = self._read_line(timeout, stop_time)
+ resp += line
+ have_seen_content_type = False
+ while not timeout and line.rstrip() != "#EOF":
+ # Make sure we haven't crashed.
+ if line == '' and self.poll() is not None:
+ # This is hex code 0xc000001d, which is used for abrupt
+ # termination. This happens if we hit ctrl+c from the prompt
+ # and we happen to be waiting on the test_shell.
+ # sdoyon: Not sure for which OS and in what circumstances the
+ # above code is valid. What works for me under Linux to detect
+ # ctrl+c is for the subprocess returncode to be negative
+ # SIGINT. And that agrees with the subprocess documentation.
+ if (-1073741510 == self.returncode() or
+ - signal.SIGINT == self.returncode()):
+ raise KeyboardInterrupt
+ crash = True
+ break
+
+ elif (line.startswith('Content-Type:') and not
+ have_seen_content_type):
+ have_seen_content_type = True
+ pass
+ else:
+ output.append(line)
+
+ (timeout, line) = self._read_line(timeout, stop_time)
+ resp += line
+
+ # Now read a second block of text for the optional image data
+ image_length = 0
+ (timeout, line) = self._read_line(timeout, stop_time)
+ resp += line
+ HASH_HEADER = 'ActualHash: '
+ LENGTH_HEADER = 'Content-Length: '
+ while not timeout and not crash and line.rstrip() != "#EOF":
+ if line == '' and self.poll() is not None:
+ if (-1073741510 == self.returncode() or
+ - signal.SIGINT == self.returncode()):
+ raise KeyboardInterrupt
+ crash = True
+ break
+ elif line.startswith(HASH_HEADER):
+ actual_image_hash = line[len(HASH_HEADER):].strip()
+ elif line.startswith('Content-Type:'):
+ pass
+ elif line.startswith(LENGTH_HEADER):
+ image_length = int(line[len(LENGTH_HEADER):])
+ elif image_length:
+ image += line
+
+ (timeout, line) = self._read_line(timeout, stop_time, image_length)
+ resp += line
+
+ if timeout:
+ self.restart()
+
+ if self._image_path and len(self._image_path):
+ image_file = file(self._image_path, "wb")
+ image_file.write(image)
+ image_file.close()
+
+ return (crash, timeout, actual_image_hash,
+ ''.join(output), ''.join(error))
+ pass
+
+ def stop(self):
+ if self._proc:
+ self._proc.stdin.close()
+ self._proc.stdout.close()
+ if self._proc.stderr:
+ self._proc.stderr.close()
+ if (sys.platform not in ('win32', 'cygwin') and
+ not self._proc.poll()):
+ # Closing stdin/stdout/stderr hangs sometimes on OS X.
+ null = open(os.devnull, "w")
+ subprocess.Popen(["kill", "-9",
+ str(self._proc.pid)], stderr=null)
+ null.close()
+
+ def _read_line(self, timeout, stop_time, image_length=0):
+ now = time.time()
+ read_fds = []
+
+ # first check to see if we have a line already read or if we've
+ # read the entire image
+ if image_length and len(self._read_buffer) >= image_length:
+ out = self._read_buffer[0:image_length]
+ self._read_buffer = self._read_buffer[image_length:]
+ return (timeout, out)
+
+ idx = self._read_buffer.find('\n')
+ if not image_length and idx != -1:
+ out = self._read_buffer[0:idx + 1]
+ self._read_buffer = self._read_buffer[idx + 1:]
+ return (timeout, out)
+
+ # If we've timed out, return just what we have, if anything
+ if timeout or now >= stop_time:
+ out = self._read_buffer
+ self._read_buffer = ''
+ return (True, out)
+
+ (read_fds, write_fds, err_fds) = select.select(
+ [self._stdout_fd], [], [], stop_time - now)
+ try:
+ if timeout or len(read_fds) == 1:
+ self._read_buffer += self._proc.stdout.read()
+ except IOError, e:
+ read = []
+ return self._read_line(timeout, stop_time)
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/path_utils.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/path_utils.py
deleted file mode 100644
index 70b8c03..0000000
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/path_utils.py
+++ /dev/null
@@ -1,395 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""This package contains utility methods for manipulating paths and
-filenames for test results and baselines. It also contains wrappers
-of a few routines in port/ so that the port package can
-be considered a 'protected' package - i.e., this file should be
-the only file that ever includes port. This leads to
-us including a few things that don't really have anything to do
- with paths, unfortunately."""
-
-import errno
-import os
-import stat
-import sys
-
-import port
-import chromium_win
-import chromium_mac
-import chromium_linux
-
-# Cache some values so we don't have to recalculate them. _basedir is
-# used by PathFromBase() and caches the full (native) path to the top
-# of the source tree (/src). _baseline_search_path is used by
-# ExpectedBaselines() and caches the list of native paths to search
-# for baseline results.
-_basedir = None
-_baseline_search_path = None
-
-
-class PathNotFound(Exception):
- pass
-
-
-def layout_tests_dir():
- """Returns the fully-qualified path to the directory containing the input
- data for the specified layout test."""
- return path_from_base('third_party', 'WebKit', 'LayoutTests')
-
-
-def chromium_baseline_path(platform=None):
- """Returns the full path to the directory containing expected
- baseline results from chromium ports. If |platform| is None, the
- currently executing platform is used.
-
- Note: although directly referencing individual port/* files is
- usually discouraged, we allow it here so that the rebaselining tool can
- pull baselines for platforms other than the host platform."""
-
- # Normalize the platform string.
- platform = platform_name(platform)
- if platform.startswith('chromium-mac'):
- return chromium_mac.baseline_path(platform)
- elif platform.startswith('chromium-win'):
- return chromium_win.baseline_path(platform)
- elif platform.startswith('chromium-linux'):
- return chromium_linux.baseline_path(platform)
-
- return port.baseline_path()
-
-
-def webkit_baseline_path(platform):
- """Returns the full path to the directory containing expected
- baseline results from WebKit ports."""
- return path_from_base('third_party', 'WebKit', 'LayoutTests',
- 'platform', platform)
-
-
-def baseline_search_path(platform=None):
- """Returns the list of directories to search for baselines/results for a
- given platform, in order of preference. Paths are relative to the top of
- the source tree. If parameter platform is None, returns the list for the
- current platform that the script is running on.
-
- Note: although directly referencing individual port/* files is
- usually discouraged, we allow it here so that the rebaselining tool can
- pull baselines for platforms other than the host platform."""
-
- # Normalize the platform name.
- platform = platform_name(platform)
- if platform.startswith('chromium-mac'):
- return chromium_mac.baseline_search_path(platform)
- elif platform.startswith('chromium-win'):
- return chromium_win.baseline_search_path(platform)
- elif platform.startswith('chromium-linux'):
- return chromium_linux.baseline_search_path(platform)
- return port.baseline_search_path()
-
-
-def expected_baselines(filename, suffix, platform=None, all_baselines=False):
- """Given a test name, finds where the baseline results are located.
-
- Args:
- filename: absolute filename to test file
- suffix: file suffix of the expected results, including dot; e.g. '.txt'
- or '.png'. This should not be None, but may be an empty string.
- platform: layout test platform: 'win', 'linux' or 'mac'. Defaults to
- the current platform.
- all_baselines: If True, return an ordered list of all baseline paths
- for the given platform. If False, return only the first
- one.
- Returns
- a list of ( platform_dir, results_filename ), where
- platform_dir - abs path to the top of the results tree (or test tree)
- results_filename - relative path from top of tree to the results file
- (os.path.join of the two gives you the full path to the file,
- unless None was returned.)
- Return values will be in the format appropriate for the current platform
- (e.g., "\\" for path separators on Windows). If the results file is not
- found, then None will be returned for the directory, but the expected
- relative pathname will still be returned.
- """
- global _baseline_search_path
- global _search_path_platform
- testname = os.path.splitext(relative_test_filename(filename))[0]
-
- baseline_filename = testname + '-expected' + suffix
-
- if (_baseline_search_path is None) or (_search_path_platform != platform):
- _baseline_search_path = baseline_search_path(platform)
- _search_path_platform = platform
-
- baselines = []
- for platform_dir in _baseline_search_path:
- if os.path.exists(os.path.join(platform_dir, baseline_filename)):
- baselines.append((platform_dir, baseline_filename))
-
- if not all_baselines and baselines:
- return baselines
-
- # If it wasn't found in a platform directory, return the expected result
- # in the test directory, even if no such file actually exists.
- platform_dir = layout_tests_dir()
- if os.path.exists(os.path.join(platform_dir, baseline_filename)):
- baselines.append((platform_dir, baseline_filename))
-
- if baselines:
- return baselines
-
- return [(None, baseline_filename)]
-
-
-def expected_filename(filename, suffix):
- """Given a test name, returns an absolute path to its expected results.
-
- If no expected results are found in any of the searched directories, the
- directory in which the test itself is located will be returned. The return
- value is in the format appropriate for the platform (e.g., "\\" for
- path separators on windows).
-
- Args:
- filename: absolute filename to test file
- suffix: file suffix of the expected results, including dot; e.g. '.txt'
- or '.png'. This should not be None, but may be an empty string.
- platform: the most-specific directory name to use to build the
- search list of directories, e.g., 'chromium-win', or
- 'chromium-mac-leopard' (we follow the WebKit format)
- """
- platform_dir, baseline_filename = expected_baselines(filename, suffix)[0]
- if platform_dir:
- return os.path.join(platform_dir, baseline_filename)
- return os.path.join(layout_tests_dir(), baseline_filename)
-
-
-def relative_test_filename(filename):
- """Provide the filename of the test relative to the layout tests
- directory as a unix style path (a/b/c)."""
- return _win_path_to_unix(filename[len(layout_tests_dir()) + 1:])
-
-
-def _win_path_to_unix(path):
- """Convert a windows path to use unix-style path separators (a/b/c)."""
- return path.replace('\\', '/')
-
-#
-# Routines that are arguably platform-specific but have been made
-# generic for now
-#
-
-
-def filename_to_uri(full_path):
- """Convert a test file to a URI."""
- LAYOUTTEST_HTTP_DIR = "http/tests/"
- LAYOUTTEST_WEBSOCKET_DIR = "websocket/tests/"
-
- relative_path = _win_path_to_unix(relative_test_filename(full_path))
- port = None
- use_ssl = False
-
- if relative_path.startswith(LAYOUTTEST_HTTP_DIR):
- # http/tests/ run off port 8000 and ssl/ off 8443
- relative_path = relative_path[len(LAYOUTTEST_HTTP_DIR):]
- port = 8000
- elif relative_path.startswith(LAYOUTTEST_WEBSOCKET_DIR):
- # websocket/tests/ run off port 8880 and 9323
- # Note: the root is /, not websocket/tests/
- port = 8880
-
- # Make http/tests/local run as local files. This is to mimic the
- # logic in run-webkit-tests.
- # TODO(jianli): Consider extending this to "media/".
- if port and not relative_path.startswith("local/"):
- if relative_path.startswith("ssl/"):
- port += 443
- protocol = "https"
- else:
- protocol = "http"
- return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
-
- if sys.platform in ('cygwin', 'win32'):
- return "file:///" + get_absolute_path(full_path)
- return "file://" + get_absolute_path(full_path)
-
-
-def get_absolute_path(path):
- """Returns an absolute UNIX path."""
- return _win_path_to_unix(os.path.abspath(path))
-
-
-def maybe_make_directory(*path):
- """Creates the specified directory if it doesn't already exist."""
- try:
- os.makedirs(os.path.join(*path))
- except OSError, e:
- if e.errno != errno.EEXIST:
- raise
-
-
-def path_from_base(*comps):
- """Returns an absolute filename from a set of components specified
- relative to the top of the source tree. If the path does not exist,
- the exception PathNotFound is raised."""
- global _basedir
- if _basedir == None:
- # We compute the top of the source tree by finding the absolute
- # path of this source file, and then climbing up three directories
- # as given in subpath. If we move this file, subpath needs to be
- # updated.
- path = os.path.abspath(__file__)
- subpath = os.path.join('third_party', 'WebKit')
- _basedir = path[:path.index(subpath)]
- path = os.path.join(_basedir, *comps)
- if not os.path.exists(path):
- raise PathNotFound('could not find %s' % (path))
- return path
-
-
-def remove_directory(*path):
- """Recursively removes a directory, even if it's marked read-only.
-
- Remove the directory located at *path, if it exists.
-
- shutil.rmtree() doesn't work on Windows if any of the files or directories
- are read-only, which svn repositories and some .svn files are. We need to
- be able to force the files to be writable (i.e., deletable) as we traverse
- the tree.
-
- Even with all this, Windows still sometimes fails to delete a file, citing
- a permission error (maybe something to do with antivirus scans or disk
- indexing). The best suggestion any of the user forums had was to wait a
- bit and try again, so we do that too. It's hand-waving, but sometimes it
- works. :/
- """
- file_path = os.path.join(*path)
- if not os.path.exists(file_path):
- return
-
- win32 = False
- if sys.platform == 'win32':
- win32 = True
- # Some people don't have the APIs installed. In that case we'll do
- # without.
- try:
- win32api = __import__('win32api')
- win32con = __import__('win32con')
- except ImportError:
- win32 = False
-
- def remove_with_retry(rmfunc, path):
- os.chmod(path, stat.S_IWRITE)
- if win32:
- win32api.SetFileAttributes(path,
- win32con.FILE_ATTRIBUTE_NORMAL)
- try:
- return rmfunc(path)
- except EnvironmentError, e:
- if e.errno != errno.EACCES:
- raise
- print 'Failed to delete %s: trying again' % repr(path)
- time.sleep(0.1)
- return rmfunc(path)
- else:
-
- def remove_with_retry(rmfunc, path):
- if os.path.islink(path):
- return os.remove(path)
- else:
- return rmfunc(path)
-
- for root, dirs, files in os.walk(file_path, topdown=False):
- # For POSIX: making the directory writable guarantees removability.
- # Windows will ignore the non-read-only bits in the chmod value.
- os.chmod(root, 0770)
- for name in files:
- remove_with_retry(os.remove, os.path.join(root, name))
- for name in dirs:
- remove_with_retry(os.rmdir, os.path.join(root, name))
-
- remove_with_retry(os.rmdir, file_path)
-
-#
-# Wrappers around port/
-#
-
-
-def platform_name(platform=None):
- """Returns the appropriate chromium platform name for |platform|. If
- |platform| is None, returns the name of the chromium platform on the
- currently running system. If |platform| is of the form 'chromium-*',
- it is returned unchanged, otherwise 'chromium-' is prepended."""
- if platform == None:
- return port.platform_name()
- if not platform.startswith('chromium-'):
- platform = "chromium-" + platform
- return platform
-
-
-def platform_version():
- return port.platform_version()
-
-
-def lighttpd_executable_path():
- return port.lighttpd_executable_path()
-
-
-def lighttpd_module_path():
- return port.lighttpd_module_path()
-
-
-def lighttpd_php_path():
- return port.lighttpd_php_path()
-
-
-def wdiff_path():
- return port.wdiff_path()
-
-
-def test_shell_path(target):
- return port.test_shell_path(target)
-
-
-def image_diff_path(target):
- return port.image_diff_path(target)
-
-
-def layout_test_helper_path(target):
- return port.layout_test_helper_path(target)
-
-
-def fuzzy_match_path():
- return port.fuzzy_match_path()
-
-
-def shut_down_http_server(server_pid):
- return port.shut_down_http_server(server_pid)
-
-
-def kill_all_test_shells():
- port.kill_all_test_shells()
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py
new file mode 100644
index 0000000..0bc6e7c
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+# 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 Google name 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.
+
+"""Dummy Port implementation used for testing."""
+
+import os
+import time
+
+import base
+
+
+class TestPort(base.Port):
+ """Test implementation of the Port interface."""
+
+ def __init__(self, port_name=None, options=None):
+ base.Port.__init__(self, port_name, options)
+
+ def base_platforms(self):
+ return ('test',)
+
+ def baseline_path(self):
+ curdir = os.path.abspath(__file__)
+ self.topdir = curdir[0:curdir.index("WebKitTools")]
+ return os.path.join(self.topdir, 'LayoutTests', 'platform', 'test')
+
+ def baseline_search_path(self):
+ return [self.baseline_path()]
+
+ def check_sys_deps(self):
+ return True
+
+ def diff_image(self, actual_filename, expected_filename, diff_filename):
+ return False
+
+ def compare_text(self, actual_text, expected_text):
+ return False
+
+ def diff_text(self, actual_text, expected_text,
+ actual_filename, expected_filename):
+ return ''
+
+ def name(self):
+ return self._name
+
+ def num_cores(self):
+ return int(os.popen2("sysctl -n hw.ncpu")[1].read())
+
+ def options(self):
+ return self._options
+
+ def results_directory(self):
+ return '/tmp' + self._options.results_directory
+
+ def setup_test_run(self):
+ pass
+
+ def show_results_html_file(self, filename):
+ pass
+
+ def start_driver(self, image_path, options):
+ return TestDriver(image_path, options, self)
+
+ def start_http_server(self):
+ pass
+
+ def start_websocket_server(self):
+ pass
+
+ def start_helper(self):
+ pass
+
+ def stop_http_server(self):
+ pass
+
+ def stop_websocket_server(self):
+ pass
+
+ def stop_helper(self):
+ pass
+
+ def test_expectations(self):
+ return ''
+
+ def test_base_platform_names(self):
+ return ('test',)
+
+ def test_platform_name(self):
+ return 'test'
+
+ def test_platform_names(self):
+ return self.test_base_platform_names()
+
+ def version():
+ return ''
+
+ def wdiff_text(self, actual_filename, expected_filename):
+ return ''
+
+
+class TestDriver(base.Driver):
+ """Test/Dummy implementation of the DumpRenderTree interface."""
+
+ def __init__(self, image_path, test_driver_options, port):
+ self._driver_options = test_driver_options
+ self._image_path = image_path
+ self._port = port
+
+ def poll(self):
+ return True
+
+ def returncode(self):
+ return 0
+
+ def run_test(self, uri, timeoutms, image_hash):
+ return (False, False, image_hash, '', None)
+
+ def stop(self):
+ pass
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py
index c6c7527..ba8a5e9 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py
@@ -39,8 +39,6 @@ import tempfile
import time
import urllib
-import path_utils
-import port
import http_server
_WS_LOG_PREFIX = 'pywebsocket.ws.log-'
@@ -51,37 +49,29 @@ _DEFAULT_WSS_PORT = 9323
def url_is_alive(url):
- """Checks to see if we get an http response from |url|.
- We poll the url 5 times with a 1 second delay. If we don't
- get a reply in that time, we give up and assume the httpd
- didn't start properly.
-
- Args:
- url: The URL to check.
- Return:
- True if the url is alive.
- """
- wait_time = 5
- while wait_time > 0:
- try:
- response = urllib.urlopen(url)
- # Server is up and responding.
- return True
- except IOError:
- pass
- wait_time -= 1
- # Wait a second and try again.
- time.sleep(1)
-
- return False
-
-
-def remove_log_files(folder, starts_with):
- files = os.listdir(folder)
- for file in files:
- if file.startswith(starts_with):
- full_path = os.path.join(folder, file)
- os.remove(full_path)
+ """Checks to see if we get an http response from |url|.
+ We poll the url 5 times with a 1 second delay. If we don't
+ get a reply in that time, we give up and assume the httpd
+ didn't start properly.
+
+ Args:
+ url: The URL to check.
+ Return:
+ True if the url is alive.
+ """
+ wait_time = 5
+ while wait_time > 0:
+ try:
+ response = urllib.urlopen(url)
+ # Server is up and responding.
+ return True
+ except IOError:
+ pass
+ wait_time -= 1
+ # Wait a second and try again.
+ time.sleep(1)
+
+ return False
class PyWebSocketNotStarted(Exception):
@@ -94,18 +84,15 @@ class PyWebSocketNotFound(Exception):
class PyWebSocket(http_server.Lighttpd):
- def __init__(self, output_dir, port=_DEFAULT_WS_PORT,
- root=None,
- use_tls=False,
- private_key=http_server.Lighttpd._pem_file,
- certificate=http_server.Lighttpd._pem_file,
+ def __init__(self, port_obj, output_dir, port=_DEFAULT_WS_PORT,
+ root=None, use_tls=False,
register_cygwin=None,
pidfile=None):
"""Args:
output_dir: the absolute path to the layout test result directory
"""
- http_server.Lighttpd.__init__(self, output_dir,
- port=port,
+ http_server.Lighttpd.__init__(self, port_obj, output_dir,
+ port=_DEFAULT_WS_PORT,
root=root,
register_cygwin=register_cygwin)
self._output_dir = output_dir
@@ -113,8 +100,8 @@ class PyWebSocket(http_server.Lighttpd):
self._port = port
self._root = root
self._use_tls = use_tls
- self._private_key = private_key
- self._certificate = certificate
+ self._private_key = self._pem_file
+ self._certificate = self._pem_file
if self._port:
self._port = int(self._port)
if self._use_tls:
@@ -131,12 +118,10 @@ class PyWebSocket(http_server.Lighttpd):
os.path.join(self._root, 'websocket', 'tests'))
else:
try:
- self._web_socket_tests = path_utils.path_from_base(
- 'third_party', 'WebKit', 'LayoutTests', 'websocket',
- 'tests')
- self._layout_tests = path_utils.path_from_base(
- 'third_party', 'WebKit', 'LayoutTests')
- except path_utils.PathNotFound:
+ self._layout_tests = self._port_obj.layout_tests_dir()
+ self._web_socket_tests = os.path.join(self._layout_tests,
+ 'websocket', 'tests')
+ except:
self._web_socket_tests = None
def start(self):
@@ -155,7 +140,7 @@ class PyWebSocket(http_server.Lighttpd):
log_file_name = log_prefix + time_str
# Remove old log files. We only need to keep the last ones.
- remove_log_files(self._output_dir, log_prefix)
+ self.remove_log_files(self._output_dir, log_prefix)
error_log = os.path.join(self._output_dir, log_file_name + "-err.txt")
@@ -163,11 +148,12 @@ class PyWebSocket(http_server.Lighttpd):
self._wsout = open(output_log, "w")
python_interp = sys.executable
- pywebsocket_base = path_utils.path_from_base(
- 'third_party', 'WebKit', 'WebKitTools', 'pywebsocket')
- pywebsocket_script = path_utils.path_from_base(
- 'third_party', 'WebKit', 'WebKitTools', 'pywebsocket',
- 'mod_pywebsocket', 'standalone.py')
+ pywebsocket_base = os.path.join(
+ os.path.dirname(os.path.dirname(os.path.dirname(
+ os.path.dirname(os.path.dirname(
+ os.path.abspath(__file__)))))), 'pywebsocket')
+ pywebsocket_script = os.path.join(pywebsocket_base, 'mod_pywebsocket',
+ 'standalone.py')
start_cmd = [
python_interp, pywebsocket_script,
'-p', str(self._port),
@@ -193,12 +179,13 @@ class PyWebSocket(http_server.Lighttpd):
env = os.environ
if sys.platform in ('cygwin', 'win32'):
env['PATH'] = '%s;%s' % (
- path_utils.path_from_base('third_party', 'cygwin', 'bin'),
+ self._port_obj.path_from_chromium_base('third_party',
+ 'cygwin', 'bin'),
env['PATH'])
if sys.platform == 'win32' and self._register_cygwin:
- setup_mount = path_utils.path_from_base('third_party', 'cygwin',
- 'setup_mount.bat')
+ setup_mount = self._port_obj.path_from_chromium_base(
+ 'third_party', 'cygwin', 'setup_mount.bat')
subprocess.Popen(setup_mount).wait()
env['PYTHONPATH'] = (pywebsocket_base + os.path.pathsep +
@@ -255,7 +242,7 @@ class PyWebSocket(http_server.Lighttpd):
'Failed to find %s server pid.' % self._server_name)
logging.debug('Shutting down %s server %d.' % (self._server_name, pid))
- port.kill_process(pid)
+ self._port_obj._kill_process(pid)
if self._process:
self._process.wait()