| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 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 PyWebSocket server used by layout tests.""" | |
| 7 | |
| 8 | |
| 9 import logging | |
| 10 import optparse | |
| 11 import os | |
| 12 import subprocess | |
| 13 import sys | |
| 14 import tempfile | |
| 15 import time | |
| 16 | |
| 17 import path_utils | |
| 18 import platform_utils | |
| 19 import http_server | |
| 20 | |
| 21 # So we can import httpd_utils below to make ui_tests happy. | |
| 22 sys.path.append(path_utils.PathFromBase('tools', 'python')) | |
| 23 import google.httpd_utils | |
| 24 | |
| 25 _WS_LOG_PREFIX = 'pywebsocket.ws.log-' | |
| 26 _WSS_LOG_PREFIX = 'pywebsocket.wss.log-' | |
| 27 | |
| 28 _DEFAULT_WS_PORT = 8880 | |
| 29 _DEFAULT_WSS_PORT = 9323 | |
| 30 | |
| 31 | |
| 32 def RemoveLogFiles(folder, starts_with): | |
| 33 files = os.listdir(folder) | |
| 34 for file in files: | |
| 35 if file.startswith(starts_with): | |
| 36 full_path = os.path.join(folder, file) | |
| 37 os.remove(full_path) | |
| 38 | |
| 39 | |
| 40 class PyWebSocketNotStarted(Exception): | |
| 41 pass | |
| 42 | |
| 43 | |
| 44 class PyWebSocketNotFound(Exception): | |
| 45 pass | |
| 46 | |
| 47 | |
| 48 class PyWebSocket(http_server.Lighttpd): | |
| 49 | |
| 50 def __init__(self, output_dir, port=_DEFAULT_WS_PORT, | |
| 51 root=None, | |
| 52 use_tls=False, | |
| 53 private_key=http_server.Lighttpd._pem_file, | |
| 54 certificate=http_server.Lighttpd._pem_file, | |
| 55 register_cygwin=None, | |
| 56 pidfile=None): | |
| 57 """Args: | |
| 58 output_dir: the absolute path to the layout test result directory | |
| 59 """ | |
| 60 http_server.Lighttpd.__init__(self, output_dir, | |
| 61 port=port, | |
| 62 root=root, | |
| 63 register_cygwin=register_cygwin) | |
| 64 self._output_dir = output_dir | |
| 65 self._process = None | |
| 66 self._port = port | |
| 67 self._root = root | |
| 68 self._use_tls = use_tls | |
| 69 self._private_key = private_key | |
| 70 self._certificate = certificate | |
| 71 if self._port: | |
| 72 self._port = int(self._port) | |
| 73 if self._use_tls: | |
| 74 self._server_name = 'PyWebSocket(Secure)' | |
| 75 else: | |
| 76 self._server_name = 'PyWebSocket' | |
| 77 self._pidfile = pidfile | |
| 78 self._wsout = None | |
| 79 | |
| 80 # Webkit tests | |
| 81 if self._root: | |
| 82 self._layout_tests = os.path.abspath(self._root) | |
| 83 self._web_socket_tests = os.path.abspath( | |
| 84 os.path.join(self._root, 'websocket', 'tests')) | |
| 85 else: | |
| 86 try: | |
| 87 self._web_socket_tests = path_utils.PathFromBase( | |
| 88 'third_party', 'WebKit', 'LayoutTests', 'websocket', | |
| 89 'tests') | |
| 90 self._layout_tests = path_utils.PathFromBase( | |
| 91 'third_party', 'WebKit', 'LayoutTests') | |
| 92 except path_utils.PathNotFound: | |
| 93 self._web_socket_tests = None | |
| 94 | |
| 95 def Start(self): | |
| 96 if not self._web_socket_tests: | |
| 97 logging.info('No need to start %s server.' % self._server_name) | |
| 98 return | |
| 99 if self.IsRunning(): | |
| 100 raise PyWebSocketNotStarted('%s is already running.' % | |
| 101 self._server_name) | |
| 102 | |
| 103 time_str = time.strftime('%d%b%Y-%H%M%S') | |
| 104 if self._use_tls: | |
| 105 log_prefix = _WSS_LOG_PREFIX | |
| 106 else: | |
| 107 log_prefix = _WS_LOG_PREFIX | |
| 108 log_file_name = log_prefix + time_str | |
| 109 | |
| 110 # Remove old log files. We only need to keep the last ones. | |
| 111 RemoveLogFiles(self._output_dir, log_prefix) | |
| 112 | |
| 113 error_log = os.path.join(self._output_dir, log_file_name + "-err.txt") | |
| 114 | |
| 115 output_log = os.path.join(self._output_dir, log_file_name + "-out.txt") | |
| 116 self._wsout = open(output_log, "w") | |
| 117 | |
| 118 python_interp = sys.executable | |
| 119 pywebsocket_base = path_utils.PathFromBase( | |
| 120 'third_party', 'WebKit', 'WebKitTools', 'pywebsocket') | |
| 121 pywebsocket_script = path_utils.PathFromBase( | |
| 122 'third_party', 'WebKit', 'WebKitTools', 'pywebsocket', | |
| 123 'mod_pywebsocket', 'standalone.py') | |
| 124 start_cmd = [ | |
| 125 python_interp, pywebsocket_script, | |
| 126 '-p', str(self._port), | |
| 127 '-d', self._layout_tests, | |
| 128 '-s', self._web_socket_tests, | |
| 129 '-l', error_log, | |
| 130 ] | |
| 131 if self._use_tls: | |
| 132 start_cmd.extend(['-t', '-k', self._private_key, | |
| 133 '-c', self._certificate]) | |
| 134 | |
| 135 # Put the cygwin directory first in the path to find cygwin1.dll | |
| 136 env = os.environ | |
| 137 if sys.platform in ('cygwin', 'win32'): | |
| 138 env['PATH'] = '%s;%s' % ( | |
| 139 path_utils.PathFromBase('third_party', 'cygwin', 'bin'), | |
| 140 env['PATH']) | |
| 141 | |
| 142 if sys.platform == 'win32' and self._register_cygwin: | |
| 143 setup_mount = path_utils.PathFromBase('third_party', 'cygwin', | |
| 144 'setup_mount.bat') | |
| 145 subprocess.Popen(setup_mount).wait() | |
| 146 | |
| 147 env['PYTHONPATH'] = (pywebsocket_base + os.path.pathsep + | |
| 148 env.get('PYTHONPATH', '')) | |
| 149 | |
| 150 logging.debug('Starting %s server.' % self._server_name) | |
| 151 self._process = subprocess.Popen(start_cmd, stdout=self._wsout, | |
| 152 env=env) | |
| 153 | |
| 154 # Wait a bit before checking the liveness of the server. | |
| 155 time.sleep(0.5) | |
| 156 | |
| 157 if self._use_tls: | |
| 158 url = 'https' | |
| 159 else: | |
| 160 url = 'http' | |
| 161 url = url + '://127.0.0.1:%d/' % self._port | |
| 162 if not google.httpd_utils.UrlIsAlive(url): | |
| 163 raise PyWebSocketNotStarted( | |
| 164 'Failed to start %s server on port %s.' % | |
| 165 (self._server_name, self._port)) | |
| 166 | |
| 167 # Our process terminated already | |
| 168 if self._process.returncode != None: | |
| 169 raise PyWebSocketNotStarted( | |
| 170 'Failed to start %s server.' % self._server_name) | |
| 171 if self._pidfile: | |
| 172 f = open(self._pidfile, 'w') | |
| 173 f.write("%d" % self._process.pid) | |
| 174 f.close() | |
| 175 | |
| 176 def Stop(self, force=False): | |
| 177 if not force and not self.IsRunning(): | |
| 178 return | |
| 179 | |
| 180 if self._process: | |
| 181 pid = self._process.pid | |
| 182 elif self._pidfile: | |
| 183 f = open(self._pidfile) | |
| 184 pid = int(f.read().strip()) | |
| 185 f.close() | |
| 186 | |
| 187 if not pid: | |
| 188 raise PyWebSocketNotFound( | |
| 189 'Failed to find %s server pid.' % self._server_name) | |
| 190 | |
| 191 logging.debug('Shutting down %s server %d.' % (self._server_name, pid)) | |
| 192 platform_utils.KillProcess(pid) | |
| 193 | |
| 194 if self._process: | |
| 195 self._process.wait() | |
| 196 self._process = None | |
| 197 | |
| 198 if self._wsout: | |
| 199 self._wsout.close() | |
| 200 self._wsout = None | |
| 201 | |
| 202 | |
| 203 if '__main__' == __name__: | |
| 204 # Provide some command line params for starting the PyWebSocket server | |
| 205 # manually. | |
| 206 option_parser = optparse.OptionParser() | |
| 207 option_parser.add_option('--server', type='choice', | |
| 208 choices=['start', 'stop'], default='start', | |
| 209 help='Server action (start|stop)') | |
| 210 option_parser.add_option('-p', '--port', dest='port', | |
| 211 default=None, help='Port to listen on') | |
| 212 option_parser.add_option('-r', '--root', | |
| 213 help='Absolute path to DocumentRoot ' | |
| 214 '(overrides layout test roots)') | |
| 215 option_parser.add_option('-t', '--tls', dest='use_tls', | |
| 216 action='store_true', | |
| 217 default=False, help='use TLS (wss://)') | |
| 218 option_parser.add_option('-k', '--private_key', dest='private_key', | |
| 219 default='', help='TLS private key file.') | |
| 220 option_parser.add_option('-c', '--certificate', dest='certificate', | |
| 221 default='', help='TLS certificate file.') | |
| 222 option_parser.add_option('--register_cygwin', action="store_true", | |
| 223 dest="register_cygwin", | |
| 224 help='Register Cygwin paths (on Win try bots)') | |
| 225 option_parser.add_option('--pidfile', help='path to pid file.') | |
| 226 options, args = option_parser.parse_args() | |
| 227 | |
| 228 if not options.port: | |
| 229 if options.use_tls: | |
| 230 options.port = _DEFAULT_WSS_PORT | |
| 231 else: | |
| 232 options.port = _DEFAULT_WS_PORT | |
| 233 | |
| 234 kwds = {'port': options.port, 'use_tls': options.use_tls} | |
| 235 if options.root: | |
| 236 kwds['root'] = options.root | |
| 237 if options.private_key: | |
| 238 kwds['private_key'] = options.private_key | |
| 239 if options.certificate: | |
| 240 kwds['certificate'] = options.certificate | |
| 241 kwds['register_cygwin'] = options.register_cygwin | |
| 242 if options.pidfile: | |
| 243 kwds['pidfile'] = options.pidfile | |
| 244 | |
| 245 pywebsocket = PyWebSocket(tempfile.gettempdir(), **kwds) | |
| 246 | |
| 247 if 'start' == options.server: | |
| 248 pywebsocket.Start() | |
| 249 else: | |
| 250 pywebsocket.Stop(force=True) | |
| OLD | NEW |