Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(617)

Side by Side Diff: LayoutTests/imported/web-platform-tests/serve.py

Issue 560893005: First checked-in import of the W3C's test suites. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: add new expectations for newly failing w3c tests Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- coding: utf-8 -*-
2 import argparse
3 import json
4 import logging
5 import os
6 import signal
7 import socket
8 import sys
9 import threading
10 import time
11 import urllib2
12 import uuid
13 from collections import defaultdict
14 from multiprocessing import Process, Event
15
16 repo_root = os.path.abspath(os.path.split(__file__)[0])
17
18 sys.path.insert(1, os.path.join(repo_root, "tools", "wptserve"))
19 from wptserve import server as wptserve, handlers
20 from wptserve.router import any_method
21 sys.path.insert(1, os.path.join(repo_root, "tools", "pywebsocket", "src"))
22 from mod_pywebsocket import standalone as pywebsocket
23
24 routes = [("GET", "/tools/runner/*", handlers.file_handler),
25 ("POST", "/tools/runner/update_manifest.py", handlers.python_script_ha ndler),
26 (any_method, "/tools/*", handlers.ErrorHandler(404)),
27 (any_method, "/serve.py", handlers.ErrorHandler(404)),
28 (any_method, "*.py", handlers.python_script_handler),
29 ("GET", "*.asis", handlers.as_is_handler),
30 ("GET", "*", handlers.file_handler),
31 ]
32
33 rewrites = [("GET", "/resources/WebIDLParser.js", "/resources/webidl2/lib/webidl 2.js")]
34
35 subdomains = [u"www",
36 u"www1",
37 u"www2",
38 u"天気の良い日",
39 u"élève"]
40
41 logger = None
42
43 def default_logger(level):
44 logger = logging.getLogger("web-platform-tests")
45 logging.basicConfig(level=getattr(logging, level.upper()))
46 return logger
47
48 def open_socket(port):
49 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
50 if port != 0:
51 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
52 sock.bind(('127.0.0.1', port))
53 sock.listen(5)
54 return sock
55
56 def get_port():
57 free_socket = open_socket(0)
58 port = free_socket.getsockname()[1]
59 logger.debug("Going to use port %s" % port)
60 free_socket.close()
61 return port
62
63
64 class ServerProc(object):
65 def __init__(self):
66 self.proc = None
67 self.daemon = None
68 self.stop = Event()
69
70 def start(self, init_func, config, paths, port, bind_hostname):
71 self.proc = Process(target=self.create_daemon, args=(init_func, config, paths, port, bind_hostname))
72 self.proc.daemon = True
73 self.proc.start()
74
75 def create_daemon(self, init_func, config, paths, port, bind_hostname):
76 try:
77 self.daemon = init_func(config, paths, port, bind_hostname)
78 except socket.error:
79 print >> sys.stderr, "Socket error on port %s" % port
80 raise
81
82 if self.daemon:
83 self.daemon.start(block=False)
84 try:
85 self.stop.wait()
86 except KeyboardInterrupt:
87 pass
88
89 def wait(self):
90 self.stop.set()
91 self.proc.join()
92
93 def kill(self):
94 self.stop.set()
95 self.proc.terminate()
96 self.proc.join()
97
98 def is_alive(self):
99 return self.proc.is_alive()
100
101 def check_subdomains(config, paths, subdomains, bind_hostname):
102 port = get_port()
103 wrapper = ServerProc()
104 wrapper.start(start_http_server, config, paths, port, bind_hostname)
105
106 connected = False
107 for i in range(10):
108 try:
109 urllib2.urlopen("http://%s:%d/" % (config["host"], port))
110 connected = True
111 break
112 except urllib2.URLError:
113 time.sleep(1)
114
115 if not connected:
116 logger.critical("Failed to connect to test server on http://%s:%s You ma y need to edit /etc/hosts or similar" % (config["host"], port))
117 sys.exit(1)
118
119 for subdomain, (punycode, host) in subdomains.iteritems():
120 domain = "%s.%s" % (punycode, host)
121 try:
122 urllib2.urlopen("http://%s:%d/" % (domain, port))
123 except Exception as e:
124 logger.critical("Failed probing domain %s. You may need to edit /etc /hosts or similar." % domain)
125 sys.exit(1)
126
127 wrapper.wait()
128
129 def get_subdomains(config):
130 #This assumes that the tld is ascii-only or already in punycode
131 host = config["host"]
132 return {subdomain: (subdomain.encode("idna"), host)
133 for subdomain in subdomains}
134
135 def start_servers(config, paths, ports, bind_hostname):
136 servers = defaultdict(list)
137
138 host = config["host"]
139
140 for scheme, ports in ports.iteritems():
141 assert len(ports) == {"http":2}.get(scheme, 1)
142
143 for port in ports:
144 init_func = {"http":start_http_server,
145 "https":start_https_server,
146 "ws":start_ws_server,
147 "wss":start_wss_server}[scheme]
148
149 server_proc = ServerProc()
150 server_proc.start(init_func, config, paths, port, bind_hostname)
151 servers[scheme].append((port, server_proc))
152
153 return servers
154
155 def start_http_server(config, paths, port, bind_hostname):
156 return wptserve.WebTestHttpd(host=config["host"],
157 port=port,
158 doc_root=paths["doc_root"],
159 routes=routes,
160 rewrites=rewrites,
161 bind_hostname=bind_hostname,
162 config=config,
163 use_ssl=False,
164 certificate=None)
165
166 def start_https_server(config, paths, port, bind_hostname):
167 return
168
169 class WebSocketDaemon(object):
170 def __init__(self, host, port, doc_root, handlers_root, log_level, bind_host name):
171 self.host = host
172 cmd_args = ["-p", port,
173 "-d", doc_root,
174 "-w", handlers_root,
175 "--log-level", log_level]
176 if (bind_hostname):
177 cmd_args = ["-H", host] + cmd_args
178 opts, args = pywebsocket._parse_args_and_config(cmd_args)
179 opts.cgi_directories = []
180 opts.is_executable_method = None
181 self.server = pywebsocket.WebSocketServer(opts)
182 ports = [item[0].getsockname()[1] for item in self.server._sockets]
183 assert all(item == ports[0] for item in ports)
184 self.port = ports[0]
185 self.started = False
186 self.server_thread = None
187
188 def start(self, block=False):
189 self.started = True
190 if block:
191 self.server.serve_forever()
192 else:
193 self.server_thread = threading.Thread(target=self.server.serve_forev er)
194 self.server_thread.setDaemon(True) # don't hang on exit
195 self.server_thread.start()
196
197 def stop(self):
198 """
199 Stops the server.
200
201 If the server is not running, this method has no effect.
202 """
203 if self.started:
204 try:
205 self.server.shutdown()
206 self.server.server_close()
207 self.server_thread.join()
208 self.server_thread = None
209 except AttributeError:
210 pass
211 self.started = False
212 self.server = None
213
214 def start_ws_server(config, paths, port, bind_hostname):
215 return WebSocketDaemon(config["host"],
216 str(port),
217 repo_root,
218 paths["ws_doc_root"],
219 "debug",
220 bind_hostname)
221
222 def start_wss_server(config, paths, port, bind_hostname):
223 return
224
225 def get_ports(config):
226 rv = defaultdict(list)
227 for scheme, ports in config["ports"].iteritems():
228 for i, port in enumerate(ports):
229 if port == "auto":
230 port = get_port()
231 else:
232 port = port
233 rv[scheme].append(port)
234 return rv
235
236 def normalise_config(config, domains, ports):
237 ports_ = {}
238 for scheme, ports_used in ports.iteritems():
239 ports_[scheme] = ports_used
240
241 domains_ = domains.copy()
242
243 for key, value in domains_.iteritems():
244 domains_[key] = ".".join(value)
245
246 domains_[""] = config["host"]
247
248 return {"host":config["host"],
249 "domains":domains_,
250 "ports": ports_}
251
252 def start(config):
253 ports = get_ports(config)
254 domains = get_subdomains(config)
255 bind_hostname = config["bind_hostname"]
256
257 paths = {"doc_root": config["doc_root"],
258 "ws_doc_root": config["ws_doc_root"]}
259
260 if config["check_subdomains"]:
261 check_subdomains(config, paths, domains, bind_hostname)
262
263 config_ = normalise_config(config, domains, ports)
264
265 servers = start_servers(config_, paths, ports, bind_hostname)
266
267 return config_, servers
268
269
270 def iter_procs(servers):
271 for servers in servers.values():
272 for port, server in servers:
273 yield server.proc
274
275 def value_set(config, key):
276 return key in config and config[key] is not None
277
278 def set_computed_defaults(config):
279 if not value_set(config, "ws_doc_root"):
280 if value_set(config, "doc_root"):
281 root = config["doc_root"]
282 else:
283 root = repo_root
284 config["ws_doc_root"] = os.path.join(repo_root, "websockets", "handlers" )
285
286 if not value_set(config, "doc_root"):
287 config["doc_root"] = repo_root
288
289
290 def merge_json(base_obj, override_obj):
291 rv = {}
292 for key, value in base_obj.iteritems():
293 if key not in override_obj:
294 rv[key] = value
295 else:
296 if isinstance(value, dict):
297 rv[key] = merge_json(value, override_obj[key])
298 else:
299 rv[key] = override_obj[key]
300 return rv
301
302 def load_config(default_path, override_path=None):
303 if os.path.exists(default_path):
304 with open(default_path) as f:
305 base_obj = json.load(f)
306 else:
307 raise ValueError("Config path %s does not exist" % default_path)
308
309 if os.path.exists(override_path):
310 with open(override_path) as f:
311 override_obj = json.load(f)
312 else:
313 override_obj = {}
314 rv = merge_json(base_obj, override_obj)
315
316 set_computed_defaults(rv)
317 return rv
318
319 def main():
320 global logger
321
322 config = load_config("config.default.json",
323 "config.json")
324
325 logger = default_logger(config["log_level"])
326
327 config_, servers = start(config)
328
329 try:
330 while any(item.is_alive() for item in iter_procs(servers)):
331 for item in iter_procs(servers):
332 item.join(1)
333 except KeyboardInterrupt:
334 logger.info("Shutting down")
335
336 if __name__ == "__main__":
337 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698