| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """A class to help start/stop the lighttpd server used by layout tests.""" | |
| 7 | |
| 8 | |
| 9 import logging | |
| 10 import optparse | |
| 11 import os | |
| 12 import shutil | |
| 13 import subprocess | |
| 14 import sys | |
| 15 import tempfile | |
| 16 import time | |
| 17 import urllib | |
| 18 | |
| 19 import http_server_base | |
| 20 import path_utils | |
| 21 | |
| 22 # So we can import httpd_utils below to make ui_tests happy. | |
| 23 sys.path.append(path_utils.PathFromBase('tools', 'python')) | |
| 24 import google.httpd_utils | |
| 25 | |
| 26 | |
| 27 def RemoveLogFiles(folder, starts_with): | |
| 28 files = os.listdir(folder) | |
| 29 for file in files: | |
| 30 if file.startswith(starts_with): | |
| 31 full_path = os.path.join(folder, file) | |
| 32 os.remove(full_path) | |
| 33 | |
| 34 | |
| 35 class Lighttpd(http_server_base.HttpServerBase): | |
| 36 # Webkit tests | |
| 37 try: | |
| 38 _webkit_tests = path_utils.PathFromBase('third_party', 'WebKit', | |
| 39 'LayoutTests', 'http', 'tests') | |
| 40 _js_test_resource = path_utils.PathFromBase('third_party', 'WebKit', | |
| 41 'LayoutTests', 'fast', | |
| 42 'js', 'resources') | |
| 43 except path_utils.PathNotFound: | |
| 44 _webkit_tests = None | |
| 45 _js_test_resource = None | |
| 46 | |
| 47 # Path where we can access all of the tests | |
| 48 _all_tests = path_utils.PathFromBase('webkit', 'data', 'layout_tests') | |
| 49 # Self generated certificate for SSL server (for client cert get | |
| 50 # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt) | |
| 51 _pem_file = path_utils.PathFromBase('tools', 'python', 'google', | |
| 52 'httpd_config', 'httpd2.pem') | |
| 53 # One mapping where we can get to everything | |
| 54 VIRTUALCONFIG = [{'port': 8081, 'docroot': _all_tests}] | |
| 55 | |
| 56 if _webkit_tests: | |
| 57 VIRTUALCONFIG.extend( | |
| 58 # Three mappings (one with SSL enabled) for LayoutTests http tests | |
| 59 [{'port': 8000, 'docroot': _webkit_tests}, | |
| 60 {'port': 8080, 'docroot': _webkit_tests}, | |
| 61 {'port': 8443, 'docroot': _webkit_tests, 'sslcert': _pem_file}]) | |
| 62 | |
| 63 def __init__(self, output_dir, background=False, port=None, | |
| 64 root=None, register_cygwin=None, run_background=None): | |
| 65 """Args: | |
| 66 output_dir: the absolute path to the layout test result directory | |
| 67 """ | |
| 68 self._output_dir = output_dir | |
| 69 self._process = None | |
| 70 self._port = port | |
| 71 self._root = root | |
| 72 self._register_cygwin = register_cygwin | |
| 73 self._run_background = run_background | |
| 74 if self._port: | |
| 75 self._port = int(self._port) | |
| 76 | |
| 77 def IsRunning(self): | |
| 78 return self._process != None | |
| 79 | |
| 80 def Start(self): | |
| 81 if self.IsRunning(): | |
| 82 raise 'Lighttpd already running' | |
| 83 | |
| 84 base_conf_file = path_utils.PathFromBase('webkit', | |
| 85 'tools', 'layout_tests', 'layout_package', 'lighttpd.conf') | |
| 86 out_conf_file = os.path.join(self._output_dir, 'lighttpd.conf') | |
| 87 time_str = time.strftime("%d%b%Y-%H%M%S") | |
| 88 access_file_name = "access.log-" + time_str + ".txt" | |
| 89 access_log = os.path.join(self._output_dir, access_file_name) | |
| 90 log_file_name = "error.log-" + time_str + ".txt" | |
| 91 error_log = os.path.join(self._output_dir, log_file_name) | |
| 92 | |
| 93 # Remove old log files. We only need to keep the last ones. | |
| 94 RemoveLogFiles(self._output_dir, "access.log-") | |
| 95 RemoveLogFiles(self._output_dir, "error.log-") | |
| 96 | |
| 97 # Write out the config | |
| 98 f = file(base_conf_file, 'rb') | |
| 99 base_conf = f.read() | |
| 100 f.close() | |
| 101 | |
| 102 f = file(out_conf_file, 'wb') | |
| 103 f.write(base_conf) | |
| 104 | |
| 105 # Write out our cgi handlers. Run perl through env so that it | |
| 106 # processes the #! line and runs perl with the proper command | |
| 107 # line arguments. Emulate apache's mod_asis with a cat cgi handler. | |
| 108 f.write(('cgi.assign = ( ".cgi" => "/usr/bin/env",\n' | |
| 109 ' ".pl" => "/usr/bin/env",\n' | |
| 110 ' ".asis" => "/bin/cat",\n' | |
| 111 ' ".php" => "%s" )\n\n') % | |
| 112 path_utils.LigHTTPdPHPPath()) | |
| 113 | |
| 114 # Setup log files | |
| 115 f.write(('server.errorlog = "%s"\n' | |
| 116 'accesslog.filename = "%s"\n\n') % (error_log, access_log)) | |
| 117 | |
| 118 # Setup upload folders. Upload folder is to hold temporary upload files | |
| 119 # and also POST data. This is used to support XHR layout tests that | |
| 120 # does POST. | |
| 121 f.write(('server.upload-dirs = ( "%s" )\n\n') % (self._output_dir)) | |
| 122 | |
| 123 # Setup a link to where the js test templates are stored | |
| 124 f.write(('alias.url = ( "/js-test-resources" => "%s" )\n\n') % | |
| 125 (self._js_test_resource)) | |
| 126 | |
| 127 # dump out of virtual host config at the bottom. | |
| 128 if self._root: | |
| 129 if self._port: | |
| 130 # Have both port and root dir. | |
| 131 mappings = [{'port': self._port, 'docroot': self._root}] | |
| 132 else: | |
| 133 # Have only a root dir - set the ports as for LayoutTests. | |
| 134 # This is used in ui_tests to run http tests against a browser. | |
| 135 | |
| 136 # default set of ports as for LayoutTests but with a | |
| 137 # specified root. | |
| 138 mappings = [{'port': 8000, 'docroot': self._root}, | |
| 139 {'port': 8080, 'docroot': self._root}, | |
| 140 {'port': 8443, 'docroot': self._root, | |
| 141 'sslcert': Lighttpd._pem_file}] | |
| 142 else: | |
| 143 mappings = self.VIRTUALCONFIG | |
| 144 for mapping in mappings: | |
| 145 ssl_setup = '' | |
| 146 if 'sslcert' in mapping: | |
| 147 ssl_setup = (' ssl.engine = "enable"\n' | |
| 148 ' ssl.pemfile = "%s"\n' % mapping['sslcert']) | |
| 149 | |
| 150 f.write(('$SERVER["socket"] == "127.0.0.1:%d" {\n' | |
| 151 ' server.document-root = "%s"\n' + | |
| 152 ssl_setup + | |
| 153 '}\n\n') % (mapping['port'], mapping['docroot'])) | |
| 154 f.close() | |
| 155 | |
| 156 executable = path_utils.LigHTTPdExecutablePath() | |
| 157 module_path = path_utils.LigHTTPdModulePath() | |
| 158 start_cmd = [executable, | |
| 159 # Newly written config file | |
| 160 '-f', path_utils.PathFromBase(self._output_dir, | |
| 161 'lighttpd.conf'), | |
| 162 # Where it can find its module dynamic libraries | |
| 163 '-m', module_path] | |
| 164 | |
| 165 if not self._run_background: | |
| 166 start_cmd.append(# Don't background | |
| 167 '-D') | |
| 168 | |
| 169 # Copy liblightcomp.dylib to /tmp/lighttpd/lib to work around the | |
| 170 # bug that mod_alias.so loads it from the hard coded path. | |
| 171 if sys.platform == 'darwin': | |
| 172 tmp_module_path = '/tmp/lighttpd/lib' | |
| 173 if not os.path.exists(tmp_module_path): | |
| 174 os.makedirs(tmp_module_path) | |
| 175 lib_file = 'liblightcomp.dylib' | |
| 176 shutil.copyfile(os.path.join(module_path, lib_file), | |
| 177 os.path.join(tmp_module_path, lib_file)) | |
| 178 | |
| 179 # Put the cygwin directory first in the path to find cygwin1.dll | |
| 180 env = os.environ | |
| 181 if sys.platform in ('cygwin', 'win32'): | |
| 182 env['PATH'] = '%s;%s' % ( | |
| 183 path_utils.PathFromBase('third_party', 'cygwin', 'bin'), | |
| 184 env['PATH']) | |
| 185 | |
| 186 if sys.platform == 'win32' and self._register_cygwin: | |
| 187 setup_mount = path_utils.PathFromBase('third_party', 'cygwin', | |
| 188 'setup_mount.bat') | |
| 189 subprocess.Popen(setup_mount).wait() | |
| 190 | |
| 191 logging.debug('Starting http server') | |
| 192 self._process = subprocess.Popen(start_cmd, env=env) | |
| 193 | |
| 194 # Wait for server to start. | |
| 195 self.mappings = mappings | |
| 196 server_started = self.WaitForAction(self.IsServerRunningOnAllPorts) | |
| 197 | |
| 198 # Our process terminated already | |
| 199 if not server_started or self._process.returncode != None: | |
| 200 raise google.httpd_utils.HttpdNotStarted('Failed to start httpd.') | |
| 201 | |
| 202 logging.debug("Server successfully started") | |
| 203 | |
| 204 # TODO(deanm): Find a nicer way to shutdown cleanly. Our log files are | |
| 205 # probably not being flushed, etc... why doesn't our python have os.kill ? | |
| 206 | |
| 207 def Stop(self, force=False): | |
| 208 if not force and not self.IsRunning(): | |
| 209 return | |
| 210 | |
| 211 httpd_pid = None | |
| 212 if self._process: | |
| 213 httpd_pid = self._process.pid | |
| 214 path_utils.ShutDownHTTPServer(httpd_pid) | |
| 215 | |
| 216 if self._process: | |
| 217 self._process.wait() | |
| 218 self._process = None | |
| 219 | |
| 220 if '__main__' == __name__: | |
| 221 # Provide some command line params for starting/stopping the http server | |
| 222 # manually. Also used in ui_tests to run http layout tests in a browser. | |
| 223 option_parser = optparse.OptionParser() | |
| 224 option_parser.add_option('-k', '--server', | |
| 225 help='Server action (start|stop)') | |
| 226 option_parser.add_option('-p', '--port', | |
| 227 help='Port to listen on (overrides layout test ports)') | |
| 228 option_parser.add_option('-r', '--root', | |
| 229 help='Absolute path to DocumentRoot (overrides layout test roots)') | |
| 230 option_parser.add_option('--register_cygwin', action="store_true", | |
| 231 dest="register_cygwin", help='Register Cygwin paths (on Win try bots)') | |
| 232 option_parser.add_option('--run_background', action="store_true", | |
| 233 dest="run_background", | |
| 234 help='Run on background (for running as UI test)') | |
| 235 options, args = option_parser.parse_args() | |
| 236 | |
| 237 if not options.server: | |
| 238 print ('Usage: %s --server {start|stop} [--root=root_dir]' | |
| 239 ' [--port=port_number]' % sys.argv[0]) | |
| 240 else: | |
| 241 if (options.root is None) and (options.port is not None): | |
| 242 # specifying root but not port means we want httpd on default | |
| 243 # set of ports that LayoutTest use, but pointing to a different | |
| 244 # source of tests. Specifying port but no root does not seem | |
| 245 # meaningful. | |
| 246 raise 'Specifying port requires also a root.' | |
| 247 httpd = Lighttpd(tempfile.gettempdir(), | |
| 248 port=options.port, | |
| 249 root=options.root, | |
| 250 register_cygwin=options.register_cygwin, | |
| 251 run_background=options.run_background) | |
| 252 if 'start' == options.server: | |
| 253 httpd.Start() | |
| 254 else: | |
| 255 httpd.Stop(force=True) | |
| OLD | NEW |