blob: 19d3f83e60bdfad3133d80350dd1c926915767f3 [file] [log] [blame]
import logging
import inspect
import subprocess
import sys
from unittest import mock
import pytest
from tools.wpt import browser
logger = logging.getLogger()
def test_all_browser_abc():
# Make sure all subclasses of Browser implement all abstract methods
# (except some known base classes). This is a basic sanity test in case
# we change the ABC interface of Browser as we only instantiate some
# products in unit tests.
classes = inspect.getmembers(browser)
for name, cls in classes:
if cls in (browser.Browser, browser.ChromeAndroidBase):
continue
if inspect.isclass(cls) and issubclass(cls, browser.Browser):
assert not inspect.isabstract(cls), "%s is abstract" % name
def test_edgechromium_webdriver_supports_browser():
# EdgeDriver binary cannot be called.
edge = browser.EdgeChromium(logger)
edge.webdriver_version = mock.MagicMock(return_value=None)
assert not edge.webdriver_supports_browser('/usr/bin/edgedriver', '/usr/bin/edge')
# Browser binary cannot be called.
edge = browser.EdgeChromium(logger)
edge.webdriver_version = mock.MagicMock(return_value='70.0.1')
edge.version = mock.MagicMock(return_value=None)
assert edge.webdriver_supports_browser('/usr/bin/edgedriver', '/usr/bin/edge')
# Browser version matches.
edge = browser.EdgeChromium(logger)
edge.webdriver_version = mock.MagicMock(return_value='70.0.1')
edge.version = mock.MagicMock(return_value='70.1.5')
assert edge.webdriver_supports_browser('/usr/bin/edgedriver', '/usr/bin/edge')
# Browser version doesn't match.
edge = browser.EdgeChromium(logger)
edge.webdriver_version = mock.MagicMock(return_value='70.0.1')
edge.version = mock.MagicMock(return_value='69.0.1')
assert not edge.webdriver_supports_browser('/usr/bin/edgedriver', '/usr/bin/edge')
# On Windows, webdriver_version directly calls _get_fileversion, so there is no
# logic to test there.
@pytest.mark.skipif(sys.platform.startswith('win'), reason='just uses _get_fileversion on Windows')
@mock.patch('tools.wpt.browser.call')
def test_edgechromium_webdriver_version(mocked_call):
edge = browser.EdgeChromium(logger)
webdriver_binary = '/usr/bin/edgedriver'
# Working cases.
mocked_call.return_value = 'MSEdgeDriver 84.0.4147.30'
assert edge.webdriver_version(webdriver_binary) == '84.0.4147.30'
mocked_call.return_value = 'MSEdgeDriver 87.0.1 (abcd1234-refs/branch-heads/4147@{#310})'
assert edge.webdriver_version(webdriver_binary) == '87.0.1'
# Various invalid version strings
mocked_call.return_value = 'Edge 84.0.4147.30 (dev)'
assert edge.webdriver_version(webdriver_binary) is None
mocked_call.return_value = 'MSEdgeDriver New 84.0.4147.30'
assert edge.webdriver_version(webdriver_binary) is None
mocked_call.return_value = ''
assert edge.webdriver_version(webdriver_binary) is None
# The underlying subprocess call throws.
mocked_call.side_effect = subprocess.CalledProcessError(5, 'cmd', output='Call failed')
assert edge.webdriver_version(webdriver_binary) is None
def test_chrome_webdriver_supports_browser():
# ChromeDriver binary cannot be called.
chrome = browser.Chrome(logger)
chrome.webdriver_version = mock.MagicMock(return_value=None)
assert not chrome.webdriver_supports_browser('/usr/bin/chromedriver', '/usr/bin/chrome', 'stable')
# Browser binary cannot be called.
chrome = browser.Chrome(logger)
chrome.webdriver_version = mock.MagicMock(return_value='70.0.1')
chrome.version = mock.MagicMock(return_value=None)
assert chrome.webdriver_supports_browser('/usr/bin/chromedriver', '/usr/bin/chrome', 'stable')
# Browser version matches.
chrome = browser.Chrome(logger)
chrome.webdriver_version = mock.MagicMock(return_value='70.0.1')
chrome.version = mock.MagicMock(return_value='70.1.5')
assert chrome.webdriver_supports_browser('/usr/bin/chromedriver', '/usr/bin/chrome', 'stable')
# Browser version doesn't match.
chrome = browser.Chrome(logger)
chrome.webdriver_version = mock.MagicMock(return_value='70.0.1')
chrome.version = mock.MagicMock(return_value='69.0.1')
assert not chrome.webdriver_supports_browser('/usr/bin/chromedriver', '/usr/bin/chrome', 'stable')
# The dev channel switches between beta and ToT ChromeDriver, so is sometimes
# a version behind its ChromeDriver. As such, we accept browser version + 1 there.
chrome = browser.Chrome(logger)
chrome.webdriver_version = mock.MagicMock(return_value='70.0.1')
chrome.version = mock.MagicMock(return_value='70.1.0')
assert chrome.webdriver_supports_browser('/usr/bin/chromedriver', '/usr/bin/chrome', 'dev')
chrome.webdriver_version = mock.MagicMock(return_value='71.0.1')
assert chrome.webdriver_supports_browser('/usr/bin/chromedriver', '/usr/bin/chrome', 'dev')
# On Windows, webdriver_version directly calls _get_fileversion, so there is no
# logic to test there.
@pytest.mark.skipif(sys.platform.startswith('win'), reason='just uses _get_fileversion on Windows')
@mock.patch('tools.wpt.browser.call')
def test_chrome_webdriver_version(mocked_call):
chrome = browser.Chrome(logger)
webdriver_binary = '/usr/bin/chromedriver'
# Working cases.
mocked_call.return_value = 'ChromeDriver 84.0.4147.30'
assert chrome.webdriver_version(webdriver_binary) == '84.0.4147.30'
mocked_call.return_value = 'ChromeDriver 87.0.1 (abcd1234-refs/branch-heads/4147@{#310})'
assert chrome.webdriver_version(webdriver_binary) == '87.0.1'
# Various invalid version strings
mocked_call.return_value = 'Chrome 84.0.4147.30 (dev)'
assert chrome.webdriver_version(webdriver_binary) is None
mocked_call.return_value = 'ChromeDriver New 84.0.4147.30'
assert chrome.webdriver_version(webdriver_binary) is None
mocked_call.return_value = ''
assert chrome.webdriver_version(webdriver_binary) is None
# The underlying subprocess call throws.
mocked_call.side_effect = subprocess.CalledProcessError(5, 'cmd', output='Call failed')
assert chrome.webdriver_version(webdriver_binary) is None
@mock.patch('subprocess.check_output')
def test_safari_version(mocked_check_output):
safari = browser.Safari(logger)
# Safari
mocked_check_output.return_value = b'Included with Safari 12.1 (14607.1.11)'
assert safari.version(webdriver_binary="safaridriver") == '12.1 (14607.1.11)'
# Safari Technology Preview
mocked_check_output.return_value = b'Included with Safari Technology Preview (Release 67, 13607.1.9.0.1)'
assert safari.version(webdriver_binary="safaridriver") == 'Technology Preview (Release 67, 13607.1.9.0.1)'
@mock.patch('subprocess.check_output')
def test_safari_version_errors(mocked_check_output):
safari = browser.Safari(logger)
# No webdriver_binary
assert safari.version() is None
# `safaridriver --version` return gibberish
mocked_check_output.return_value = b'gibberish'
assert safari.version(webdriver_binary="safaridriver") is None
# `safaridriver --version` fails (as it does for Safari <=12.0)
mocked_check_output.return_value = b'dummy'
mocked_check_output.side_effect = subprocess.CalledProcessError(1, 'cmd')
assert safari.version(webdriver_binary="safaridriver") is None
@mock.patch('subprocess.check_output')
def test_webkitgtk_minibrowser_version(mocked_check_output):
webkitgtk_minibrowser = browser.WebKitGTKMiniBrowser(logger)
# stable version
mocked_check_output.return_value = b'WebKitGTK 2.26.1\n'
assert webkitgtk_minibrowser.version(binary='MiniBrowser') == '2.26.1'
# nightly version
mocked_check_output.return_value = b'WebKitGTK 2.27.1 (r250823)\n'
assert webkitgtk_minibrowser.version(binary='MiniBrowser') == '2.27.1 (r250823)'
@mock.patch('subprocess.check_output')
def test_webkitgtk_minibrowser_version_errors(mocked_check_output):
webkitgtk_minibrowser = browser.WebKitGTKMiniBrowser(logger)
# No binary
assert webkitgtk_minibrowser.version() is None
# `MiniBrowser --version` return gibberish
mocked_check_output.return_value = b'gibberish'
assert webkitgtk_minibrowser.version(binary='MiniBrowser') is None
# `MiniBrowser --version` fails (as it does for MiniBrowser <= 2.26.0)
mocked_check_output.return_value = b'dummy'
mocked_check_output.side_effect = subprocess.CalledProcessError(1, 'cmd')
assert webkitgtk_minibrowser.version(binary='MiniBrowser') is None
# The test below doesn't work on Windows because distutils find_binary()
# on Windows only works if the binary name ends with a ".exe" suffix.
# But, WebKitGTK itself doesn't support Windows, so lets skip the test.
@pytest.mark.skipif(sys.platform.startswith('win'), reason='test not needed on Windows')
@mock.patch('os.path.isfile')
def test_webkitgtk_minibrowser_find_binary(mocked_os_path_isfile):
webkitgtk_minibrowser = browser.WebKitGTKMiniBrowser(logger)
# No MiniBrowser found
mocked_os_path_isfile.side_effect = lambda path: path == '/etc/passwd'
assert webkitgtk_minibrowser.find_binary() is None
# Found on the default Fedora path
fedora_minibrowser_path = '/usr/libexec/webkit2gtk-4.0/MiniBrowser'
mocked_os_path_isfile.side_effect = lambda path: path == fedora_minibrowser_path
assert webkitgtk_minibrowser.find_binary() == fedora_minibrowser_path
# Found on the default Debian path for AMD64 (gcc not available)
debian_minibrowser_path_amd64 = '/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/MiniBrowser'
mocked_os_path_isfile.side_effect = lambda path: path == debian_minibrowser_path_amd64
assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_amd64
# Found on the default Debian path for AMD64 (gcc available but gives an error)
debian_minibrowser_path_amd64 = '/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/MiniBrowser'
mocked_os_path_isfile.side_effect = lambda path: path in [debian_minibrowser_path_amd64, '/usr/bin/gcc']
with mock.patch('subprocess.check_output', return_value = b'error', side_effect = subprocess.CalledProcessError(1, 'cmd')):
assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_amd64
# Found on the default Debian path for ARM64 (gcc available)
debian_minibrowser_path_arm64 = '/usr/lib/aarch64-linux-gnu/webkit2gtk-4.0/MiniBrowser'
mocked_os_path_isfile.side_effect = lambda path: path in [debian_minibrowser_path_arm64, '/usr/bin/gcc']
with mock.patch('subprocess.check_output', return_value = b'aarch64-linux-gnu'):
assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_arm64