WebDriver: add support for test expectations
[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 json
26 import sys
27
28 from webkitpy.common.system.filesystem import FileSystem
29 from webkitpy.common.webkit_finder import WebKitFinder
30 import webkitpy.thirdparty.autoinstalled.mozlog
31 import webkitpy.thirdparty.autoinstalled.mozprocess
32 from mozlog import structuredlog
33
34 w3c_tools_dir = WebKitFinder(FileSystem()).path_from_webkit_base('WebDriverTests', 'imported', 'w3c', 'tools')
35
36
37 def _ensure_directory_in_path(directory):
38     if not directory in sys.path:
39         sys.path.insert(0, directory)
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
43 from wptrunner.executors.base import WdspecExecutor, WebDriverProtocol
44 from wptrunner.webdriver_server import WebDriverServer
45
46 pytest_runner = None
47
48
49 def do_delayed_imports():
50     global pytest_runner
51     import webkitpy.webdriver_tests.pytest_runner as pytest_runner
52
53
54 _log = logging.getLogger(__name__)
55
56
57 class MessageLogger(object):
58
59     def __init__(self, message_func):
60         self.name = 'WebKit WebDriver WPT logger'
61         self.send_message = message_func
62
63     def _log_data(self, action, **kwargs):
64         self.send_message('log', action, kwargs)
65
66     def process_output(self, process, data, command):
67         self._log_data('process_output', process=process, data=data, command=command)
68
69
70 class TestRunner(object):
71
72     def __init__(self):
73         self.logger = MessageLogger(self.send_message)
74         structuredlog.set_default_logger(self.logger)
75
76     def send_message(self, command, *args):
77         if command == 'log':
78             self._log(*args)
79
80     def _log(self, level, details):
81         if level == 'process_output':
82             self._process_output(details['process'], details['command'], details['data'])
83             return
84
85         if not 'message' in details:
86             return
87         message = details['message']
88         if level == 'info':
89             _log.info(message)
90         elif level == 'debug':
91             _log.debug(message)
92         elif level == 'error':
93             _log.error(message)
94         elif level == 'criticial':
95             _log.critical(message)
96         elif level == 'warning':
97             _log.warning(message)
98
99     def _process_output(self, pid, command, data):
100         _log.debug('(%s:%d): %s' % (os.path.basename(command).split()[0], pid, data))
101
102
103 def _log_func(level_name):
104     def log(self, message):
105         self._log_data(level_name.lower(), message=message)
106     log.__name__ = str(level_name).lower()
107     return log
108
109 # Create all the methods on StructuredLog for debug levels.
110 for level_name in structuredlog.log_levels:
111     setattr(MessageLogger, level_name.lower(), _log_func(level_name))
112
113
114 class WebKitDriverServer(WebDriverServer):
115     default_base_path = '/'
116     test_env = None
117
118     def __init__(self, logger, binary=None, port=None, base_path='', args=None):
119         WebDriverServer.__init__(self, logger, binary, port=port, base_path=base_path, args=args, env=self.test_env)
120
121     def make_command(self):
122         return [self.binary, '--port=%s' % str(self.port)] + self._args
123
124
125 class WebKitDriverProtocol(WebDriverProtocol):
126     server_cls = WebKitDriverServer
127
128
129 class WebDriverW3CExecutor(WdspecExecutor):
130     protocol_cls = WebKitDriverProtocol
131
132     def __init__(self, driver, server, display_driver):
133         WebKitDriverServer.test_env = display_driver._setup_environ_for_test()
134         WebKitDriverServer.test_env.update(driver.browser_env())
135         server_config = {'host': server.host(), 'ports': {'http': [str(server.port())]}}
136         WdspecExecutor.__init__(self, driver.browser_name(), server_config, driver.binary_path(), None, capabilities=driver.capabilities())
137
138         if pytest_runner is None:
139             do_delayed_imports()
140
141     def setup(self):
142         self.runner = TestRunner()
143         self.protocol.setup(self.runner)
144
145     def teardown(self):
146         self.protocol.teardown()
147
148     def run(self, test, timeout, expectations):
149         env = {'WD_HOST': self.protocol.session_config['host'],
150                'WD_PORT': str(self.protocol.session_config['port']),
151                'WD_CAPABILITIES': json.dumps(self.protocol.session_config['capabilities']),
152                'WD_SERVER_CONFIG': json.dumps(self.server_config)}
153         args = ['--strict', '-p', 'no:mozlog']
154         return pytest_runner.run(test, args, timeout, env, expectations)