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 |