OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """A class to start/stop the apache http server used by layout tests.""" |
| 6 |
| 7 import logging |
| 8 import optparse |
| 9 import os |
| 10 import subprocess |
| 11 import sys |
| 12 import time |
| 13 |
| 14 import google.httpd_utils |
| 15 |
| 16 import path_utils |
| 17 import platform_utils |
| 18 |
| 19 class LayoutTestApacheHttpd(object): |
| 20 _PORTS = [ |
| 21 {'port': 8000}, |
| 22 {'port': 8080}, |
| 23 {'port': 8443, 'is_ssl': True} |
| 24 ] |
| 25 |
| 26 def __init__(self, output_dir): |
| 27 """Args: |
| 28 output_dir: the absolute path to the layout test result directory |
| 29 """ |
| 30 self._output_dir = output_dir |
| 31 self._httpd_proc = None |
| 32 path_utils.MaybeMakeDirectory(output_dir) |
| 33 |
| 34 # The upstream .conf file assumed the existence of /tmp/WebKit for placing |
| 35 # apache files like the lock file there. |
| 36 path_utils.MaybeMakeDirectory(os.path.join("/tmp", "WebKit")) |
| 37 |
| 38 test_dir = path_utils.PathFromBase('third_party', 'WebKit', |
| 39 'LayoutTests') |
| 40 js_test_resources_dir = os.path.join(test_dir, "fast", "js", "resources") |
| 41 mime_types_path = os.path.join(test_dir, "http", "conf", "mime.types") |
| 42 cert_file = os.path.join(test_dir, "http", "conf", "webkit-httpd.pem") |
| 43 |
| 44 cmd = [os.path.join("/usr", "sbin", "httpd"), |
| 45 '-f', self._GetApacheConfigFilePath(test_dir, output_dir), |
| 46 '-C', "DocumentRoot %s" % os.path.join(test_dir, "http", "tests"), |
| 47 '-c', "Alias /js-test-resources %s" % js_test_resources_dir, |
| 48 '-C', "Listen %s" % "127.0.0.1:8000", |
| 49 '-C', "Listen %s" % "127.0.0.1:8081", |
| 50 '-c', "TypesConfig \"%s\"" % mime_types_path, |
| 51 '-c', "CustomLog \"%s/access_log.txt\" common" % output_dir, |
| 52 '-c', "ErrorLog \"%s/error_log.txt\"" % output_dir, |
| 53 '-C', "User \"%s\"" % os.environ.get("USERNAME", |
| 54 os.environ.get("USER", "")), |
| 55 '-c', "SSLCertificateFile %s" % cert_file, |
| 56 ] |
| 57 |
| 58 self._start_cmd = cmd |
| 59 |
| 60 def _GetApacheConfigFilePath(self, test_dir, output_dir): |
| 61 """Returns the path to the apache config file to use. |
| 62 Args: |
| 63 test_dir: absolute path to the LayoutTests directory. |
| 64 output_dir: absolute path to the layout test results directory. |
| 65 """ |
| 66 conf_file_name = "apache2-httpd.conf" |
| 67 httpd_config = os.path.join(test_dir, "http", "conf", conf_file_name) |
| 68 httpd_config_copy = os.path.join(output_dir, conf_file_name) |
| 69 main_document_root = os.path.join(path_utils.LayoutTestsDir(), |
| 70 "LayoutTests", "http", "tests") |
| 71 chrome_document_root = path_utils.PathFromBase('webkit', 'data', |
| 72 'layout_tests') |
| 73 httpd_conf = open(httpd_config).read() |
| 74 # TODO(ojan): Instead of writing an extra file, checkin a conf file |
| 75 # upstream. Or, even better, upstream/delete all our chrome http tests so we |
| 76 # don't need this special-cased DocumentRoot and then just use the upstream |
| 77 # conf file. |
| 78 httpd_conf = (httpd_conf + |
| 79 self._GetVirtualHostConfig(chrome_document_root, 8081)) |
| 80 |
| 81 f = open(httpd_config_copy, 'wb') |
| 82 f.write(httpd_conf) |
| 83 f.close() |
| 84 |
| 85 return httpd_config_copy |
| 86 |
| 87 def _GetVirtualHostConfig(self, document_root, port, ssl=False): |
| 88 """Returns a <VirtualHost> directive block for an httpd.conf file. It will |
| 89 listen to 127.0.0.1 on each of the given port. |
| 90 """ |
| 91 return '\n'.join(('<VirtualHost 127.0.0.1:%s>' % port, |
| 92 'DocumentRoot %s' % document_root, |
| 93 ssl and 'SSLEngine On' or '', |
| 94 '</VirtualHost>', '')) |
| 95 |
| 96 def _IsServerRunningOnAllPorts(self): |
| 97 """Returns whether the server is running on all the desired ports.""" |
| 98 for mapping in self._PORTS: |
| 99 url = 'http%s://127.0.0.1:%d/' % ('is_ssl' in mapping and 's' or '', |
| 100 mapping['port']) |
| 101 if not google.httpd_utils.UrlIsAlive(url): |
| 102 return False |
| 103 |
| 104 return True |
| 105 |
| 106 def _StartHttpdProcess(self): |
| 107 """Starts the httpd process and returns whether there were errors.""" |
| 108 self._httpd_proc = subprocess.Popen(self._start_cmd, stderr=subprocess.PIPE) |
| 109 if len(self._httpd_proc.stderr.read()): |
| 110 return False |
| 111 return True |
| 112 |
| 113 def _WaitForAction(self, action): |
| 114 """Repeat the action for 20 seconds or until it succeeds. Returns whether |
| 115 it succeeded.""" |
| 116 succeeded = False |
| 117 |
| 118 start_time = time.time() |
| 119 # Give apache up to 20 seconds to start up. |
| 120 while time.time() - start_time < 20 and not succeeded: |
| 121 succeeded = action() |
| 122 |
| 123 return succeeded |
| 124 |
| 125 def Start(self): |
| 126 """Starts the apache http server.""" |
| 127 # Stop any currently running servers. |
| 128 self.Stop() |
| 129 |
| 130 logging.debug("Starting apache http server") |
| 131 server_started = self._WaitForAction(self._StartHttpdProcess) |
| 132 if server_started: |
| 133 server_started = self._WaitForAction(self._IsServerRunningOnAllPorts) |
| 134 |
| 135 if server_started: |
| 136 logging.debug("Server successfully started") |
| 137 else: |
| 138 raise google.httpd_utils.HttpdNotStarted('Failed to start httpd') |
| 139 |
| 140 def Stop(self): |
| 141 """Stops the apache http server.""" |
| 142 logging.debug("Shutting down any running http servers") |
| 143 path_utils.ShutDownHTTPServer(self._httpd_proc) |
OLD | NEW |