summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/wptrunner
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/tools/wptrunner')
-rw-r--r--testing/web-platform/tests/tools/wptrunner/docs/expectation.rst2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/requirements.txt10
-rw-r--r--testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt8
-rw-r--r--testing/web-platform/tests/tools/wptrunner/requirements_opera.txt2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/requirements_safari.txt2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/tox.ini2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py5
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/android_weblayer.py105
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py20
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edge.py (renamed from testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edgechromium.py)20
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py16
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py6
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py24
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executoredge.py24
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py15
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py21
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py14
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/testdriver-extra.js8
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py64
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py7
22 files changed, 204 insertions, 175 deletions
diff --git a/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst b/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst
index fea676565b..76f088dd8f 100644
--- a/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst
+++ b/testing/web-platform/tests/tools/wptrunner/docs/expectation.rst
@@ -153,7 +153,7 @@ When used for expectation data, metadata files have the following format:
:implementation-status:
One of the values ``implementing``,
- ``not-implementing`` or ``default``. This is used in conjunction
+ ``not-implementing`` or ``backlog``. This is used in conjunction
with the ``--skip-implementation-status`` command line argument to
``wptrunner`` to ignore certain features where running the test is
low value.
diff --git a/testing/web-platform/tests/tools/wptrunner/requirements.txt b/testing/web-platform/tests/tools/wptrunner/requirements.txt
index a7face3bd0..bb9b4ac77c 100644
--- a/testing/web-platform/tests/tools/wptrunner/requirements.txt
+++ b/testing/web-platform/tests/tools/wptrunner/requirements.txt
@@ -1,11 +1,11 @@
html5lib==1.1
-mozdebug==0.3.0
+mozdebug==0.3.1
mozinfo==1.2.3 # https://bugzilla.mozilla.org/show_bug.cgi?id=1621226
mozlog==8.0.0
mozprocess==1.3.1
-packaging==23.1
-pillow==9.5.0
+packaging==24.0
+pillow==10.3.0
requests==2.31.0
six==1.16.0
-urllib3==2.0.7
-aioquic==0.9.19
+urllib3==2.2.1
+aioquic==0.9.21
diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt b/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt
index 3ba4731494..ed377b9c95 100644
--- a/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt
+++ b/testing/web-platform/tests/tools/wptrunner/requirements_firefox.txt
@@ -1,10 +1,10 @@
marionette_driver==3.4.0
mozcrash==2.2.0
-mozdevice==4.1.1
+mozdevice==4.1.2
mozinstall==2.1.0
mozleak==0.2
-mozprofile==2.6.1
-mozrunner==8.3.0
+mozprofile==3.0.0
+mozrunner==8.3.1
mozversion==2.4.0
-psutil==5.9.5
+psutil==5.9.8
redo==2.0.4
diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_opera.txt b/testing/web-platform/tests/tools/wptrunner/requirements_opera.txt
index db0c5dd992..6c2425f337 100644
--- a/testing/web-platform/tests/tools/wptrunner/requirements_opera.txt
+++ b/testing/web-platform/tests/tools/wptrunner/requirements_opera.txt
@@ -1,2 +1,2 @@
mozprocess==1.3.1
-selenium==4.18.1
+selenium==4.20.0
diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_safari.txt b/testing/web-platform/tests/tools/wptrunner/requirements_safari.txt
index bcce11aed8..0704b2dbf6 100644
--- a/testing/web-platform/tests/tools/wptrunner/requirements_safari.txt
+++ b/testing/web-platform/tests/tools/wptrunner/requirements_safari.txt
@@ -1 +1 @@
-psutil==5.9.5
+psutil==5.9.8
diff --git a/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt b/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt
index c9e42346ce..806352e87e 100644
--- a/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt
+++ b/testing/web-platform/tests/tools/wptrunner/requirements_sauce.txt
@@ -1,2 +1,2 @@
-selenium==4.18.1
+selenium==4.20.0
requests==2.31.0
diff --git a/testing/web-platform/tests/tools/wptrunner/tox.ini b/testing/web-platform/tests/tools/wptrunner/tox.ini
index 82d3ac6f55..c380be1252 100644
--- a/testing/web-platform/tests/tools/wptrunner/tox.ini
+++ b/testing/web-platform/tests/tools/wptrunner/tox.ini
@@ -2,7 +2,7 @@
xfail_strict=true
[tox]
-envlist = py311-{base,chrome,firefox,opera,safari,sauce,servo,webkit,webkitgtk_minibrowser,epiphany},{py37,py38,py39,py310}-base
+envlist = py312-{base,chrome,firefox,opera,safari,sauce,servo,webkit,webkitgtk_minibrowser,epiphany},{py38,py39,py310,py311}-base
skip_missing_interpreters = False
[testenv]
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py
index 81dc549d73..d54a9be943 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/__init__.py
@@ -22,14 +22,13 @@ All classes and functions named in the above dict must be imported into the
module global scope.
"""
-product_list = ["android_weblayer",
- "android_webview",
+product_list = ["android_webview",
"chrome",
"chrome_android",
"chrome_ios",
"chromium",
"content_shell",
- "edgechromium",
+ "edge",
"firefox",
"firefox_android",
"safari",
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/android_weblayer.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/android_weblayer.py
deleted file mode 100644
index db23b64793..0000000000
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/android_weblayer.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# mypy: allow-untyped-defs
-
-from .base import NullBrowser # noqa: F401
-from .base import require_arg
-from .base import get_timeout_multiplier # noqa: F401
-from .chrome import executor_kwargs as chrome_executor_kwargs
-from .chrome_android import ChromeAndroidBrowserBase
-from ..executors.base import WdspecExecutor # noqa: F401
-from ..executors.executorchrome import ChromeDriverPrintRefTestExecutor # noqa: F401
-from ..executors.executorwebdriver import (WebDriverCrashtestExecutor, # noqa: F401
- WebDriverTestharnessExecutor, # noqa: F401
- WebDriverRefTestExecutor) # noqa: F401
-
-
-__wptrunner__ = {"product": "android_weblayer",
- "check_args": "check_args",
- "browser": {None: "WeblayerShell",
- "wdspec": "NullBrowser"},
- "executor": {"testharness": "WebDriverTestharnessExecutor",
- "reftest": "WebDriverRefTestExecutor",
- "print-reftest": "ChromeDriverPrintRefTestExecutor",
- "wdspec": "WdspecExecutor",
- "crashtest": "WebDriverCrashtestExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_extras": "env_extras",
- "env_options": "env_options",
- "timeout_multiplier": "get_timeout_multiplier"}
-
-_wptserve_ports = set()
-
-
-def check_args(**kwargs):
- require_arg(kwargs, "webdriver_binary")
-
-
-def browser_kwargs(logger, test_type, run_info_data, config, **kwargs):
- return {"binary": kwargs["binary"],
- "adb_binary": kwargs["adb_binary"],
- "device_serial": kwargs["device_serial"],
- "webdriver_binary": kwargs["webdriver_binary"],
- "webdriver_args": kwargs.get("webdriver_args"),
- "stackwalk_binary": kwargs.get("stackwalk_binary"),
- "symbols_path": kwargs.get("symbols_path")}
-
-
-def executor_kwargs(logger, test_type, test_environment, run_info_data,
- **kwargs):
- # Use update() to modify the global list in place.
- _wptserve_ports.update(set(
- test_environment.config['ports']['http'] + test_environment.config['ports']['https'] +
- test_environment.config['ports']['ws'] + test_environment.config['ports']['wss']
- ))
-
- executor_kwargs = chrome_executor_kwargs(logger, test_type, test_environment, run_info_data,
- **kwargs)
- del executor_kwargs["capabilities"]["goog:chromeOptions"]["prefs"]
- capabilities = executor_kwargs["capabilities"]
- # Note that for WebLayer, we launch a test shell and have the test shell use
- # WebLayer.
- # https://cs.chromium.org/chromium/src/weblayer/shell/android/shell_apk/
- capabilities["goog:chromeOptions"]["androidPackage"] = \
- "org.chromium.weblayer.shell"
- capabilities["goog:chromeOptions"]["androidActivity"] = ".WebLayerShellActivity"
- capabilities["goog:chromeOptions"]["androidKeepAppDataDir"] = \
- kwargs.get("keep_app_data_directory")
-
- # Workaround: driver.quit() cannot quit WeblayerShell.
- executor_kwargs["pause_after_test"] = False
- # Workaround: driver.close() is not supported.
- executor_kwargs["restart_after_test"] = True
- executor_kwargs["close_after_done"] = False
- return executor_kwargs
-
-
-def env_extras(**kwargs):
- return []
-
-
-def env_options():
- # allow the use of host-resolver-rules in lieu of modifying /etc/hosts file
- return {"server_host": "127.0.0.1"}
-
-
-class WeblayerShell(ChromeAndroidBrowserBase):
- """Chrome is backed by chromedriver, which is supplied through
- ``wptrunner.webdriver.ChromeDriverServer``.
- """
-
- def __init__(self, logger, binary,
- webdriver_binary="chromedriver",
- adb_binary=None,
- remote_queue=None,
- device_serial=None,
- webdriver_args=None,
- stackwalk_binary=None,
- symbols_path=None):
- """Creates a new representation of Chrome. The `binary` argument gives
- the browser binary to use for testing."""
- super().__init__(logger,
- webdriver_binary, adb_binary, remote_queue,
- device_serial, webdriver_args, stackwalk_binary,
- symbols_path)
- self.binary = binary
- self.wptserver_ports = _wptserve_ports
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py
index 8198bfe11d..c0a176743d 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py
@@ -53,13 +53,13 @@ def browser_kwargs(logger, test_type, run_info_data, config, **kwargs):
"webdriver_args": kwargs.get("webdriver_args")}
-def executor_kwargs(logger, test_type, test_environment, run_info_data,
+def executor_kwargs(logger, test_type, test_environment, run_info_data, subsuite,
**kwargs):
sanitizer_enabled = kwargs.get("sanitizer_enabled")
if sanitizer_enabled:
test_type = "crashtest"
executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data,
- **kwargs)
+ subsuite, **kwargs)
executor_kwargs["close_after_done"] = True
executor_kwargs["sanitizer_enabled"] = sanitizer_enabled
executor_kwargs["reuse_window"] = kwargs.get("reuse_window", False)
@@ -115,6 +115,10 @@ def executor_kwargs(logger, test_type, test_environment, run_info_data,
# The GenericSensorExtraClasses flag enables the browser-side
# implementation of sensors such as Ambient Light Sensor.
chrome_options["args"].append("--enable-features=GenericSensorExtraClasses")
+ # Do not show Chrome for Testing infobar. For other Chromium build this
+ # flag is no-op. Required to avoid flakiness in tests, as the infobar
+ # changes the viewport, which can happen during the test run.
+ chrome_options["args"].append("--disable-infobars")
# Classify `http-private`, `http-public` and https variants in the
# appropriate IP address spaces.
@@ -134,8 +138,14 @@ def executor_kwargs(logger, test_type, test_environment, run_info_data,
chrome_options["args"].append(
"--ip-address-space-overrides=" + address_space_overrides_arg)
+ # Always disable antialiasing on the Ahem font.
+ blink_features = ['DisableAhemAntialias']
+
if kwargs["enable_mojojs"]:
- chrome_options["args"].append("--enable-blink-features=MojoJS,MojoJSTest")
+ blink_features.append('MojoJS')
+ blink_features.append('MojoJSTest')
+
+ chrome_options["args"].append("--enable-blink-features=" + ','.join(blink_features))
if kwargs["enable_swiftshader"]:
# https://chromium.googlesource.com/chromium/src/+/HEAD/docs/gpu/swiftshader.md
@@ -149,6 +159,10 @@ def executor_kwargs(logger, test_type, test_environment, run_info_data,
if arg not in chrome_options["args"]:
chrome_options["args"].append(arg)
+ for arg in subsuite.config.get("binary_args", []):
+ if arg not in chrome_options["args"]:
+ chrome_options["args"].append(arg)
+
# Pass the --headless=new flag to Chrome if WPT's own --headless flag was
# set. '--headless' should always mean the new headless mode, as the old
# headless mode is not used anyway.
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edgechromium.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edge.py
index 4f5bffa06c..82597c9312 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edgechromium.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/edge.py
@@ -6,18 +6,18 @@ from .chrome import executor_kwargs as chrome_executor_kwargs
from ..executors.executorwebdriver import WebDriverCrashtestExecutor # noqa: F401
from ..executors.base import WdspecExecutor # noqa: F401
from ..executors.executoredge import ( # noqa: F401
- EdgeChromiumDriverPrintRefTestExecutor,
- EdgeChromiumDriverRefTestExecutor,
- EdgeChromiumDriverTestharnessExecutor,
+ EdgeDriverPrintRefTestExecutor,
+ EdgeDriverRefTestExecutor,
+ EdgeDriverTestharnessExecutor,
)
-__wptrunner__ = {"product": "edgechromium",
+__wptrunner__ = {"product": "edge",
"check_args": "check_args",
- "browser": "EdgeChromiumBrowser",
- "executor": {"testharness": "EdgeChromiumDriverTestharnessExecutor",
- "reftest": "EdgeChromiumDriverRefTestExecutor",
- "print-reftest": "EdgeChromiumDriverPrintRefTestExecutor",
+ "browser": "EdgeBrowser",
+ "executor": {"testharness": "EdgeDriverTestharnessExecutor",
+ "reftest": "EdgeDriverRefTestExecutor",
+ "print-reftest": "EdgeDriverPrintRefTestExecutor",
"wdspec": "WdspecExecutor",
"crashtest": "WebDriverCrashtestExecutor"},
"browser_kwargs": "browser_kwargs",
@@ -58,9 +58,9 @@ def update_properties():
return (["debug", "os", "processor"], {"os": ["version"], "processor": ["bits"]})
-class EdgeChromiumBrowser(WebDriverBrowser):
+class EdgeBrowser(WebDriverBrowser):
"""MicrosoftEdge is backed by MSEdgeDriver, which is supplied through
- ``wptrunner.webdriver.EdgeChromiumDriverServer``.
+ ``wptrunner.webdriver.EdgeDriverServer``.
"""
def make_command(self):
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
index 814b8b8d75..d977930a28 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -132,6 +132,7 @@ def browser_kwargs(logger, test_type, run_info_data, config, subsuite, **kwargs)
"headless": kwargs["headless"],
"preload_browser": kwargs["preload_browser"] and not kwargs["pause_after_test"] and not kwargs["num_test_groups"] == 1,
"specialpowers_path": kwargs["specialpowers_path"],
+ "allow_list_paths": kwargs["allow_list_paths"],
"debug_test": kwargs["debug_test"]}
if test_type == "wdspec" and kwargs["binary"]:
browser_kwargs["webdriver_args"].extend(["--binary", kwargs["binary"]])
@@ -644,7 +645,8 @@ class GeckodriverOutputHandler(FirefoxOutputHandler):
class ProfileCreator:
def __init__(self, logger, prefs_root, config, test_type, extra_prefs,
disable_fission, debug_test, browser_channel, binary,
- package_name, certutil_binary, ca_certificate_path):
+ package_name, certutil_binary, ca_certificate_path,
+ allow_list_paths):
self.logger = logger
self.prefs_root = prefs_root
self.config = config
@@ -658,6 +660,7 @@ class ProfileCreator:
self.package_name = package_name
self.certutil_binary = certutil_binary
self.ca_certificate_path = ca_certificate_path
+ self.allow_list_paths = allow_list_paths
def create(self, **kwargs):
"""Create a Firefox profile and return the mozprofile Profile object pointing at that
@@ -669,6 +672,7 @@ class ProfileCreator:
profile = FirefoxProfile(preferences=preferences,
restore=False,
+ allowlistpaths=self.allow_list_paths,
**kwargs)
self._set_required_prefs(profile)
if self.ca_certificate_path is not None:
@@ -795,7 +799,7 @@ class FirefoxBrowser(Browser):
stackfix_dir=None, binary_args=None, timeout_multiplier=None, leak_check=False,
asan=False, chaos_mode_flags=None, config=None,
browser_channel="nightly", headless=None, preload_browser=False,
- specialpowers_path=None, debug_test=False, **kwargs):
+ specialpowers_path=None, debug_test=False, allow_list_paths=None, **kwargs):
Browser.__init__(self, logger)
self.logger = logger
@@ -826,7 +830,8 @@ class FirefoxBrowser(Browser):
binary,
package_name,
certutil_binary,
- ca_certificate_path)
+ ca_certificate_path,
+ allow_list_paths)
if preload_browser:
instance_manager_cls = PreloadInstanceManager
@@ -899,7 +904,7 @@ class FirefoxWdSpecBrowser(WebDriverBrowser):
disable_fission=False, stackfix_dir=None, leak_check=False,
asan=False, chaos_mode_flags=None, config=None, browser_channel="nightly",
headless=None, debug_test=False, profile_creator_cls=ProfileCreator,
- **kwargs):
+ allow_list_paths=None, **kwargs):
super().__init__(logger, binary, webdriver_binary, webdriver_args)
self.binary = binary
@@ -927,7 +932,8 @@ class FirefoxWdSpecBrowser(WebDriverBrowser):
binary,
package_name,
certutil_binary,
- ca_certificate_path)
+ ca_certificate_path,
+ allow_list_paths)
self.profile = profile_creator.create()
self.marionette_port = None
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py
index 7c158902e1..526f83d595 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py
@@ -148,11 +148,13 @@ def get_environ(chaos_mode_flags, env_extras=None):
class ProfileCreator(FirefoxProfileCreator):
def __init__(self, logger, prefs_root, config, test_type, extra_prefs,
disable_fission, debug_test, browser_channel, binary,
- package_name, certutil_binary, ca_certificate_path):
+ package_name, certutil_binary, ca_certificate_path,
+ allow_list_paths=None):
super().__init__(logger, prefs_root, config, test_type, extra_prefs,
disable_fission, debug_test, browser_channel, None,
- package_name, certutil_binary, ca_certificate_path)
+ package_name, certutil_binary, ca_certificate_path,
+ allow_list_paths)
def _set_required_prefs(self, profile):
profile.set_preferences({
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py
index cb9c1a1508..6e0c081b48 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py
@@ -443,6 +443,26 @@ class GetVirtualSensorInformationAction:
self.logger.debug("Requesting information from %s sensor" % sensor_type)
return self.protocol.virtual_sensor.get_virtual_sensor_information(sensor_type)
+class SetDevicePostureAction:
+ name = "set_device_posture"
+
+ def __init__(self, logger, protocol):
+ self.logger = logger
+ self.protocol = protocol
+
+ def __call__(self, payload):
+ posture = payload["posture"]
+ return self.protocol.device_posture.set_device_posture(posture)
+
+class ClearDevicePostureAction:
+ name = "clear_device_posture"
+
+ def __init__(self, logger, protocol):
+ self.logger = logger
+ self.protocol = protocol
+
+ def __call__(self, payload):
+ return self.protocol.device_posture.clear_device_posture()
actions = [ClickAction,
DeleteAllCookiesAction,
@@ -477,4 +497,6 @@ actions = [ClickAction,
CreateVirtualSensorAction,
UpdateVirtualSensorAction,
RemoveVirtualSensorAction,
- GetVirtualSensorInformationAction]
+ GetVirtualSensorInformationAction,
+ SetDevicePostureAction,
+ ClearDevicePostureAction]
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py
index 763b6fcb19..92a782e835 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py
@@ -313,7 +313,7 @@ class TestExecutor:
result = self.do_test(test)
except Exception as e:
exception_string = traceback.format_exc()
- message = f"Exception in TextExecutor.run:\n{exception_string}"
+ message = f"Exception in TestExecutor.run:\n{exception_string}"
self.logger.warning(message)
result = self.result_from_exception(test, e, exception_string)
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executoredge.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executoredge.py
index cbe5eadf9a..3b62cb7477 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executoredge.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executoredge.py
@@ -20,42 +20,42 @@ here = os.path.dirname(__file__)
_SanitizerMixin = make_sanitizer_mixin(WebDriverCrashtestExecutor)
-class EdgeChromiumDriverTestharnessProtocolPart(ChromeDriverTestharnessProtocolPart):
+class EdgeDriverTestharnessProtocolPart(ChromeDriverTestharnessProtocolPart):
def setup(self):
super().setup()
self.cdp_company_prefix = "ms"
-class EdgeChromiumDriverPrintProtocolPart(ChromeDriverPrintProtocolPart):
+class EdgeDriverPrintProtocolPart(ChromeDriverPrintProtocolPart):
def setup(self):
super().setup()
self.cdp_company_prefix = "ms"
-class EdgeChromiumDriverProtocol(WebDriverProtocol):
+class EdgeDriverProtocol(WebDriverProtocol):
implements = [
- EdgeChromiumDriverPrintProtocolPart,
- EdgeChromiumDriverTestharnessProtocolPart,
+ EdgeDriverPrintProtocolPart,
+ EdgeDriverTestharnessProtocolPart,
*(part for part in WebDriverProtocol.implements
- if part.name != EdgeChromiumDriverTestharnessProtocolPart.name)
+ if part.name != EdgeDriverTestharnessProtocolPart.name)
]
reuse_window = False
-class EdgeChromiumDriverRefTestExecutor(WebDriverRefTestExecutor, _SanitizerMixin): # type: ignore
- protocol_cls = EdgeChromiumDriverProtocol
+class EdgeDriverRefTestExecutor(WebDriverRefTestExecutor, _SanitizerMixin): # type: ignore
+ protocol_cls = EdgeDriverProtocol
-class EdgeChromiumDriverTestharnessExecutor(WebDriverTestharnessExecutor, _SanitizerMixin): # type: ignore
- protocol_cls = EdgeChromiumDriverProtocol
+class EdgeDriverTestharnessExecutor(WebDriverTestharnessExecutor, _SanitizerMixin): # type: ignore
+ protocol_cls = EdgeDriverProtocol
def __init__(self, *args, reuse_window=False, **kwargs):
super().__init__(*args, **kwargs)
self.protocol.reuse_window = reuse_window
-class EdgeChromiumDriverPrintRefTestExecutor(EdgeChromiumDriverRefTestExecutor):
- protocol_cls = EdgeChromiumDriverProtocol
+class EdgeDriverPrintRefTestExecutor(EdgeDriverRefTestExecutor):
+ protocol_cls = EdgeDriverProtocol
def setup(self, runner):
super().setup(runner)
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py
index 0f640d7741..05a9fc1ae4 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -45,6 +45,7 @@ from .protocol import (AccessibilityProtocolPart,
PrintProtocolPart,
DebugProtocolPart,
VirtualSensorProtocolPart,
+ DevicePostureProtocolPart,
merge_dicts)
@@ -749,6 +750,17 @@ class MarionetteVirtualSensorProtocolPart(VirtualSensorProtocolPart):
raise NotImplementedError("get_virtual_sensor_information not yet implemented")
+class MarionetteDevicePostureProtocolPart(DevicePostureProtocolPart):
+ def setup(self):
+ self.marionette = self.parent.marionette
+
+ def set_device_posture(self, posture):
+ raise NotImplementedError("set_device_posture not yet implemented")
+
+ def clear_device_posture(self):
+ raise NotImplementedError("clear_device_posture not yet implemented")
+
+
class MarionetteProtocol(Protocol):
implements = [MarionetteBaseProtocolPart,
MarionetteTestharnessProtocolPart,
@@ -769,7 +781,8 @@ class MarionetteProtocol(Protocol):
MarionettePrintProtocolPart,
MarionetteDebugProtocolPart,
MarionetteAccessibilityProtocolPart,
- MarionetteVirtualSensorProtocolPart]
+ MarionetteVirtualSensorProtocolPart,
+ MarionetteDevicePostureProtocolPart]
def __init__(self, executor, browser, capabilities=None, timeout_multiplier=1, e10s=True, ccov=False):
do_delayed_imports()
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py
index 6df2d96461..69013e5e79 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -35,6 +35,7 @@ from .protocol import (BaseProtocolPart,
RPHRegistrationsProtocolPart,
FedCMProtocolPart,
VirtualSensorProtocolPart,
+ DevicePostureProtocolPart,
merge_dicts)
from webdriver.client import Session
@@ -431,6 +432,16 @@ class WebDriverVirtualSensorPart(VirtualSensorProtocolPart):
def get_virtual_sensor_information(self, sensor_type):
return self.webdriver.send_session_command("GET", "sensor/%s" % sensor_type)
+class WebDriverDevicePostureProtocolPart(DevicePostureProtocolPart):
+ def setup(self):
+ self.webdriver = self.parent.webdriver
+
+ def set_device_posture(self, posture):
+ body = {"posture": posture}
+ return self.webdriver.send_session_command("POST", "deviceposture", body)
+
+ def clear_device_posture(self):
+ return self.webdriver.send_session_command("DELETE", "deviceposture")
class WebDriverProtocol(Protocol):
implements = [WebDriverBaseProtocolPart,
@@ -450,7 +461,8 @@ class WebDriverProtocol(Protocol):
WebDriverRPHRegistrationsProtocolPart,
WebDriverFedCMProtocolPart,
WebDriverDebugProtocolPart,
- WebDriverVirtualSensorPart]
+ WebDriverVirtualSensorPart,
+ WebDriverDevicePostureProtocolPart]
def __init__(self, executor, browser, capabilities, **kwargs):
super().__init__(executor, browser)
@@ -527,7 +539,9 @@ class WebDriverRun(TimedRunner):
self.result = True, self.func(self.protocol, self.url, self.timeout)
except (error.TimeoutException, error.ScriptTimeoutException):
self.result = False, ("EXTERNAL-TIMEOUT", None)
- except (socket.timeout, error.UnknownErrorException):
+ except socket.timeout:
+ # Checking if the browser is alive below is likely to hang, so mark
+ # this case as a CRASH unconditionally.
self.result = False, ("CRASH", None)
except Exception as e:
if (isinstance(e, error.WebDriverException) and
@@ -536,11 +550,12 @@ class WebDriverRun(TimedRunner):
# workaround for https://bugs.chromium.org/p/chromedriver/issues/detail?id=2001
self.result = False, ("EXTERNAL-TIMEOUT", None)
else:
+ status = "INTERNAL-ERROR" if self.protocol.is_alive() else "CRASH"
message = str(getattr(e, "message", ""))
if message:
message += "\n"
message += traceback.format_exc()
- self.result = False, ("INTERNAL-ERROR", message)
+ self.result = False, (status, message)
finally:
self.result_flag.set()
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py
index e44d1a7666..3d588738b6 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py
@@ -802,3 +802,17 @@ class VirtualSensorProtocolPart(ProtocolPart):
@abstractmethod
def get_virtual_sensor_information(self, sensor_type):
pass
+
+class DevicePostureProtocolPart(ProtocolPart):
+ """Protocol part for Device Posture"""
+ __metaclass__ = ABCMeta
+
+ name = "device_posture"
+
+ @abstractmethod
+ def set_device_posture(self, posture):
+ pass
+
+ @abstractmethod
+ def clear_device_posture(self):
+ pass
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testdriver-extra.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/testdriver-extra.js
index af25bf4111..87d3826bfc 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testdriver-extra.js
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testdriver-extra.js
@@ -327,4 +327,12 @@
window.test_driver_internal.get_virtual_sensor_information = function(sensor_type, context=null) {
return create_action("get_virtual_sensor_information", {sensor_type, context});
};
+
+ window.test_driver_internal.set_device_posture = function(posture, context=null) {
+ return create_action("set_device_posture", {posture, context});
+ };
+
+ window.test_driver_internal.clear_device_posture = function(context=null) {
+ return create_action("clear_device_posture", {context});
+ };
})();
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
index 70da22f5b7..93e19fa47b 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
@@ -1,7 +1,6 @@
# mypy: allow-untyped-defs
import threading
-import time
import traceback
from queue import Empty
from collections import namedtuple, defaultdict
@@ -31,6 +30,30 @@ TestImplementation = namedtuple('TestImplementation',
'browser_cls', 'browser_kwargs'])
+class StopFlag:
+ """Synchronization for coordinating a graceful exit."""
+
+ def __init__(self, size: int):
+ # Flag that is polled by threads so that they can gracefully exit in the
+ # face of SIGINT.
+ self._should_stop = threading.Event()
+ # A barrier that each `TestRunnerManager` thread waits on when exiting
+ # its run loop. This provides a reliable way for the `ManagerGroup` to
+ # tell when all threads have cleaned up their resources.
+ #
+ # The barrier's extra waiter is the main thread (`ManagerGroup`).
+ self._all_managers_done = threading.Barrier(1 + size)
+
+ def stop(self) -> None:
+ self._should_stop.set()
+
+ def should_stop(self) -> bool:
+ return self._should_stop.is_set()
+
+ def wait_for_all_managers_done(self, timeout: Optional[float] = None) -> None:
+ self._all_managers_done.wait(timeout)
+
+
class LogMessageHandler:
def __init__(self, send_message):
self.send_message = send_message
@@ -443,7 +466,8 @@ class TestRunnerManager(threading.Thread):
if self.browser is not None:
assert self.browser.browser is not None
self.browser.browser.cleanup()
- self.logger.debug("TestRunnerManager main loop terminated")
+ self.logger.debug("TestRunnerManager main loop terminated")
+ self.parent_stop_flag.wait_for_all_managers_done()
def wait_event(self):
dispatch = {
@@ -517,7 +541,7 @@ class TestRunnerManager(threading.Thread):
return f(*data)
def should_stop(self):
- return self.child_stop_flag.is_set() or self.parent_stop_flag.is_set()
+ return self.child_stop_flag.is_set() or self.parent_stop_flag.should_stop()
def start_init(self):
subsuite, test_type, test, test_group, group_metadata = self.get_next_test()
@@ -977,9 +1001,7 @@ class ManagerGroup:
self.max_restarts = max_restarts
self.pool = set()
- # Event that is polled by threads so that they can gracefully exit in the face
- # of sigint
- self.stop_flag = threading.Event()
+ self.stop_flag = None
self.logger = structuredlog.StructuredLogger(suite_name)
def __enter__(self):
@@ -992,6 +1014,7 @@ class ManagerGroup:
"""Start all managers in the group"""
test_queue, size = self.test_queue_builder.make_queue(tests)
self.logger.info("Using %i child processes" % size)
+ self.stop_flag = StopFlag(size)
for idx in range(size):
manager = TestRunnerManager(self.suite_name,
@@ -1020,18 +1043,31 @@ class ManagerGroup:
timeout: Overall timeout (in seconds) for all threads to join. The
default value indicates an indefinite timeout.
"""
- deadline = None if timeout is None else time.time() + timeout
- for manager in self.pool:
- manager_timeout = None
- if deadline is not None:
- manager_timeout = max(0, deadline - time.time())
- manager.join(manager_timeout)
+ # Here, the main thread cannot simply `join()` the threads in
+ # `self.pool` sequentially because a keyboard interrupt raised during a
+ # `Thread.join()` may incorrectly mark that thread as "stopped" when it
+ # is not [0, 1]. Subsequent `join()`s for the affected thread won't
+ # block anymore, so a subsequent `ManagerGroup.wait()` may return with
+ # that thread still alive.
+ #
+ # To the extent the timeout allows, it's important that
+ # `ManagerGroup.wait()` returns with all `TestRunnerManager` threads
+ # actually stopped. Otherwise, a live thread may log after `mozlog`
+ # shutdown (not allowed) or worse, leak browser processes that the
+ # thread should have stopped when exiting its run loop [2].
+ #
+ # [0]: https://github.com/python/cpython/issues/90882
+ # [1]: https://github.com/python/cpython/blob/558b517b/Lib/threading.py#L1146-L1178
+ # [2]: https://crbug.com/330236796
+ assert self.stop_flag, "ManagerGroup hasn't been started yet"
+ self.stop_flag.wait_for_all_managers_done(timeout)
def stop(self):
"""Set the stop flag so that all managers in the group stop as soon
as possible"""
- self.stop_flag.set()
- self.logger.debug("Stop flag set in ManagerGroup")
+ if self.stop_flag:
+ self.stop_flag.stop()
+ self.logger.debug("Stop flag set in ManagerGroup")
def test_count(self):
return sum(manager.test_count for manager in self.pool)
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py
index d65369b380..d9d85de6a4 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py
@@ -396,11 +396,16 @@ def run_tests(config, product, test_paths, **kwargs):
product.check_args(**kwargs)
+ kwargs["allow_list_paths"] = []
if kwargs["install_fonts"]:
+ # Add test font to allow list for sandbox to ensure that the content
+ # processes will have read access.
+ ahem_path = os.path.join(test_paths["/"].tests_path, "fonts/Ahem.ttf")
+ kwargs["allow_list_paths"].append(ahem_path)
env_extras.append(FontInstaller(
logger,
font_dir=kwargs["font_dir"],
- ahem=os.path.join(test_paths["/"].tests_path, "fonts/Ahem.ttf")
+ ahem=ahem_path
))
recording.set(["startup", "load_tests"])