1 # Copyright (C) 2017 Igalia S.L.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
16 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 from webkitpy.common.webkit_finder import WebKitFinder
33 _log = logging.getLogger(__name__)
36 class WebDriverW3CWebServer(object):
38 def __init__(self, port):
42 layout_root = self._port.layout_tests_dir()
43 self._layout_doc_root = os.path.join(layout_root, 'imported', 'w3c', 'web-platform-tests')
48 tmpdir = tempfile.gettempdir()
49 if self._port.host.platform.is_mac():
51 self._runtime_path = os.path.join(tmpdir, "WebKitWebDriverTests")
52 self._port.host.filesystem.maybe_make_directory(self._runtime_path)
54 self._pid_file = os.path.join(self._runtime_path, '%s.pid' % self._name)
55 self._servers_file = os.path.join(self._runtime_path, '%s_servers.json' % (self._name))
57 # FIXME: We use the runtime path for now for log output, since we don't have a results directory yet.
58 self._output_log_path = os.path.join(self._runtime_path, '%s_process_log.out.txt' % (self._name))
60 def _wait_for_server(self, wait_secs=20, sleep_secs=1):
61 def check_port(host, port):
64 s.connect((host, port))
66 if e.errno not in (errno.ECONNREFUSED, errno.ECONNRESET):
73 start_time = time.time()
74 while time.time() - start_time < wait_secs:
75 if self._port._executive.check_running_pid(self._pid) and check_port(self._server_host, self._server_port):
77 time.sleep(sleep_secs)
81 assert not self._pid, '%s server is already running' % self._name
83 # Stop any stale servers left over from previous instances.
84 if self._port.host.filesystem.exists(self._pid_file):
86 self._pid = int(self._port.host.filesystem.read_text_file(self._pid_file))
88 except (ValueError, UnicodeDecodeError):
89 # These could be raised if the pid file is corrupt.
90 self._port.host.filesystem.remove(self._pid_file)
93 _log.debug('Copying WebDriver WPT server config.json')
94 doc_root = os.path.join(WebKitFinder(self._port.host.filesystem).path_from_webkit_base('WebDriverTests'), 'imported', 'w3c')
95 config_filename = os.path.join(doc_root, 'config.json')
96 config_json = self._port.host.filesystem.read_text_file(config_filename).replace("%DOC_ROOT%", doc_root)
97 self._port.host.filesystem.write_text_file(os.path.join(self._layout_doc_root, 'config.json'), config_json)
98 config = json.loads(config_json)
99 self._server_host = config['host']
100 self._server_port = config['ports']['http'][0]
102 self._wsout = self._port.host.filesystem.open_text_file_for_writing(self._output_log_path)
103 launcher = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'layout_tests', 'servers', 'web_platform_test_launcher.py'))
104 cmd = ['python', launcher, self._servers_file]
105 self._process = self._port._executive.popen(cmd, cwd=self._layout_doc_root, shell=False, stdin=self._port._executive.PIPE, stdout=self._wsout, stderr=self._wsout)
106 self._pid = self._process.pid
107 self._port.host.filesystem.write_text_file(self._pid_file, str(self._pid))
109 if not self._wait_for_server():
110 _log.error('WPT Server process exited prematurely with status code %s' % self._process.returncode)
114 _log.info('WebDriver WPT server listening at http://%s:%s/' % (self._server_host, self._server_port))
117 _log.debug('Cleaning WebDriver WPT server config.json')
118 temporary_config_file = os.path.join(self._layout_doc_root, 'config.json')
119 if self._port.host.filesystem.exists(temporary_config_file):
120 self._port.host.filesystem.remove(temporary_config_file)
122 self._process.communicate(input='\n')
126 if self._pid and self._port._executive.check_running_pid(self._pid):
127 _log.warning('Cannot stop %s server normally.' % (self._name))
128 _log.warning('Killing server launcher process (pid: %d).' % (self._pid))
129 self._port._executive.kill_process(self._pid)
130 self._port.host.filesystem.remove(self._pid_file)
134 return self._server_host
137 return self._server_port