diff options
Diffstat (limited to 'chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers')
15 files changed, 435 insertions, 711 deletions
diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http_server.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py index e00a9a0cb44..b83cd379baa 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http_server.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py @@ -26,62 +26,67 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""A class to start/stop the apache http server used by layout tests.""" - +"""Start and stop the Apache HTTP server as it is used by the layout tests.""" import logging import os -import re import socket -import sys -from webkitpy.layout_tests.servers import http_server_base +from webkitpy.layout_tests.servers import server_base _log = logging.getLogger(__name__) -class LayoutTestApacheHttpd(http_server_base.HttpServerBase): - def __init__(self, port_obj, output_dir, additional_dirs=None, number_of_servers=None): - """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, number_of_servers) +class ApacheHTTP(server_base.ServerBase): + def __init__(self, port_obj, output_dir, additional_dirs, number_of_servers): + super(ApacheHTTP, self).__init__(port_obj, output_dir) # We use the name "httpd" instead of "apache" to make our paths (e.g. the pid file: /tmp/WebKit/httpd.pid) # match old-run-webkit-tests: https://bugs.webkit.org/show_bug.cgi?id=63956 self._name = 'httpd' self._mappings = [{'port': 8000}, {'port': 8080}, {'port': 8443, 'sslcert': True}] - self._output_dir = output_dir - self._filesystem.maybe_make_directory(output_dir) + self._number_of_servers = number_of_servers self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name) + executable = self._port_obj.path_to_apache() + server_root = self._filesystem.dirname(self._filesystem.dirname(executable)) + test_dir = self._port_obj.layout_tests_dir() + document_root = self._filesystem.join(test_dir, "http", "tests") js_test_resources_dir = self._filesystem.join(test_dir, "resources") media_resources_dir = self._filesystem.join(test_dir, "media") mime_types_path = self._filesystem.join(test_dir, "http", "conf", "mime.types") cert_file = self._filesystem.join(test_dir, "http", "conf", "webkit-httpd.pem") + access_log = self._filesystem.join(output_dir, "access_log.txt") error_log = self._filesystem.join(output_dir, "error_log.txt") - document_root = self._filesystem.join(test_dir, "http", "tests") - # FIXME: We shouldn't be calling a protected method of _port_obj! - executable = self._port_obj._path_to_apache() + self._is_win = self._port_obj.host.platform.is_win() start_cmd = [executable, - '-f', "\"%s\"" % self._get_apache_config_file_path(test_dir, output_dir), - '-C', "\'DocumentRoot \"%s\"\'" % document_root, - '-c', "\'Alias /js-test-resources \"%s\"'" % js_test_resources_dir, - '-c', "\'Alias /media-resources \"%s\"'" % media_resources_dir, - '-c', "\'TypesConfig \"%s\"\'" % mime_types_path, - '-c', "\'CustomLog \"%s\" common\'" % access_log, - '-c', "\'ErrorLog \"%s\"\'" % error_log, - '-C', "\'User \"%s\"\'" % os.environ.get("USERNAME", os.environ.get("USER", "")), - '-c', "\'PidFile %s'" % self._pid_file, - '-k', "start"] + '-f', '%s' % self._port_obj.path_to_apache_config_file(), + '-C', 'ServerRoot "%s"' % server_root, + '-C', 'DocumentRoot "%s"' % document_root, + '-c', 'Alias /js-test-resources "%s"' % js_test_resources_dir, + '-c', 'Alias /media-resources "%s"' % media_resources_dir, + '-c', 'TypesConfig "%s"' % mime_types_path, + '-c', 'CustomLog "%s" common' % access_log, + '-c', 'ErrorLog "%s"' % error_log, + '-c', 'PidFile %s' % self._pid_file, + '-c', 'SSLCertificateFile "%s"' % cert_file, + ] + + if self._is_win: + start_cmd += ['-c', "ThreadsPerChild %d" % (self._number_of_servers * 2)] + else: + start_cmd += ['-c', "StartServers %d" % self._number_of_servers, + '-c', "MinSpareServers %d" % self._number_of_servers, + '-c', "MaxSpareServers %d" % self._number_of_servers, + '-C', 'User "%s"' % os.environ.get('USERNAME', os.environ.get('USER', '')), + '-k', 'start'] enable_ipv6 = self._port_obj.http_server_supports_ipv6() # Perform part of the checks Apache's APR does when trying to listen to @@ -99,68 +104,44 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase): for mapping in self._mappings: port = mapping['port'] - start_cmd += ['-C', "\'Listen 127.0.0.1:%d\'" % port] + start_cmd += ['-C', "Listen 127.0.0.1:%d" % port] # We listen to both IPv4 and IPv6 loop-back addresses, but ignore # requests to 8000 from random users on network. # See https://bugs.webkit.org/show_bug.cgi?id=37104 if enable_ipv6: - start_cmd += ['-C', "\'Listen [::1]:%d\'" % port] + start_cmd += ['-C', "Listen [::1]:%d" % port] if additional_dirs: + self._start_cmd = start_cmd for alias, path in additional_dirs.iteritems(): - start_cmd += ['-c', "\'Alias %s \"%s\"\'" % (alias, path), + start_cmd += ['-c', 'Alias %s "%s"' % (alias, path), # Disable CGI handler for additional dirs. - '-c', "\'<Location %s>\'" % alias, - '-c', "\'RemoveHandler .cgi .pl\'", - '-c', "\'</Location>\'"] - - if self._number_of_servers: - start_cmd += ['-c', "\'StartServers %d\'" % self._number_of_servers, - '-c', "\'MinSpareServers %d\'" % self._number_of_servers, - '-c', "\'MaxSpareServers %d\'" % self._number_of_servers] - - stop_cmd = [executable, - '-f', "\"%s\"" % self._get_apache_config_file_path(test_dir, output_dir), - '-c', "\'PidFile %s'" % self._pid_file, - '-k', "stop"] - - start_cmd.extend(['-c', "\'SSLCertificateFile %s\'" % cert_file]) - # Join the string here so that Cygwin/Windows and Mac/Linux - # can use the same code. Otherwise, we could remove the single - # quotes above and keep cmd as a sequence. - # FIXME: It's unclear if this is still needed. - self._start_cmd = " ".join(start_cmd) - self._stop_cmd = " ".join(stop_cmd) - - def _get_apache_config_file_path(self, test_dir, output_dir): - """Returns the path to the apache config file to use. - Args: - test_dir: absolute path to the LayoutTests directory. - output_dir: absolute path to the layout test results directory. - """ - httpd_config = self._port_obj._path_to_apache_config_file() - httpd_config_copy = os.path.join(output_dir, "httpd.conf") - httpd_conf = self._filesystem.read_text_file(httpd_config) - - # FIXME: Why do we need to copy the config file since we're not modifying it? - self._filesystem.write_text_file(httpd_config_copy, httpd_conf) - - return httpd_config_copy + '-c', '<Location %s>' % alias, + '-c', 'RemoveHandler .cgi .pl', + '-c', '</Location>'] + + self._start_cmd = start_cmd def _spawn_process(self): _log.debug('Starting %s server, cmd="%s"' % (self._name, str(self._start_cmd))) - retval, err = self._run(self._start_cmd) - if retval or len(err): - raise http_server_base.ServerError('Failed to start %s: %s' % (self._name, err)) + self._process = self._executive.popen(self._start_cmd) + if self._process.returncode is not None: + retval = self._process.returncode + err = self._process.stderr.read() + if retval or len(err): + raise server_base.ServerError('Failed to start %s: %s' % (self._name, err)) # For some reason apache isn't guaranteed to have created the pid file before # the process exits, so we wait a little while longer. if not self._wait_for_action(lambda: self._filesystem.exists(self._pid_file)): - raise http_server_base.ServerError('Failed to start %s: no pid file found' % self._name) + raise server_base.ServerError('Failed to start %s: no pid file found' % self._name) return int(self._filesystem.read_text_file(self._pid_file)) + def stop(self): + self._stop_running_server() + def _stop_running_server(self): # If apache was forcefully killed, the pid file will not have been deleted, so check # that the process specified by the pid_file no longer exists before deleting the file. @@ -168,25 +149,22 @@ class LayoutTestApacheHttpd(http_server_base.HttpServerBase): self._filesystem.remove(self._pid_file) return - retval, err = self._run(self._stop_cmd) + if self._is_win: + self._executive.kill_process(self._pid) + return + + proc = self._executive.popen([self._port_obj.path_to_apache(), + '-f', self._port_obj.path_to_apache_config_file(), + '-c', 'PidFile "%s"' % self._pid_file, + '-k', 'stop'], stderr=self._executive.PIPE) + proc.wait() + retval = proc.returncode + err = proc.stderr.read() if retval or len(err): - raise http_server_base.ServerError('Failed to stop %s: %s' % (self._name, err)) + raise server_base.ServerError('Failed to stop %s: %s' % (self._name, err)) # For some reason apache isn't guaranteed to have actually stopped after # the stop command returns, so we wait a little while longer for the # pid file to be removed. if not self._wait_for_action(lambda: not self._filesystem.exists(self._pid_file)): - raise http_server_base.ServerError('Failed to stop %s: pid file still exists' % self._name) - - def _run(self, cmd): - # Use shell=True because we join the arguments into a string for - # the sake of Window/Cygwin and it needs quoting that breaks - # shell=False. - # FIXME: We should not need to be joining shell arguments into strings. - # shell=True is a trail of tears. - # Note: Not thread safe: http://bugs.python.org/issue2320 - process = self._executive.popen(cmd, shell=True, stderr=self._executive.PIPE) - process.wait() - retval = process.returncode - err = process.stderr.read() - return (retval, err) + raise server_base.ServerError('Failed to stop %s: pid file still exists' % self._name) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http_server_unittest.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http_unittest.py index e68c5e39aa6..6f9fb688bb8 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http_server_unittest.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http_unittest.py @@ -34,11 +34,11 @@ from webkitpy.common.system.executive_mock import MockExecutive from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.common.host_mock import MockHost from webkitpy.layout_tests.port import test -from webkitpy.layout_tests.servers.apache_http_server import LayoutTestApacheHttpd -from webkitpy.layout_tests.servers.http_server_base import ServerError +from webkitpy.layout_tests.servers.apache_http import ApacheHTTP +from webkitpy.layout_tests.servers.server_base import ServerError -class TestLayoutTestApacheHttpd(unittest.TestCase): +class TestApacheHTTP(unittest.TestCase): def test_start_cmd(self): # Fails on win - see https://bugs.webkit.org/show_bug.cgi?id=84726 if sys.platform in ('cygwin', 'win32'): @@ -51,9 +51,9 @@ class TestLayoutTestApacheHttpd(unittest.TestCase): host = MockHost() host.executive = MockExecutive(should_log=True) test_port = test.TestPort(host) - host.filesystem.write_text_file(test_port._path_to_apache_config_file(), '') + host.filesystem.write_text_file(test_port.path_to_apache_config_file(), '') - server = LayoutTestApacheHttpd(test_port, "/mock/output_dir", number_of_servers=4) + server = ApacheHTTP(test_port, "/mock/output_dir", additional_dirs=[], number_of_servers=4) server._check_that_all_ports_are_available = lambda: True server._is_server_running_on_all_ports = lambda: True server._wait_for_action = fake_pid @@ -67,4 +67,3 @@ class TestLayoutTestApacheHttpd(unittest.TestCase): self.assertIn("StartServers 4", logs) self.assertIn("MinSpareServers 4", logs) self.assertIn("MaxSpareServers 4", logs) - self.assertTrue(host.filesystem.exists("/mock/output_dir/httpd.conf")) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/cli_wrapper.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/cli_wrapper.py new file mode 100644 index 00000000000..49b98008b26 --- /dev/null +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/cli_wrapper.py @@ -0,0 +1,67 @@ +# 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. + +"""A utility script for starting and stopping servers as they are used in the layout tests.""" + +import logging +import optparse + +from webkitpy.common.host import Host + +_log = logging.getLogger(__name__) + + +def main(server_constructor, input_fn=None, argv=None, **kwargs): + input_fn = input_fn or raw_input + + option_parser = optparse.OptionParser() + option_parser.add_option('--output-dir', dest='output_dir', + default=None, help='output directory.') + option_parser.add_option('-v', '--verbose', action='store_true') + options, args = option_parser.parse_args(argv) + + logging.basicConfig() + logger = logging.getLogger() + logger.setLevel(logging.DEBUG if options.verbose else logging.INFO) + + host = Host() + port_obj = host.port_factory.get() + if not options.output_dir: + options.output_dir = port_obj.default_results_directory() + + # Create the output directory if it doesn't already exist. + port_obj.host.filesystem.maybe_make_directory(options.output_dir) + + server = server_constructor(port_obj, options.output_dir, **kwargs) + server.start() + try: + _ = input_fn('Hit any key to stop the server and exit.') + except (KeyboardInterrupt, EOFError) as e: + pass + + server.stop() diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/cli_wrapper_unittest.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/cli_wrapper_unittest.py new file mode 100644 index 00000000000..54647394d6b --- /dev/null +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/cli_wrapper_unittest.py @@ -0,0 +1,34 @@ +# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +from webkitpy.layout_tests.servers import server_base +from webkitpy.layout_tests.servers import cli_wrapper + + +class MockServer(object): + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + self.start_called = False + self.stop_called = False + + def start(self): + self.start_called = True + + def stop(self): + self.stop_called = True + + +class TestCliWrapper(unittest.TestCase): + + def test_main(self): + def mock_server_constructor(*args, **kwargs): + self.server = MockServer(args, kwargs) + return self.server + + cli_wrapper.main(mock_server_constructor, input_fn=lambda msg: True, argv=[]) + self.assertTrue(self.server.start_called) + self.assertTrue(self.server.stop_called) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service.py index 08ead87d1c2..c193d0b34b2 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service.py @@ -26,62 +26,24 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""A class to help start/stop the crash service used by layout tests.""" +"""Start and stop the crash service as it is used by the layout tests.""" -import logging -import os -import time +from webkitpy.layout_tests.servers import server_base -from webkitpy.layout_tests.servers import http_server_base - -_log = logging.getLogger(__name__) - - -class CrashService(http_server_base.HttpServerBase): +class CrashService(server_base.ServerBase): def __init__(self, port_obj, crash_dumps_dir): """Args: crash_dumps_dir: the absolute path to the directory where to store crash dumps """ # Webkit tests - http_server_base.HttpServerBase.__init__(self, port_obj) + super(CrashService, self).__init__(port_obj, port_obj.default_results_directory()) self._name = 'CrashService' self._crash_dumps_dir = crash_dumps_dir + self._env = None self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name) - - def _spawn_process(self): - start_cmd = [self._port_obj._path_to_crash_service(), - '--dumps-dir=%s' % self._crash_dumps_dir, - '--no-window'] - _log.debug('Starting crash service, cmd = "%s"' % " ".join(start_cmd)) - process = self._executive.popen(start_cmd, shell=False, stderr=self._executive.PIPE) - pid = process.pid - self._filesystem.write_text_file(self._pid_file, str(pid)) - return pid - - def _stop_running_server(self): - # FIXME: It would be nice if we had a cleaner way of killing this process. - # Currently we throw away the process object created in _spawn_process, - # since there doesn't appear to be any way to kill the server any more - # cleanly using it than just killing the pid, and we need to support - # killing a pid directly anyway for run-webkit-httpd and run-webkit-websocketserver. - self._wait_for_action(self._check_and_kill) - if self._filesystem.exists(self._pid_file): - self._filesystem.remove(self._pid_file) - - def _check_and_kill(self): - if self._executive.check_running_pid(self._pid): - host = self._port_obj.host - if host.platform.is_win() and not host.platform.is_cygwin(): - # FIXME: https://bugs.webkit.org/show_bug.cgi?id=106838 - # We need to kill all of the child processes as well as the - # parent, so we can't use executive.kill_process(). - # - # If this is actually working, we should figure out a clean API. - self._executive.run_command(["taskkill.exe", "/f", "/t", "/pid", self._pid], error_handler=self._executive.ignore_error) - else: - self._executive.kill_process(self._pid) - return False - return True + self._start_cmd = [self._port_obj._path_to_crash_service(), + '--dumps-dir=%s' % self._crash_dumps_dir, + '--no-window'] diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service_unittest.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service_unittest.py index 4204cb46967..37b9a03db48 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service_unittest.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/crash_service_unittest.py @@ -33,7 +33,7 @@ import webkitpy.thirdparty.unittest2 as unittest from webkitpy.common.host_mock import MockHost from webkitpy.layout_tests.port import test from webkitpy.layout_tests.servers.crash_service import CrashService -from webkitpy.layout_tests.servers.http_server_base import ServerError +from webkitpy.layout_tests.servers.server_base import ServerError class TestCrashService(unittest.TestCase): @@ -78,4 +78,3 @@ class TestCrashService(unittest.TestCase): server._wait_for_action = wait_for_action server.stop() - self.assertEqual(['taskkill.exe', '/f', '/t', '/pid', 42], host.executive.calls[1]) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py deleted file mode 100644 index 1fbf1321231..00000000000 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (C) 2011 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. - -"""A class to help start/stop the lighttpd server used by layout tests.""" - -import logging -import os -import time - -from webkitpy.layout_tests.servers import http_server_base - - -_log = logging.getLogger(__name__) - - -class Lighttpd(http_server_base.HttpServerBase): - - def __init__(self, port_obj, output_dir, background=False, port=None, - root=None, run_background=None, additional_dirs=None, - layout_tests_dir=None, number_of_servers=None): - """Args: - output_dir: the absolute path to the layout test result directory - """ - # Webkit tests - http_server_base.HttpServerBase.__init__(self, port_obj, number_of_servers) - self._name = 'lighttpd' - self._output_dir = output_dir - self._port = port - self._root = root - self._run_background = run_background - self._additional_dirs = additional_dirs - self._layout_tests_dir = layout_tests_dir - - self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name) - - if self._port: - self._port = int(self._port) - - if not self._layout_tests_dir: - self._layout_tests_dir = self._port_obj.layout_tests_dir() - - self._webkit_tests = os.path.join(self._layout_tests_dir, 'http', 'tests') - self._js_test_resource = os.path.join(self._layout_tests_dir, 'resources') - self._media_resource = os.path.join(self._layout_tests_dir, 'media') - - # 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 _prepare_config(self): - base_conf_file = self._port_obj.path_from_webkit_base('Tools', - 'Scripts', 'webkitpy', 'layout_tests', 'servers', '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" - access_log = os.path.join(self._output_dir, access_file_name) - log_file_name = "error.log-" + time_str + ".txt" - error_log = os.path.join(self._output_dir, log_file_name) - - # Write out the config - base_conf = self._filesystem.read_text_file(base_conf_file) - - # FIXME: This should be re-worked so that this block can - # use with open() instead of a manual file.close() call. - f = self._filesystem.open_text_file_for_writing(out_conf_file) - f.write(base_conf) - - # Write out our cgi handlers. Run perl through env so that it - # processes the #! line and runs perl with the proper command - # line arguments. Emulate apache's mod_asis with a cat cgi handler. - f.write(('cgi.assign = ( ".cgi" => "/usr/bin/env",\n' - ' ".pl" => "/usr/bin/env",\n' - ' ".asis" => "/bin/cat",\n' - ' ".php" => "%s" )\n\n') % - self._port_obj._path_to_lighttpd_php()) - - # Setup log files - f.write(('server.errorlog = "%s"\n' - 'accesslog.filename = "%s"\n\n') % (error_log, access_log)) - - # Setup upload folders. Upload folder is to hold temporary upload files - # and also POST data. This is used to support XHR layout tests that - # does POST. - f.write(('server.upload-dirs = ( "%s" )\n\n') % (self._output_dir)) - - # Setup a link to where the js test templates are stored - f.write(('alias.url = ( "/js-test-resources" => "%s" )\n\n') % - (self._js_test_resource)) - - if self._additional_dirs: - for alias, path in self._additional_dirs.iteritems(): - f.write(('alias.url += ( "%s" => "%s" )\n\n') % (alias, path)) - - # Setup a link to where the media resources are stored. - f.write(('alias.url += ( "/media-resources" => "%s" )\n\n') % - (self._media_resource)) - - # dump out of virtual host config at the bottom. - if self._root: - if self._port: - # Have both port and root dir. - mappings = [{'port': self._port, 'docroot': self._root}] - else: - # Have only a root dir - set the ports as for LayoutTests. - # This is used in ui_tests to run http tests against a browser. - - # default set of ports as for LayoutTests but with a - # specified root. - mappings = [{'port': 8000, 'docroot': self._root}, - {'port': 8080, 'docroot': self._root}, - {'port': 8443, 'docroot': self._root, - 'sslcert': self._pem_file}] - else: - mappings = self.VIRTUALCONFIG - for mapping in mappings: - ssl_setup = '' - if 'sslcert' in mapping: - ssl_setup = (' ssl.engine = "enable"\n' - ' ssl.pemfile = "%s"\n' % mapping['sslcert']) - - f.write(('$SERVER["socket"] == "127.0.0.1:%d" {\n' - ' server.document-root = "%s"\n' + - ssl_setup + - '}\n\n') % (mapping['port'], mapping['docroot'])) - f.close() - - executable = self._port_obj._path_to_lighttpd() - module_path = self._port_obj._path_to_lighttpd_modules() - start_cmd = [executable, - # Newly written config file - '-f', os.path.join(self._output_dir, 'lighttpd.conf'), - # Where it can find its module dynamic libraries - '-m', module_path] - - if not self._run_background: - start_cmd.append(# Don't background - '-D') - - # Copy liblightcomp.dylib to /tmp/lighttpd/lib to work around the - # bug that mod_alias.so loads it from the hard coded path. - if self._port_obj.host.platform.is_mac(): - tmp_module_path = '/tmp/lighttpd/lib' - if not self._filesystem.exists(tmp_module_path): - self._filesystem.maybe_make_directory(tmp_module_path) - lib_file = 'liblightcomp.dylib' - self._filesystem.copyfile(self._filesystem.join(module_path, lib_file), - self._filesystem.join(tmp_module_path, lib_file)) - - self._start_cmd = start_cmd - self._env = self._port_obj.setup_environ_for_server('lighttpd') - self._mappings = mappings - - def _remove_stale_logs(self): - # Sometimes logs are open in other processes but they should clear eventually. - for log_prefix in ('access.log-', 'error.log-'): - try: - self._remove_log_files(self._output_dir, log_prefix) - except OSError, e: - _log.warning('Failed to remove old %s %s files' % (self._name, log_prefix)) - - def _spawn_process(self): - _log.debug('Starting %s server, cmd="%s"' % (self._name, self._start_cmd)) - process = self._executive.popen(self._start_cmd, env=self._env, shell=False, stderr=self._executive.PIPE) - pid = process.pid - self._filesystem.write_text_file(self._pid_file, str(pid)) - return pid - - def _stop_running_server(self): - # FIXME: It would be nice if we had a cleaner way of killing this process. - # Currently we throw away the process object created in _spawn_process, - # since there doesn't appear to be any way to kill the server any more - # cleanly using it than just killing the pid, and we need to support - # killing a pid directly anyway for run-webkit-httpd and run-webkit-websocketserver. - self._wait_for_action(self._check_and_kill) - if self._filesystem.exists(self._pid_file): - self._filesystem.remove(self._pid_file) - - def _check_and_kill(self): - if self._executive.check_running_pid(self._pid): - host = self._port_obj.host - if host.platform.is_win() and not host.platform.is_cygwin(): - # FIXME: https://bugs.webkit.org/show_bug.cgi?id=106838 - # We need to kill all of the child processes as well as the - # parent, so we can't use executive.kill_process(). - # - # If this is actually working, we should figure out a clean API. - self._executive.run_command(["taskkill.exe", "/f", "/t", "/pid", self._pid], error_handler=self._executive.ignore_error) - else: - self._executive.kill_process(self._pid) - return False - return True diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/httpd2.pem b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/httpd2.pem deleted file mode 100644 index 6349b782b26..00000000000 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/httpd2.pem +++ /dev/null @@ -1,41 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQUFADBgMRAwDgYDVQQDEwdUZXN0 -IENBMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN -TW91bnRhaW4gVmlldzESMBAGA1UEChMJQ2VydCBUZXN0MB4XDTA4MDcyODIyMzIy -OFoXDTEzMDcyNzIyMzIyOFowSjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlm -b3JuaWExEjAQBgNVBAoTCUNlcnQgVGVzdDESMBAGA1UEAxMJMTI3LjAuMC4xMIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQj2tPWPUgbuI4H3/3dnttqVbndwU3 -3BdRCd67DFM44GRrsjDSH4bY/EbFyX9D52d/iy6ZaAmDePcCz5k/fgP3DMujykYG -qgNiV2ywxTlMj7NlN2C7SRt68fQMZr5iI7rypdxuaZt9lSMD3ENBffYtuLTyZd9a -3JPJe1TaIab5GwIDAQABo4HCMIG/MAkGA1UdEwQCMAAwHQYDVR0OBBYEFCYLBv5K -x5sLNVlpLh5FwTwhdDl7MIGSBgNVHSMEgYowgYeAFF3Of5nj1BlBMU/Gz7El9Vqv -45cxoWSkYjBgMRAwDgYDVQQDEwdUZXN0IENBMQswCQYDVQQGEwJVUzETMBEGA1UE -CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzESMBAGA1UEChMJ -Q2VydCBUZXN0ggkA1FGT1D/e2U4wDQYJKoZIhvcNAQEFBQADggIBAEtkVmLObUgk -b2cIA2S+QDtifq1UgVfBbytvR2lFmnADOR55mo0gHQG3HHqq4g034LmoVXDHhUk8 -Gb6aFiv4QubmVhLXcUelTRXwiNvGzkW7pC6Jrq105hdPjzXMKTcmiLaopm5Fqfc7 -hj5Cn1Sjspc8pdeQjrbeMdvca7KlFrGP8YkwCU2xOOX9PiN9G0966BWfjnr/fZZp -+OQVuUFHdiAZwthEMuDpAAXHqYXIsermgdOpgJaA53cf8NqBV2QGhtFgtsJCRoiu -7DKqhyRWBGyz19VIH2b7y+6qvQVxuHk19kKRM0nftw/yNcJnm7gtttespMUPsOMa -a2SD1G0hm0TND6vxaBhgR3cVqpl/qIpAdFi00Tm7hTyYE7I43zPW03t+/DpCt3Um -EMRZsQ90co5q+bcx/vQ7YAtwUh30uMb0wpibeyCwDp8cqNmSiRkEuc/FjTYes5t8 -5gR//WX1l0+qjrjusO9NmoLnq2Yk6UcioX+z+q6Z/dudGfqhLfeWD2Q0LWYA242C -d7km5Y3KAt1PJdVsof/aiVhVdddY/OIEKTRQhWEdDbosy2eh16BCKXT2FFvhNDg1 -AYFvn6I8nj9IldMJiIc3DdhacEAEzRMeRgPdzAa1griKUGknxsyTyRii8ru0WS6w -DCNrlDOVXdzYGEZooBI76BDVY0W0akjV ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDQj2tPWPUgbuI4H3/3dnttqVbndwU33BdRCd67DFM44GRrsjDS -H4bY/EbFyX9D52d/iy6ZaAmDePcCz5k/fgP3DMujykYGqgNiV2ywxTlMj7NlN2C7 -SRt68fQMZr5iI7rypdxuaZt9lSMD3ENBffYtuLTyZd9a3JPJe1TaIab5GwIDAQAB -AoGANHXu8z2YIzlhE+bwhGm8MGBpKL3qhRuKjeriqMA36tWezOw8lY4ymEAU+Ulv -BsCdaxqydQoTYou57m4TyUHEcxq9pq3H0zB0qL709DdHi/t4zbV9XIoAzC5v0/hG -9+Ca29TwC02FCw+qLkNrtwCpwOcQmc+bPxqvFu1iMiahURECQQD2I/Hi2413CMZz -TBjl8fMiVO9GhA2J0sc8Qi+YcgJakaLD9xcbaiLkTzPZDlA389C1b6Ia+poAr4YA -Ve0FFbxpAkEA2OobayyHE/QtPEqoy6NLR57jirmVBNmSWWd4lAyL5UIHIYVttJZg -8CLvbzaU/iDGwR+wKsM664rKPHEmtlyo4wJBAMeSqYO5ZOCJGu9NWjrHjM3fdAsG -8zs2zhiLya+fcU0iHIksBW5TBmt71Jw/wMc9R5J1K0kYvFml98653O5si1ECQBCk -RV4/mE1rmlzZzYFyEcB47DQkcM5ictvxGEsje0gnfKyRtAz6zI0f4QbDRUMJ+LWw -XK+rMsYHa+SfOb0b9skCQQCLdeonsIpFDv/Uv+flHISy0WA+AFkLXrRkBKh6G/OD -dMHaNevkJgUnpceVEnkrdenp5CcEoFTI17pd+nBgDm/B ------END RSA PRIVATE KEY----- diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.conf b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.conf deleted file mode 100644 index 4360c37d9d8..00000000000 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.conf +++ /dev/null @@ -1,89 +0,0 @@ -server.tag = "LightTPD/1.4.19 (Win32)" -server.modules = ( "mod_accesslog", - "mod_alias", - "mod_cgi", - "mod_rewrite" ) - -# default document root required -server.document-root = "." - -# files to check for if .../ is requested -index-file.names = ( "index.php", "index.pl", "index.cgi", - "index.html", "index.htm", "default.htm" ) -# mimetype mapping -mimetype.assign = ( - ".gif" => "image/gif", - ".jpg" => "image/jpeg", - ".jpeg" => "image/jpeg", - ".png" => "image/png", - ".svg" => "image/svg+xml", - ".css" => "text/css", - ".html" => "text/html", - ".htm" => "text/html", - ".xhtml" => "application/xhtml+xml", - ".js" => "application/x-javascript", - ".log" => "text/plain", - ".conf" => "text/plain", - ".text" => "text/plain", - ".txt" => "text/plain", - ".dtd" => "text/xml", - ".xml" => "text/xml", - ".manifest" => "text/cache-manifest", - ) - -# Use the "Content-Type" extended attribute to obtain mime type if possible -mimetype.use-xattr = "enable" - -## -# which extensions should not be handle via static-file transfer -# -# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi -static-file.exclude-extensions = ( ".php", ".pl", ".cgi" ) - -server.bind = "localhost" -server.port = 8001 - -## virtual directory listings -dir-listing.activate = "enable" -#dir-listing.encoding = "iso-8859-2" -#dir-listing.external-css = "style/oldstyle.css" - -## enable debugging -#debug.log-request-header = "enable" -#debug.log-response-header = "enable" -#debug.log-request-handling = "enable" -#debug.log-file-not-found = "enable" - -#### SSL engine -#ssl.engine = "enable" -#ssl.pemfile = "server.pem" - -# Rewrite rule for utf-8 path test (LayoutTests/http/tests/uri/utf8-path.html) -# See the apache rewrite rule at LayoutTests/http/tests/uri/intercept/.htaccess -# Rewrite rule for LayoutTests/http/tests/appcache/cyrillic-uri.html. -# See the apache rewrite rule at -# LayoutTests/http/tests/appcache/resources/intercept/.htaccess -url.rewrite-once = ( - "^/uri/intercept/(.*)" => "/uri/resources/print-uri.php", - "^/appcache/resources/intercept/(.*)" => "/appcache/resources/print-uri.php" -) - -# LayoutTests/http/tests/xmlhttprequest/response-encoding.html uses an htaccess -# to override charset for reply2.txt, reply2.xml, and reply4.txt. -$HTTP["url"] =~ "^/xmlhttprequest/resources/reply2.(txt|xml)" { - mimetype.assign = ( - ".txt" => "text/plain; charset=windows-1251", - ".xml" => "text/xml; charset=windows-1251" - ) -} -$HTTP["url"] =~ "^/xmlhttprequest/resources/reply4.txt" { - mimetype.assign = ( ".txt" => "text/plain; charset=koi8-r" ) -} - -# LayoutTests/http/tests/appcache/wrong-content-type.html uses an htaccess -# to override mime type for wrong-content-type.manifest. -$HTTP["url"] =~ "^/appcache/resources/wrong-content-type.manifest" { - mimetype.assign = ( ".manifest" => "text/plain" ) -} - -# Autogenerated test-specific config follows. diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.py new file mode 100644 index 00000000000..f4bf7c45937 --- /dev/null +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.py @@ -0,0 +1,131 @@ +# Copyright (C) 2011 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. + +"""Start and stop the lighttpd server as it is used by the layout tests.""" + +import logging +import time + +from webkitpy.layout_tests.servers import server_base + + +_log = logging.getLogger(__name__) + + +class Lighttpd(server_base.ServerBase): + + def __init__(self, port_obj, output_dir): + super(Lighttpd, self).__init__(port_obj, output_dir) + self._name = 'lighttpd' + self._log_prefixes = ('access.log-', 'error.log-') + self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name) + + self._layout_tests_dir = self._port_obj.layout_tests_dir() + + self._webkit_tests = self._filesystem.join(self._layout_tests_dir, 'http', 'tests') + self._js_test_resource = self._filesystem.join(self._layout_tests_dir, 'resources') + self._media_resource = self._filesystem.join(self._layout_tests_dir, 'media') + + # Self generated certificate for SSL server. + self._pem_file = self._filesystem.join(self._layout_tests_dir, 'http', 'conf', 'httpd2.pem') + + self.mappings = [ + {'port': 8000, 'docroot': self._webkit_tests}, + {'port': 8080, 'docroot': self._webkit_tests}, + {'port': 8443, 'docroot': self._webkit_tests, 'sslcert': self._pem_file}, + ] + + self._start_cmd = [ + self._port_obj.path_to_lighttpd(), + '-f', self._filesystem.join(self._output_dir, 'lighttpd.conf'), + '-m', self._port_obj.path_to_lighttpd_modules(), + '-D', + ] + self._env = self._port_obj.setup_environ_for_server() + + def _prepare_config(self): + time_str = time.strftime("%d%b%Y-%H%M%S") + access_file_name = "access.log-" + time_str + ".txt" + access_log = self._filesystem.join(self._output_dir, access_file_name) + log_file_name = "error.log-" + time_str + ".txt" + error_log = self._filesystem.join(self._output_dir, log_file_name) + + # Write out the config + base_conf_file = self._filesystem.join(self._layout_tests_dir, 'http', 'conf', 'lighttpd.conf') + out_conf_file = self._filesystem.join(self._output_dir, 'lighttpd.conf') + with self._filesystem.open_text_file_for_writing(out_conf_file) as f: + base_conf = self._filesystem.read_text_file(base_conf_file) + f.write(base_conf) + + # Write out our cgi handlers. Run perl through env so that it + # processes the #! line and runs perl with the proper command + # line arguments. Emulate apache's mod_asis with a cat cgi handler. + f.write(('cgi.assign = ( ".cgi" => "/usr/bin/env",\n' + ' ".pl" => "/usr/bin/env",\n' + ' ".asis" => "/bin/cat",\n' + ' ".php" => "%s" )\n\n') % + self._port_obj.path_to_lighttpd_php()) + + # Setup log files + f.write(('server.errorlog = "%s"\n' + 'accesslog.filename = "%s"\n\n') % (error_log, access_log)) + + # Setup upload folders. Upload folder is to hold temporary upload files + # and also POST data. This is used to support XHR layout tests that + # does POST. + f.write(('server.upload-dirs = ( "%s" )\n\n') % (self._output_dir)) + + # Setup a link to where the js test templates are stored + f.write(('alias.url = ( "/js-test-resources" => "%s" )\n\n') % + (self._js_test_resource)) + + # Setup a link to where the media resources are stored. + f.write(('alias.url += ( "/media-resources" => "%s" )\n\n') % + (self._media_resource)) + + # dump out of virtual host config at the bottom. + for mapping in self.mappings: + ssl_setup = '' + if 'sslcert' in mapping: + ssl_setup = (' ssl.engine = "enable"\n' + ' ssl.pemfile = "%s"\n' % mapping['sslcert']) + + f.write(('$SERVER["socket"] == "127.0.0.1:%d" {\n' + ' server.document-root = "%s"\n' + + ssl_setup + + '}\n\n') % (mapping['port'], mapping['docroot'])) + + # Copy liblightcomp.dylib to /tmp/lighttpd/lib to work around the + # bug that mod_alias.so loads it from the hard coded path. + if self._port_obj.host.platform.is_mac(): + tmp_module_path = '/tmp/lighttpd/lib' + if not self._filesystem.exists(tmp_module_path): + self._filesystem.maybe_make_directory(tmp_module_path) + lib_file = 'liblightcomp.dylib' + self._filesystem.copyfile(self._filesystem.join(self._port_obj.path_to_lighttpd_modules(), lib_file), + self._filesystem.join(tmp_module_path, lib_file)) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server_unittest.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd_unittest.py index 740cd2b5692..50fbb99dbe1 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server_unittest.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd_unittest.py @@ -32,11 +32,11 @@ import webkitpy.thirdparty.unittest2 as unittest from webkitpy.common.host_mock import MockHost from webkitpy.layout_tests.port import test -from webkitpy.layout_tests.servers.http_server import Lighttpd -from webkitpy.layout_tests.servers.http_server_base import ServerError +from webkitpy.layout_tests.servers.lighttpd import Lighttpd +from webkitpy.layout_tests.servers.server_base import ServerError -class TestHttpServer(unittest.TestCase): +class TestLighttpdServer(unittest.TestCase): def test_start_cmd(self): # Fails on win - see https://bugs.webkit.org/show_bug.cgi?id=84726 if sys.platform in ('cygwin', 'win32'): @@ -45,21 +45,16 @@ class TestHttpServer(unittest.TestCase): host = MockHost() test_port = test.TestPort(host) host.filesystem.write_text_file( - "/mock-checkout/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.conf", "Mock Config\n") + "/test.checkout/LayoutTests/http/conf/lighttpd.conf", "Mock Config\n") host.filesystem.write_text_file( "/usr/lib/lighttpd/liblightcomp.dylib", "Mock dylib") - server = Lighttpd(test_port, "/mock/output_dir", - additional_dirs={ - "/mock/one-additional-dir": "/mock-checkout/one-additional-dir", - "/mock/another-additional-dir": "/mock-checkout/one-additional-dir"}) + server = Lighttpd(test_port, "/mock/output_dir") self.assertRaises(ServerError, server.start) config_file = host.filesystem.read_text_file("/mock/output_dir/lighttpd.conf") self.assertEqual(re.findall(r"alias.url.+", config_file), [ 'alias.url = ( "/js-test-resources" => "/test.checkout/LayoutTests/resources" )', - 'alias.url += ( "/mock/one-additional-dir" => "/mock-checkout/one-additional-dir" )', - 'alias.url += ( "/mock/another-additional-dir" => "/mock-checkout/one-additional-dir" )', 'alias.url += ( "/media-resources" => "/test.checkout/LayoutTests/media" )', ]) @@ -67,17 +62,14 @@ class TestHttpServer(unittest.TestCase): host = MockHost() test_port = test.TestPort(host) host.filesystem.write_text_file( - "/mock-checkout/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/lighttpd.conf", "Mock Config\n") + "/test.checkout/LayoutTests/http/conf/lighttpd.conf", "Mock Config\n") host.filesystem.write_text_file( "/usr/lib/lighttpd/liblightcomp.dylib", "Mock dylib") host.platform.is_win = lambda: True host.platform.is_cygwin = lambda: False - server = Lighttpd(test_port, "/mock/output_dir", - additional_dirs={ - "/mock/one-additional-dir": "/mock-checkout/one-additional-dir", - "/mock/another-additional-dir": "/mock-checkout/one-additional-dir"}) + server = Lighttpd(test_port, "/mock/output_dir") server._check_that_all_ports_are_available = lambda: True server._is_server_running_on_all_ports = lambda: True @@ -96,6 +88,4 @@ class TestHttpServer(unittest.TestCase): host.executive.check_running_pid = mock_returns([True, False]) server._wait_for_action = wait_for_action - server.stop() - self.assertEqual(['taskkill.exe', '/f', '/t', '/pid', 42], host.executive.calls[1]) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py new file mode 100644 index 00000000000..f5fa4d5fe1d --- /dev/null +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py @@ -0,0 +1,76 @@ +# Copyright (C) 2011 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. + +"""A class to help start/stop the PyWebSocket server as used by the layout tests.""" + +import logging +import os +import sys +import time + +from webkitpy.layout_tests.servers import server_base +from webkitpy.thirdparty import mod_pywebsocket + +_log = logging.getLogger(__name__) + + +_WS_LOG_PREFIX = 'pywebsocket.ws.log-' + +_DEFAULT_WS_PORT = 8880 + + +class PyWebSocket(server_base.ServerBase): + + def __init__(self, port_obj, output_dir): + super(PyWebSocket, self).__init__(port_obj, output_dir) + self._name = 'pywebsocket' + self._log_prefixes = (_WS_LOG_PREFIX,) + self._mappings = [{'port': _DEFAULT_WS_PORT}] + self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name) + + self._port = _DEFAULT_WS_PORT + self._layout_tests = self._port_obj.layout_tests_dir() + self._web_socket_tests = self._filesystem.join(self._layout_tests, 'http', 'tests', 'websocket') + time_str = time.strftime('%d%b%Y-%H%M%S') + log_file_name = _WS_LOG_PREFIX + time_str + error_log = self._filesystem.join(self._output_dir, log_file_name + "-err.txt") + pywebsocket_base = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty') + pywebsocket_script = self._filesystem.join(pywebsocket_base, 'mod_pywebsocket', 'standalone.py') + + self._start_cmd = [ + sys.executable, '-u', pywebsocket_script, + '--server-host', 'localhost', + '--port', str(self._port), + '--document-root', self._web_socket_tests, + '--scan-dir', self._web_socket_tests, + '--cgi-paths', '/', + '--log-file', error_log, + '--websock-handlers-map-file', self._filesystem.join(self._web_socket_tests, 'handler_map.txt'), + ] + self._env = self._port_obj.setup_environ_for_server() + self._env['PYTHONPATH'] = (pywebsocket_base + os.pathsep + self._env.get('PYTHONPATH', '')) diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server_base.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/server_base.py index 3ce15a5683c..5b7f34121a3 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server_base.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/server_base.py @@ -26,7 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Base class with common routines between the Apache, Lighttpd, and websocket servers.""" +"""Base class used to start servers used by the layout tests.""" import errno import logging @@ -43,18 +43,14 @@ class ServerError(Exception): pass -class HttpServerBase(object): +class ServerBase(object): """A skeleton class for starting and stopping servers used by the layout tests.""" - def __init__(self, port_obj, number_of_servers=None): + def __init__(self, port_obj, output_dir): + self._port_obj = port_obj self._executive = port_obj._executive self._filesystem = port_obj._filesystem - self._name = '<virtual>' - self._mappings = {} - self._pid = None - self._pid_file = None - self._port_obj = port_obj - self._number_of_servers = number_of_servers + self._output_dir = output_dir # We need a non-checkout-dependent place to put lock files, etc. We # don't use the Python default on the Mac because it defaults to a @@ -67,6 +63,20 @@ class HttpServerBase(object): self._runtime_path = self._filesystem.join(tmpdir, "WebKit") self._filesystem.maybe_make_directory(self._runtime_path) + # Subclasses must override these fields. + self._name = '<virtual>' + self._log_prefixes = tuple() + self._mappings = {} + self._pid_file = None + self._start_cmd = None + + # Subclasses may override these fields. + self._env = None + self._stdout = self._executive.PIPE + self._stderr = self._executive.PIPE + self._process = None + self._pid = None + def start(self): """Starts the server. It is an error to start an already started server. @@ -140,20 +150,31 @@ class HttpServerBase(object): left over from a prior run. This routine should log warnings if the files cannot be deleted, but should not fail unless failure to delete the logs will actually cause start() to fail.""" - pass + # Sometimes logs are open in other processes but they should clear eventually. + for log_prefix in self._log_prefixes: + try: + self._remove_log_files(self._output_dir, log_prefix) + except OSError, e: + _log.warning('Failed to remove old %s %s files' % (self._name, log_prefix)) def _spawn_process(self): - """This routine must be implemented by subclasses to actually start the server. - - This routine returns the pid of the started process, and also ensures that that - pid has been written to self._pid_file.""" - raise NotImplementedError() + _log.debug('Starting %s server, cmd="%s"' % (self._name, self._start_cmd)) + process = self._executive.popen(self._start_cmd, env=self._env, stdout=self._stdout, stderr=self._stderr) + pid = process.pid + self._filesystem.write_text_file(self._pid_file, str(pid)) + return pid def _stop_running_server(self): - """This routine must be implemented by subclasses to actually stop the running server listed in self._pid_file.""" - raise NotImplementedError() + self._wait_for_action(self._check_and_kill) + if self._filesystem.exists(self._pid_file): + self._filesystem.remove(self._pid_file) - # Utility routines. + def _check_and_kill(self): + if self._executive.check_running_pid(self._pid): + host = self._port_obj.host + self._executive.kill_process(self._pid) + return False + return True def _remove_pid_file(self): if self._filesystem.exists(self._pid_file): diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server_base_unittest.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/server_base_unittest.py index c6fb2e9cff6..8a1a992a06a 100644 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/http_server_base_unittest.py +++ b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/server_base_unittest.py @@ -30,17 +30,17 @@ import webkitpy.thirdparty.unittest2 as unittest from webkitpy.common.host_mock import MockHost from webkitpy.layout_tests.port import test -from webkitpy.layout_tests.servers.http_server_base import HttpServerBase +from webkitpy.layout_tests.servers.server_base import ServerBase -class TestHttpServerBase(unittest.TestCase): +class TestServerBase(unittest.TestCase): def test_corrupt_pid_file(self): # This tests that if the pid file is corrupt or invalid, # both start() and stop() deal with it correctly and delete the file. host = MockHost() test_port = test.TestPort(host) - server = HttpServerBase(test_port) + server = ServerBase(test_port, test_port.default_results_directory()) server._pid_file = '/tmp/pidfile' server._spawn_process = lambda: 4 server._is_server_running_on_all_ports = lambda: True diff --git a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/websocket_server.py b/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/websocket_server.py deleted file mode 100644 index 9f47dee0d32..00000000000 --- a/chromium/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/websocket_server.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright (C) 2011 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. - -"""A class to help start/stop the PyWebSocket server used by layout tests.""" - -import logging -import os -import sys -import time - -from webkitpy.layout_tests.servers import http_server -from webkitpy.layout_tests.servers import http_server_base - -_log = logging.getLogger(__name__) - - -_WS_LOG_PREFIX = 'pywebsocket.ws.log-' -_WSS_LOG_PREFIX = 'pywebsocket.wss.log-' - - -_DEFAULT_WS_PORT = 8880 -_DEFAULT_WSS_PORT = 9323 - - -class PyWebSocket(http_server.Lighttpd): - def __init__(self, port_obj, output_dir, port=_DEFAULT_WS_PORT, - root=None, use_tls=False, - private_key=None, certificate=None, ca_certificate=None, - pidfile=None): - """Args: - output_dir: the absolute path to the layout test result directory - """ - http_server.Lighttpd.__init__(self, port_obj, output_dir, - port=_DEFAULT_WS_PORT, - root=root) - self._output_dir = output_dir - self._pid_file = pidfile - self._process = None - - self._port = port - self._root = root - self._use_tls = use_tls - - self._name = 'pywebsocket' - if self._use_tls: - self._name = 'pywebsocket_secure' - - if private_key: - self._private_key = private_key - else: - self._private_key = self._pem_file - if certificate: - self._certificate = certificate - else: - self._certificate = self._pem_file - self._ca_certificate = ca_certificate - if self._port: - self._port = int(self._port) - self._wsin = None - self._wsout = None - self._mappings = [{'port': self._port}] - - if not self._pid_file: - self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name) - - # Webkit tests - # FIXME: This is the wrong way to detect if we're in Chrome vs. WebKit! - # The port objects are supposed to abstract this. - if self._root: - self._layout_tests = self._filesystem.abspath(self._root) - self._web_socket_tests = self._filesystem.abspath(self._filesystem.join(self._root, 'http', 'tests', 'websocket')) - else: - try: - self._layout_tests = self._port_obj.layout_tests_dir() - self._web_socket_tests = self._filesystem.join(self._layout_tests, 'http', 'tests', 'websocket') - except: - self._web_socket_tests = None - - if self._use_tls: - self._log_prefix = _WSS_LOG_PREFIX - else: - self._log_prefix = _WS_LOG_PREFIX - - def _prepare_config(self): - time_str = time.strftime('%d%b%Y-%H%M%S') - log_file_name = self._log_prefix + time_str - # FIXME: Doesn't Executive have a devnull, so that we don't have to use os.devnull directly? - self._wsin = open(os.devnull, 'r') - - error_log = self._filesystem.join(self._output_dir, log_file_name + "-err.txt") - output_log = self._filesystem.join(self._output_dir, log_file_name + "-out.txt") - self._wsout = self._filesystem.open_text_file_for_writing(output_log) - - from webkitpy.thirdparty import mod_pywebsocket - python_interp = sys.executable - # FIXME: Use self._filesystem.path_to_module(self.__module__) instead of __file__ - # I think this is trying to get the chrome directory? Doesn't the port object know that? - pywebsocket_base = self._filesystem.join(self._filesystem.dirname(self._filesystem.dirname(self._filesystem.dirname(self._filesystem.abspath(__file__)))), 'thirdparty') - pywebsocket_script = self._filesystem.join(pywebsocket_base, 'mod_pywebsocket', 'standalone.py') - start_cmd = [ - python_interp, '-u', pywebsocket_script, - '--server-host', 'localhost', - '--port', str(self._port), - '--document-root', self._web_socket_tests, - '--scan-dir', self._web_socket_tests, - '--cgi-paths', '/', - '--log-file', error_log, - ] - - handler_map_file = self._filesystem.join(self._web_socket_tests, 'handler_map.txt') - if self._filesystem.exists(handler_map_file): - _log.debug('Using handler_map_file: %s' % handler_map_file) - start_cmd.append('--websock-handlers-map-file') - start_cmd.append(handler_map_file) - else: - _log.warning('No handler_map_file found') - - if self._use_tls: - start_cmd.extend(['-t', '-k', self._private_key, - '-c', self._certificate]) - if self._ca_certificate: - start_cmd.append('--ca-certificate') - start_cmd.append(self._ca_certificate) - - self._start_cmd = start_cmd - server_name = self._filesystem.basename(pywebsocket_script) - self._env = self._port_obj.setup_environ_for_server(server_name) - self._env['PYTHONPATH'] = (pywebsocket_base + os.path.pathsep + self._env.get('PYTHONPATH', '')) - - def _remove_stale_logs(self): - try: - self._remove_log_files(self._output_dir, self._log_prefix) - except OSError, e: - _log.warning('Failed to remove stale %s log files: %s' % (self._name, str(e))) - - def _spawn_process(self): - _log.debug('Starting %s server, cmd="%s"' % (self._name, self._start_cmd)) - self._process = self._executive.popen(self._start_cmd, env=self._env, shell=False, stdin=self._wsin, stdout=self._wsout, stderr=self._executive.STDOUT) - self._filesystem.write_text_file(self._pid_file, str(self._process.pid)) - return self._process.pid - - def _stop_running_server(self): - super(PyWebSocket, self)._stop_running_server() - - if self._wsin: - self._wsin.close() - self._wsin = None - if self._wsout: - self._wsout.close() - self._wsout = None |