WebDriver: add timeout option to run-webdriver-tests script
[WebKit-https.git] / Tools / Scripts / webkitpy / webdriver_tests / webdriver_w3c_executor.py
1 # Copyright (C) 2017 Igalia S.L.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
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.
11 #
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.
22
23 import logging
24 import os
25 import sys
26
27 from webkitpy.common.system.filesystem import FileSystem
28 from webkitpy.common.webkit_finder import WebKitFinder
29 import webkitpy.thirdparty.autoinstalled.mozlog
30 import webkitpy.thirdparty.autoinstalled.mozprocess
31 from mozlog import structuredlog
32
33 w3c_tools_dir = WebKitFinder(FileSystem()).path_from_webkit_base('WebDriverTests', 'imported', 'w3c', 'tools')
34
35
36 def _ensure_directory_in_path(directory):
37     if not directory in sys.path:
38         sys.path.insert(0, directory)
39 _ensure_directory_in_path(os.path.join(w3c_tools_dir, 'pytest'))
40 _ensure_directory_in_path(os.path.join(w3c_tools_dir, 'webdriver'))
41 _ensure_directory_in_path(os.path.join(w3c_tools_dir, 'wptrunner'))
42 _ensure_directory_in_path(os.path.join(w3c_tools_dir, "webdriver"))
43
44 import webkitpy.thirdparty.autoinstalled.pytest_timeout
45 from wptrunner.executors.base import WdspecExecutor, WebDriverProtocol
46 from wptrunner.webdriver_server import WebDriverServer
47
48 _log = logging.getLogger(__name__)
49
50
51 class MessageLogger(object):
52
53     def __init__(self, message_func):
54         self.name = 'WebKit WebDriver WPT logger'
55         self.send_message = message_func
56
57     def _log_data(self, action, **kwargs):
58         self.send_message('log', action, kwargs)
59
60     def process_output(self, process, data, command):
61         self._log_data('process_output', process=process, data=data, command=command)
62
63
64 class TestRunner(object):
65
66     def __init__(self):
67         self.logger = MessageLogger(self.send_message)
68         structuredlog.set_default_logger(self.logger)
69
70     def send_message(self, command, *args):
71         if command == 'log':
72             self._log(*args)
73
74     def _log(self, level, details):
75         if level == 'process_output':
76             self._process_output(details['process'], details['command'], details['data'])
77             return
78
79         if not 'message' in details:
80             return
81         message = details['message']
82         if level == 'info':
83             _log.info(message)
84         elif level == 'debug':
85             _log.debug(message)
86         elif level == 'error':
87             _log.error(message)
88         elif level == 'criticial':
89             _log.critical(message)
90         elif level == 'warning':
91             _log.warning(message)
92
93     def _process_output(self, pid, command, data):
94         _log.debug('(%s:%d): %s' % (os.path.basename(command).split()[0], pid, data))
95
96
97 def _log_func(level_name):
98     def log(self, message):
99         self._log_data(level_name.lower(), message=message)
100     log.__name__ = str(level_name).lower()
101     return log
102
103 # Create all the methods on StructuredLog for debug levels.
104 for level_name in structuredlog.log_levels:
105     setattr(MessageLogger, level_name.lower(), _log_func(level_name))
106
107
108 class WebKitDriverServer(WebDriverServer):
109     default_base_path = '/'
110     test_env = None
111
112     def __init__(self, logger, binary=None, port=None, base_path='', args=None):
113         WebDriverServer.__init__(self, logger, binary, port=port, base_path=base_path, args=args, env=self.test_env)
114
115     def make_command(self):
116         return [self.binary, '--port=%s' % str(self.port)] + self._args
117
118
119 class WebKitDriverProtocol(WebDriverProtocol):
120     server_cls = WebKitDriverServer
121
122
123 class WebDriverW3CExecutor(WdspecExecutor):
124     protocol_cls = WebKitDriverProtocol
125
126     def __init__(self, driver, server, display_driver):
127         WebKitDriverServer.test_env = display_driver._setup_environ_for_test()
128         WebKitDriverServer.test_env.update(driver.browser_env())
129         server_config = {'host': server.host(), 'ports': {'http': [str(server.port())]}}
130         WdspecExecutor.__init__(self, driver.browser_name(), server_config, driver.binary_path(), None, capabilities=driver.capabilities())
131
132     def setup(self):
133         self.runner = TestRunner()
134         self.protocol.setup(self.runner)
135
136     def teardown(self):
137         self.protocol.teardown()
138
139     def run(self, path):
140         # Timeout here doesn't really matter because it's ignored, so we pass 0.
141         return self.do_wdspec(self.protocol.session_config, path, 0)