blob: 7ba634a0775ff6acbdc7bcbca3ecce8948b8357a [file] [log] [blame]
Alexei Barantsev70795f32019-07-26 18:48:34 +03001# Licensed to the Software Freedom Conservancy (SFC) under one
2# or more contributor license agreements. See the NOTICE file
3# distributed with this work for additional information
4# regarding copyright ownership. The SFC licenses this file
5# to you under the Apache License, Version 2.0 (the
6# "License"); you may not use this file except in compliance
7# with the License. You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing,
12# software distributed under the License is distributed on an
13# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14# KIND, either express or implied. See the License for the
15# specific language governing permissions and limitations
16# under the License.
17
18import os
19import socket
20import subprocess
21import sys
22import time
23
24import pytest
25from _pytest.skipping import MarkEvaluator
26
27from selenium import webdriver
28from selenium.webdriver import DesiredCapabilities
29from test.selenium.webdriver.common.webserver import SimpleWebServer
30from test.selenium.webdriver.common.network import get_lan_ip
31
32if sys.version_info[0] == 3:
33 from urllib.request import urlopen
34else:
35 from urllib import urlopen
36
37drivers = (
38 'BlackBerry',
39 'Chrome',
40 'Edge',
41 'Firefox',
42 'Ie',
43 'Marionette',
44 'Remote',
45 'Safari',
46 'WebKitGTK',
47)
48
49
50def pytest_addoption(parser):
51 parser.addoption('--driver', action='append', choices=drivers, dest='drivers',
52 metavar='DRIVER',
53 help='driver to run tests against ({})'.format(', '.join(drivers)))
54 parser.addoption('--browser-binary', action='store', dest='binary',
55 help='location of the browser binary')
56 parser.addoption('--driver-binary', action='store', dest='executable',
57 help='location of the service executable binary')
58 parser.addoption('--browser-args', action='store', dest='args',
59 help='arguments to start the browser with')
60
61
62def pytest_ignore_collect(path, config):
63 drivers_opt = config.getoption('drivers')
64 _drivers = set(drivers).difference(drivers_opt or drivers)
65 if drivers_opt:
66 _drivers.add('unit')
67 parts = path.dirname.split(os.path.sep)
68 return len([d for d in _drivers if d.lower() in parts]) > 0
69
70
71driver_instance = None
72
73
74@pytest.fixture(scope='function')
75def driver(request):
76 kwargs = {}
77
78 try:
79 driver_class = request.param
80 except AttributeError:
81 raise Exception('This test requires a --driver to be specified.')
82
83 # conditionally mark tests as expected to fail based on driver
84 request.node._evalxfail = request.node._evalxfail or MarkEvaluator(
85 request.node, 'xfail_{0}'.format(driver_class.lower()))
86 if request.node._evalxfail.istrue():
87 def fin():
88 global driver_instance
89 if driver_instance is not None:
90 driver_instance.quit()
91 driver_instance = None
92 request.addfinalizer(fin)
93
94 # skip driver instantiation if xfail(run=False)
95 if not request.config.getoption('runxfail'):
96 if request.node._evalxfail.istrue():
97 if request.node._evalxfail.get('run') is False:
98 yield
99 return
100
101 driver_path = request.config.option.executable
102 options = None
103
104 global driver_instance
105 if driver_instance is None:
106 if driver_class == 'BlackBerry':
107 kwargs.update({'device_password': 'password'})
108 if driver_class == 'Firefox':
109 kwargs.update({'capabilities': {'marionette': False}})
110 options = get_options(driver_class, request.config)
111 if driver_class == 'Marionette':
112 driver_class = 'Firefox'
113 options = get_options(driver_class, request.config)
114 if driver_class == 'Remote':
115 capabilities = DesiredCapabilities.FIREFOX.copy()
116 kwargs.update({'desired_capabilities': capabilities})
117 options = get_options('Firefox', request.config)
118 if driver_class == 'WebKitGTK':
119 options = get_options(driver_class, request.config)
120 if driver_path is not None:
121 kwargs['executable_path'] = driver_path
122 if options is not None:
123 kwargs['options'] = options
124 driver_instance = getattr(webdriver, driver_class)(**kwargs)
125 yield driver_instance
126 if MarkEvaluator(request.node, 'no_driver_after_test').istrue():
127 driver_instance = None
128
129
130def get_options(driver_class, config):
131 browser_path = config.option.binary
132 browser_args = config.option.args
133 options = None
134 if browser_path or browser_args:
135 options = getattr(webdriver, '{}Options'.format(driver_class))()
136 if driver_class == 'WebKitGTK':
137 options.overlay_scrollbars_enabled = False
138 if browser_path is not None:
139 options.binary_location = browser_path
140 if browser_args is not None:
141 for arg in browser_args.split():
142 options.add_argument(arg)
143 return options
144
145
146@pytest.fixture(scope='session', autouse=True)
147def stop_driver(request):
148 def fin():
149 global driver_instance
150 if driver_instance is not None:
151 driver_instance.quit()
152 driver_instance = None
153 request.addfinalizer(fin)
154
155
156def pytest_exception_interact(node, call, report):
157 if report.failed:
158 global driver_instance
159 if driver_instance is not None:
160 driver_instance.quit()
161 driver_instance = None
162
163
164@pytest.fixture
165def pages(driver, webserver):
166 class Pages(object):
167 def url(self, name):
168 return webserver.where_is(name)
169
170 def load(self, name):
171 driver.get(self.url(name))
172 return Pages()
173
174
175@pytest.fixture(autouse=True, scope='session')
176def server(request):
177 drivers = request.config.getoption('drivers')
178 if drivers is None or 'Remote' not in drivers:
179 yield None
180 return
181
182 _host = 'localhost'
183 _port = 4444
184 _path = '../buck-out/gen/java/server/src/org/openqa/grid/selenium/selenium.jar'
185
186 def wait_for_server(url, timeout):
187 start = time.time()
188 while time.time() - start < timeout:
189 try:
190 urlopen(url)
191 return 1
192 except IOError:
193 time.sleep(0.2)
194 return 0
195
196 _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
197 url = 'http://{}:{}/wd/hub'.format(_host, _port)
198 try:
199 _socket.connect((_host, _port))
200 print('The remote driver server is already running or something else'
201 'is using port {}, continuing...'.format(_port))
202 except Exception:
203 print('Starting the Selenium server')
204 process = subprocess.Popen(['java', '-jar', _path])
205 print('Selenium server running as process: {}'.format(process.pid))
206 assert wait_for_server(url, 10), 'Timed out waiting for Selenium server at {}'.format(url)
207 print('Selenium server is ready')
208 yield process
209 process.terminate()
210 process.wait()
211 print('Selenium server has been terminated')
212
213
214@pytest.fixture(autouse=True, scope='session')
215def webserver():
216 webserver = SimpleWebServer(host=get_lan_ip())
217 webserver.start()
218 yield webserver
219 webserver.stop()