blob: e41aeb21aade2b3626963b19081984cf41cd14ce [file] [log] [blame]
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Start and stop the WPTserve servers as they're used by the layout tests."""
import datetime
import json
import logging
from blinkpy.common.path_finder import PathFinder
from blinkpy.web_tests.servers import server_base
_log = logging.getLogger(__name__)
class WPTServe(server_base.ServerBase):
def __init__(self, port_obj, output_dir):
super(WPTServe, self).__init__(port_obj, output_dir)
# These ports must match wpt_support/wpt.config.json
http_port, http_alt_port, https_port = (8001, 8081, 8444)
ws_port, wss_port = (9001, 9444)
self._name = 'wptserve'
self._log_prefixes = ('access_log', 'error_log')
self._mappings = [{'port': http_port},
{'port': http_alt_port},
{'port': https_port, 'sslcert': True},
{'port': ws_port},
{'port': wss_port, 'sslcert': True}]
# TODO(burnik): We can probably avoid PID files for WPT in the future.
fs = self._filesystem
self._pid_file = fs.join(self._runtime_path, '' % self._name)
finder = PathFinder(fs)
path_to_pywebsocket = finder.path_from_chromium_base('third_party', 'pywebsocket', 'src')
path_to_wpt_support = finder.path_from_blink_tools('blinkpy', 'third_party', 'wpt')
path_to_wpt_root = fs.join(path_to_wpt_support, 'wpt')
path_to_wpt_tests = fs.abspath(fs.join(self._port_obj.layout_tests_dir(), 'external', 'wpt'))
path_to_ws_handlers = fs.join(path_to_wpt_tests, 'websockets', 'handlers')
self._config_file = self._prepare_wptserve_config(path_to_wpt_support)
wpt_script = fs.join(path_to_wpt_root, 'wpt')
start_cmd = [,
'-u', wpt_script, 'serve',
'--config', self._config_file,
'--doc_root', path_to_wpt_tests]
# TODO(burnik): Merge with default start_cmd once we roll in websockets.
start_cmd += ['--ws_doc_root', path_to_ws_handlers]
self._stdout = self._stderr = self._executive.DEVNULL
# TODO(burnik): We should stop setting the CWD once WPT can be run without it.
self._cwd = path_to_wpt_root
self._env =
self._env.update({'PYTHONPATH': path_to_pywebsocket})
self._start_cmd = start_cmd
expiration_date =, 1, 4)
if > expiration_date - datetime.timedelta(30):
'Pre-generated keys and certificates are going to be expired at %s.'
' Please re-generate them by following steps in %s/README.chromium.',
expiration_date.strftime('%b %d %Y'), path_to_wpt_support)
def _prepare_wptserve_config(self, path_to_wpt_support):
fs = self._filesystem
template_path = fs.join(path_to_wpt_support, 'wpt.config.json')
config = json.loads(fs.read_text_file(template_path))
'url-path': '/gen/',
'local-dir': self._port_obj.generated_sources_directory()
f, temp_file = fs.open_text_tempfile('.json')
json.dump(config, f)
return temp_file
def _stop_running_server(self):
if self._filesystem.exists(self._pid_file):
if self._filesystem.exists(self._config_file):
def _check_and_kill_wptserve(self):
"""Tries to kill wptserve.
Returns True if it appears to be not running. Or, if it appears to be
running, tries to kill the process and returns False.
if not (self._pid and self._executive.check_running_pid(self._pid)):
_log.debug('pid %d is not running', self._pid)
return True
_log.debug('pid %d is running, killing it', self._pid)
# Executive.kill_process appears to not to effectively kill the
# wptserve processes on Linux (and presumably other platforms).
if self._platform.is_win():
# According to Popen.wait(), this can deadlock when using stdout=PIPE or
# stderr=PIPE. We're using DEVNULL for both so that should not occur.
if self._process is not None:
return False