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')
47 tmpdir = tempfile.gettempdir()
48 if self._port.host.platform.is_mac():
50 self._runtime_path = os.path.join(tmpdir, "WebKitWebDriverTests")
51 self._port.host.filesystem.maybe_make_directory(self._runtime_path)
53 self._pid_file = os.path.join(self._runtime_path, '%s.pid' % self._name)
54 self._servers_file = os.path.join(self._runtime_path, '%s_servers.json' % (self._name))
56 # FIXME: We use the runtime path for now for log output, since we don't have a results directory yet.
57 self._output_log_path = os.path.join(self._runtime_path, '%s_process_log.out.txt' % (self._name))
59 def _wait_for_server(self, wait_secs=20, sleep_secs=1):
60 def check_port(host, port):
63 s.connect((host, port))
65 if e.errno not in (errno.ECONNREFUSED, errno.ECONNRESET):
72 start_time = time.time()
73 while time.time() - start_time < wait_secs:
74 if self._port._executive.check_running_pid(self._pid) and check_port(self._server_host, self._server_port):
76 time.sleep(sleep_secs)
80 assert not self._pid, '%s server is already running' % self._name
82 # Stop any stale servers left over from previous instances.
83 if self._port.host.filesystem.exists(self._pid_file):
85 self._pid = int(self._port.host.filesystem.read_text_file(self._pid_file))
87 except (ValueError, UnicodeDecodeError):
88 # These could be raised if the pid file is corrupt.
89 self._port.host.filesystem.remove(self._pid_file)
92 _log.debug('Copying WebDriver WPT server config.json')
93 doc_root = os.path.join(WebKitFinder(self._port.host.filesystem).path_from_webkit_base('WebDriverTests'), 'imported', 'w3c')
94 config_filename = os.path.join(doc_root, 'config.json')
95 config_json = self._port.host.filesystem.read_text_file(config_filename).replace("%DOC_ROOT%", doc_root)
96 self._port.host.filesystem.write_text_file(os.path.join(self._layout_doc_root, 'config.json'), config_json)
97 config = json.loads(config_json)
98 self._server_host = config['host']
99 self._server_port = config['ports']['http'][0]
101 self._wsout = self._port.host.filesystem.open_text_file_for_writing(self._output_log_path)
102 launcher = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'layout_tests', 'servers', 'web_platform_test_launcher.py'))
103 cmd = ['python', launcher, self._servers_file]
104 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)
105 self._pid = self._process.pid
106 self._port.host.filesystem.write_text_file(self._pid_file, str(self._pid))
108 if not self._wait_for_server():
109 _log.error('WPT Server process exited prematurely with status code %s' % self._process.returncode)
113 _log.info('WebDriver WPT server listening at http://%s:%s/' % (self._server_host, self._server_port))
116 _log.debug('Cleaning WebDriver WPT server config.json')
117 self._port.host.filesystem.remove(os.path.join(self._layout_doc_root, 'config.json'))
119 self._process.communicate(input='\n')
123 if self._pid and self._port._executive.check_running_pid(self._pid):
124 _log.warning('Cannot stop %s server normally.' % (self._name))
125 _log.warning('Killing server launcher process (pid: %d).' % (self._pid))
126 self._port._executive.kill_process(self._pid)
127 self._port.host.filesystem.remove(self._pid_file)
131 return self._server_host
134 return self._server_port