summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/tools')
-rw-r--r--testing/web-platform/tests/tools/web_features/manifest.py2
-rw-r--r--testing/web-platform/tests/tools/web_features/tests/test_manifest.py3
-rw-r--r--testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/permissions.py6
-rw-r--r--testing/web-platform/tests/tools/wpt/browser.py18
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py157
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py3
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome_ios.py8
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py1
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py1
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py1
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py1
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/wktr.py1
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py43
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py2
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js7
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py5
-rw-r--r--testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py2
-rw-r--r--testing/web-platform/tests/tools/wptserve/wptserve/constants.py1
-rw-r--r--testing/web-platform/tests/tools/wptserve/wptserve/utils.py2
19 files changed, 161 insertions, 103 deletions
diff --git a/testing/web-platform/tests/tools/web_features/manifest.py b/testing/web-platform/tests/tools/web_features/manifest.py
index 0f442fe7f6..15ec5362b4 100644
--- a/testing/web-platform/tests/tools/web_features/manifest.py
+++ b/testing/web-platform/tests/tools/web_features/manifest.py
@@ -187,7 +187,7 @@ def write_manifest_file(path: str, web_features_map: WebFeaturesMap) -> None:
{
"version": 1,
"data": web_features_map
- }, cls=WebFeatureManifestEncoder))
+ }, cls=WebFeatureManifestEncoder, sort_keys=True))
def main(venv: Any = None, **kwargs: Any) -> int:
diff --git a/testing/web-platform/tests/tools/web_features/tests/test_manifest.py b/testing/web-platform/tests/tools/web_features/tests/test_manifest.py
index 8b656876ff..b83829308a 100644
--- a/testing/web-platform/tests/tools/web_features/tests/test_manifest.py
+++ b/testing/web-platform/tests/tools/web_features/tests/test_manifest.py
@@ -202,8 +202,7 @@ def test_valid_schema():
write_manifest_file("test_file.json", web_features_map)
mock_file.assert_called_once_with("test_file.json", "w")
mock_file.return_value.write.assert_called_once_with(
- ('{"version": 1,'
- ' "data": {"grid": ["/grid_test1.js", "/grid_test2.js"], "avif": ["/avif_test1.js"]}}'))
+ '{"data": {"avif": ["/avif_test1.js"], "grid": ["/grid_test1.js", "/grid_test2.js"]}, "version": 1}')
args = mock_file.return_value.write.call_args
file_dict = json.loads(args[0][0])
# Should not throw an exception
diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/permissions.py b/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/permissions.py
index 3062260b34..a081e060e9 100644
--- a/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/permissions.py
+++ b/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/permissions.py
@@ -9,10 +9,12 @@ class Permissions(BidiModule):
def set_permission(self,
descriptor: Union[Optional[Mapping[str, Any]], Undefined] = UNDEFINED,
state: Union[Optional[str], Undefined] = UNDEFINED,
- origin: Union[Optional[str], Undefined] = UNDEFINED) -> Mapping[str, Any]:
+ origin: Union[Optional[str], Undefined] = UNDEFINED,
+ user_context: Union[Optional[str], Undefined] = UNDEFINED) -> Mapping[str, Any]:
params: MutableMapping[str, Any] = {
"descriptor": descriptor,
"state": state,
- "origin": origin
+ "origin": origin,
+ "userContext": user_context,
}
return params
diff --git a/testing/web-platform/tests/tools/wpt/browser.py b/testing/web-platform/tests/tools/wpt/browser.py
index 2f9c453131..ea71499ec4 100644
--- a/testing/web-platform/tests/tools/wpt/browser.py
+++ b/testing/web-platform/tests/tools/wpt/browser.py
@@ -1559,7 +1559,23 @@ class ChromeiOS(Browser):
raise NotImplementedError
def version(self, binary=None, webdriver_binary=None):
- return None
+ if webdriver_binary is None:
+ self.logger.warning(
+ "Cannot find ChromeiOS version without CWTChromeDriver")
+ return None
+ # Use `chrome iOS driver --version` to get the version. Example output:
+ # "125.0.6378.0"
+ try:
+ version_string = call(webdriver_binary, "--version").strip()
+ except subprocess.CalledProcessError as e:
+ self.logger.warning(f"Failed to call {webdriver_binary}: {e}")
+ return None
+ m = re.match(r"[\d][\d\.]*", version_string)
+ if not m:
+ self.logger.warning(
+ f"Failed to extract version from: {version_string}")
+ return None
+ return m.group(0)
class Opera(Browser):
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py
index 180e3fb959..6b1465cde8 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py
@@ -1,5 +1,3 @@
-# mypy: allow-untyped-defs
-
import enum
import errno
import os
@@ -8,16 +6,21 @@ import socket
import time
import traceback
from abc import ABCMeta, abstractmethod
+from typing import cast, Any, List, Mapping, Optional, Tuple, Type
import mozprocess
+from mozdebug import DebuggerInfo
+from mozlog.structuredlog import StructuredLogger
from ..environment import wait_for_service
+from ..testloader import GroupMetadata
from ..wptcommandline import require_arg # noqa: F401
+from ..wpttest import Test
here = os.path.dirname(__file__)
-def cmd_arg(name, value=None):
+def cmd_arg(name: str, value: Optional[str] = None) -> str:
prefix = "-" if platform.system() == "Windows" else "--"
rv = prefix + name
if value is not None:
@@ -25,7 +28,7 @@ def cmd_arg(name, value=None):
return rv
-def maybe_add_args(required_args, current_args):
+def maybe_add_args(required_args: List[str], current_args: List[str]) -> List[str]:
for required_arg in required_args:
# If the arg is in the form of "variable=value", only add it if
# no arg with another value for "variable" is already there.
@@ -39,15 +42,16 @@ def maybe_add_args(required_args, current_args):
return current_args
-def certificate_domain_list(list_of_domains, certificate_file):
+def certificate_domain_list(list_of_domains: List[str],
+ certificate_file: str) -> List[Mapping[str, Any]]:
"""Build a list of domains where certificate_file should be used"""
- cert_list = []
+ cert_list: List[Mapping[str, Any]] = []
for domain in list_of_domains:
cert_list.append({"host": domain, "certificateFile": certificate_file})
return cert_list
-def get_free_port():
+def get_free_port() -> int:
"""Get a random unbound port"""
while True:
s = socket.socket()
@@ -56,27 +60,27 @@ def get_free_port():
except OSError:
continue
else:
- return s.getsockname()[1]
+ return cast(int, s.getsockname()[1])
finally:
s.close()
-def get_timeout_multiplier(test_type, run_info_data, **kwargs):
+def get_timeout_multiplier(test_type: str, run_info_data: Mapping[str, Any], **kwargs: Any) -> float:
if kwargs["timeout_multiplier"] is not None:
- return kwargs["timeout_multiplier"]
+ return cast(float, kwargs["timeout_multiplier"])
return 1
-def browser_command(binary, args, debug_info):
+def browser_command(binary: str,
+ args: List[str],
+ debug_info: DebuggerInfo) -> Tuple[List[str], List[str]]:
if debug_info:
if debug_info.requiresEscapedArgs:
args = [item.replace("&", "\\&") for item in args]
debug_args = [debug_info.path] + debug_info.args
else:
debug_args = []
-
command = [binary] + args
-
return debug_args, command
@@ -84,6 +88,9 @@ class BrowserError(Exception):
pass
+BrowserSettings = Mapping[str, Any]
+
+
class Browser:
"""Abstract class serving as the basis for Browser implementations.
@@ -94,17 +101,16 @@ class Browser:
"""
__metaclass__ = ABCMeta
- process_cls = None
- init_timeout = 30
+ init_timeout: float = 30
- def __init__(self, logger):
+ def __init__(self, logger: StructuredLogger):
self.logger = logger
- def setup(self):
+ def setup(self) -> None:
"""Used for browser-specific setup that happens at the start of a test run"""
pass
- def settings(self, test):
+ def settings(self, test: Test) -> BrowserSettings:
"""Dictionary of metadata that is constant for a specific launch of a browser.
This is used to determine when the browser instance configuration changes, requiring
@@ -114,64 +120,66 @@ class Browser:
return {}
@abstractmethod
- def start(self, group_metadata, **kwargs):
+ def start(self, group_metadata: GroupMetadata, **kwargs: Any) -> None:
"""Launch the browser object and get it into a state where is is ready to run tests"""
pass
@abstractmethod
- def stop(self, force=False):
- """Stop the running browser process."""
+ def stop(self, force: bool = False) -> bool:
+ """Stop the running browser process.
+
+ Return True iff the browser was successfully stopped.
+ """
pass
+ @property
@abstractmethod
- def pid(self):
+ def pid(self) -> Optional[int]:
"""pid of the browser process or None if there is no pid"""
pass
@abstractmethod
- def is_alive(self):
+ def is_alive(self) -> bool:
"""Boolean indicating whether the browser process is still running"""
pass
- def cleanup(self):
+ def cleanup(self) -> None:
"""Browser-specific cleanup that is run after the testrun is finished"""
pass
- def executor_browser(self):
+ def executor_browser(self) -> Tuple[Type['ExecutorBrowser'], Mapping[str, Any]]:
"""Returns the ExecutorBrowser subclass for this Browser subclass and the keyword arguments
with which it should be instantiated"""
return ExecutorBrowser, {}
- def maybe_parse_tombstone(self):
- """Possibly parse tombstones on Android device for Android target"""
- pass
-
- def check_crash(self, process, test):
+ def check_crash(self, process: int, test: str) -> bool:
"""Check if a crash occured and output any useful information to the
log. Returns a boolean indicating whether a crash occured."""
return False
@property
- def pac(self):
+ def pac(self) -> Optional[str]:
return None
+
class NullBrowser(Browser):
- def __init__(self, logger, **kwargs):
+ def __init__(self, logger: StructuredLogger, **kwargs: Any):
super().__init__(logger)
- def start(self, **kwargs):
+ def start(self, group_metadata: GroupMetadata, **kwargs: Any) -> None:
"""No-op browser to use in scenarios where the TestRunnerManager shouldn't
actually own the browser process (e.g. Servo where we start one browser
per test)"""
pass
- def stop(self, force=False):
- pass
+ def stop(self, force: bool = False) -> bool:
+ return True
- def pid(self):
+ @property
+ def pid(self) -> Optional[int]:
return None
- def is_alive(self):
+ def is_alive(self) -> bool:
return True
@@ -184,7 +192,7 @@ class ExecutorBrowser:
but in some cases it may have more elaborate methods for setting
up the browser from the runner process.
"""
- def __init__(self, **kwargs):
+ def __init__(self, **kwargs: Any):
for k, v in kwargs.items():
setattr(self, k, v)
@@ -233,20 +241,20 @@ class OutputHandler:
but sometimes use a wrapper e.g. mozrunner.
"""
- def __init__(self, logger, command, **kwargs):
+ def __init__(self, logger: StructuredLogger, command: List[str], **kwargs: Any):
self.logger = logger
self.command = command
- self.pid = None
+ self.pid: Optional[int] = None
self.state = OutputHandlerState.BEFORE_PROCESS_START
- self.line_buffer = []
+ self.line_buffer: List[bytes] = []
- def after_process_start(self, pid):
+ def after_process_start(self, pid: int) -> None:
assert self.state == OutputHandlerState.BEFORE_PROCESS_START
self.logger.debug("OutputHandler.after_process_start")
self.pid = pid
self.state = OutputHandlerState.AFTER_PROCESS_START
- def start(self, **kwargs):
+ def start(self, **kwargs: Any) -> None:
assert self.state == OutputHandlerState.AFTER_PROCESS_START
self.logger.debug("OutputHandler.start")
# Need to change the state here before we try to empty the buffer
@@ -254,9 +262,9 @@ class OutputHandler:
self.state = OutputHandlerState.AFTER_HANDLER_START
for item in self.line_buffer:
self(item)
- self.line_buffer = None
+ self.line_buffer.clear()
- def after_process_stop(self, clean_shutdown=True):
+ def after_process_stop(self, clean_shutdown: bool = True) -> None:
# If we didn't get as far as configure, just
# dump all logs with no configuration
self.logger.debug("OutputHandler.after_process_stop")
@@ -264,7 +272,7 @@ class OutputHandler:
self.start()
self.state = OutputHandlerState.AFTER_PROCESS_STOP
- def __call__(self, line):
+ def __call__(self, line: bytes) -> None:
if self.state < OutputHandlerState.AFTER_HANDLER_START:
self.line_buffer.append(line)
return
@@ -282,9 +290,17 @@ class OutputHandler:
class WebDriverBrowser(Browser):
__metaclass__ = ABCMeta
- def __init__(self, logger, binary=None, webdriver_binary=None,
- webdriver_args=None, host="127.0.0.1", port=None, base_path="/",
- env=None, supports_pac=True, **kwargs):
+ def __init__(self,
+ logger: StructuredLogger,
+ binary: Optional[str] = None,
+ webdriver_binary: Optional[str] = None,
+ webdriver_args: Optional[List[str]] = None,
+ host: str = "127.0.0.1",
+ port: Optional[int] = None,
+ base_path: str = "/",
+ env: Optional[Mapping[str, str]] = None,
+ supports_pac: bool = True,
+ **kwargs: Any):
super().__init__(logger)
if webdriver_binary is None:
@@ -303,17 +319,17 @@ class WebDriverBrowser(Browser):
self.env = os.environ.copy() if env is None else env
self.webdriver_args = webdriver_args if webdriver_args is not None else []
- self.init_deadline = None
- self._output_handler = None
+ self.init_deadline: Optional[float] = None
+ self._output_handler: Optional[OutputHandler] = None
self._cmd = None
- self._proc = None
+ self._proc: Optional[mozprocess.ProcessHandler] = None
self._pac = None
- def make_command(self):
+ def make_command(self) -> List[str]:
"""Returns the full command for starting the server process as a list."""
return [self.webdriver_binary] + self.webdriver_args
- def start(self, group_metadata, **kwargs):
+ def start(self, group_metadata: GroupMetadata, **kwargs: Any) -> None:
self.init_deadline = time.time() + self.init_timeout
try:
self._run_server(group_metadata, **kwargs)
@@ -321,14 +337,15 @@ class WebDriverBrowser(Browser):
self.stop()
raise
- def create_output_handler(self, cmd):
+ def create_output_handler(self, cmd: List[str]) -> OutputHandler:
"""Return an instance of the class used to handle application output.
This can be overridden by subclasses which have particular requirements
for parsing, or otherwise using, the output."""
return OutputHandler(self.logger, cmd)
- def _run_server(self, group_metadata, **kwargs):
+ def _run_server(self, group_metadata: GroupMetadata, **kwargs: Any) -> None:
+ assert self.init_deadline is not None
cmd = self.make_command()
self._output_handler = self.create_output_handler(cmd)
@@ -365,17 +382,18 @@ class WebDriverBrowser(Browser):
self._output_handler.start(group_metadata=group_metadata, **kwargs)
self.logger.debug("_run complete")
- def stop(self, force=False):
+ def stop(self, force: bool = False) -> bool:
self.logger.debug("Stopping WebDriver")
clean = True
if self.is_alive():
+ proc = cast(mozprocess.ProcessHandler, self._proc)
# Pass a timeout value to mozprocess Processhandler.kill()
# to ensure it always returns within it.
# See https://bugzilla.mozilla.org/show_bug.cgi?id=1760080
- kill_result = self._proc.kill(timeout=5)
+ kill_result = proc.kill(timeout=5)
if force and kill_result != 0:
clean = False
- self._proc.kill(9, timeout=5)
+ proc.kill(9, timeout=5)
success = not self.is_alive()
if success and self._output_handler is not None:
# Only try to do output post-processing if we managed to shut down
@@ -383,42 +401,41 @@ class WebDriverBrowser(Browser):
self._output_handler = None
return success
- def is_alive(self):
- return hasattr(self._proc, "proc") and self._proc.poll() is None
+ def is_alive(self) -> bool:
+ return self._proc is not None and hasattr(self._proc, "proc") and self._proc.poll() is None
@property
- def url(self):
+ def url(self) -> str:
if self.port is not None:
return f"http://{self.host}:{self.port}{self.base_path}"
raise ValueError("Can't get WebDriver URL before port is assigned")
@property
- def pid(self):
- if self._proc is not None:
- return self._proc.pid
+ def pid(self) -> Optional[int]:
+ return self._proc.pid if self._proc is not None else None
@property
- def port(self):
+ def port(self) -> int:
# If no port is supplied, we'll get a free port right before we use it.
# Nothing guarantees an absence of race conditions here.
if self._port is None:
self._port = get_free_port()
return self._port
- def cleanup(self):
+ def cleanup(self) -> None:
self.stop()
- def executor_browser(self):
+ def executor_browser(self) -> Tuple[Type[ExecutorBrowser], Mapping[str, Any]]:
return ExecutorBrowser, {"webdriver_url": self.url,
"host": self.host,
"port": self.port,
"pac": self.pac,
"env": self.env}
- def settings(self, test):
+ def settings(self, test: Test) -> BrowserSettings:
self._pac = test.environment.get("pac", None) if self._supports_pac else None
return {"pac": self._pac}
@property
- def pac(self):
+ def pac(self) -> Optional[str]:
return self._pac
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 7cb46783fc..8198bfe11d 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome.py
@@ -97,6 +97,9 @@ def executor_kwargs(logger, test_type, test_environment, run_info_data,
chrome_options["args"].append("--use-fake-ui-for-media-stream")
# Use a fake UI for FedCM to allow testing it.
chrome_options["args"].append("--use-fake-ui-for-fedcm")
+ # This is needed until https://github.com/web-platform-tests/wpt/pull/40709
+ # is merged.
+ chrome_options["args"].append("--enable-features=FedCmWithoutWellKnownEnforcement")
# Use a fake UI for digital identity to allow testing it.
chrome_options["args"].append("--use-fake-ui-for-digital-identity")
# Shorten delay for Reporting <https://w3c.github.io/reporting/>.
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome_ios.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome_ios.py
index 85c98f2994..d3beb449e2 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome_ios.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/chrome_ios.py
@@ -4,7 +4,9 @@ from .base import WebDriverBrowser, require_arg
from .base import get_timeout_multiplier # noqa: F401
from ..executors import executor_kwargs as base_executor_kwargs
from ..executors.base import WdspecExecutor # noqa: F401
-from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401
+from ..executors.executorchrome import ChromeDriverPrintRefTestExecutor # noqa: F401
+from ..executors.executorwebdriver import (WebDriverCrashtestExecutor, # noqa: F401
+ WebDriverTestharnessExecutor, # noqa: F401
WebDriverRefTestExecutor) # noqa: F401
@@ -12,7 +14,9 @@ __wptrunner__ = {"product": "chrome_ios",
"check_args": "check_args",
"browser": "ChromeiOSBrowser",
"executor": {"testharness": "WebDriverTestharnessExecutor",
- "reftest": "WebDriverRefTestExecutor"},
+ "reftest": "WebDriverRefTestExecutor",
+ "print-reftest": "ChromeDriverPrintRefTestExecutor",
+ "crashtest": "WebDriverCrashtestExecutor"},
"browser_kwargs": "browser_kwargs",
"executor_kwargs": "executor_kwargs",
"env_extras": "env_extras",
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 6bcbef7c47..814b8b8d75 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -864,6 +864,7 @@ class FirefoxBrowser(Browser):
self.instance_manager.stop_current(force)
self.logger.debug("stopped")
+ @property
def pid(self):
return self.instance.pid()
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 0e90c8a6e4..7c158902e1 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
@@ -323,6 +323,7 @@ class FirefoxAndroidBrowser(Browser):
self.runner.cleanup()
self.logger.debug("stopped")
+ @property
def pid(self):
if self.runner.process_handler is None:
return None
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py
index 0f21afd38f..465aac6e49 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py
@@ -231,6 +231,7 @@ class SauceBrowser(Browser):
def stop(self, force=False):
pass
+ @property
def pid(self):
return None
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py
index 5195fa6442..2cb638be15 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/servodriver.py
@@ -161,6 +161,7 @@ class ServoWebDriverBrowser(Browser):
if self.output_handler is not None:
self.output_handler.after_process_stop()
+ @property
def pid(self):
if self.proc is None:
return None
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/wktr.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/wktr.py
index 8d429f357b..d65f35ccb3 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/wktr.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/wktr.py
@@ -186,6 +186,7 @@ class WKTRBrowser(Browser):
def is_alive(self):
return self._proc is not None and self._proc.poll() is None
+ @property
def pid(self):
return self._proc.pid if self._proc else None
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py
index e206e42754..37951f41d2 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/environment.py
@@ -1,5 +1,6 @@
# mypy: allow-untyped-defs
+import contextlib
import errno
import json
import os
@@ -7,8 +8,11 @@ import signal
import socket
import sys
import time
+from typing import Optional
+import mozprocess
from mozlog import get_default_logger, handlers
+from mozlog.structuredlog import StructuredLogger
from . import mpcontext
from .wptlogging import LogLevelRewriter, QueueHandler, LogQueueThread
@@ -110,6 +114,7 @@ class TestEnvironment:
self.options = options if options is not None else {}
mp_context = mpcontext.get_context()
+ self._stack = contextlib.ExitStack()
self.cache_manager = mp_context.Manager()
self.stash = serve.stash.StashServer(mp_context=mp_context)
self.env_extras = env_extras
@@ -121,13 +126,13 @@ class TestEnvironment:
self.suppress_handler_traceback = suppress_handler_traceback
def __enter__(self):
- server_log_handler = self.server_logging_ctx.__enter__()
+ server_log_handler = self._stack.enter_context(self.server_logging_ctx)
self.config_ctx = self.build_config()
- self.config = self.config_ctx.__enter__()
+ self.config = self._stack.enter_context(self.config_ctx)
- self.stash.__enter__()
- self.cache_manager.__enter__()
+ self._stack.enter_context(self.stash)
+ self._stack.enter_context(self.cache_manager)
assert self.env_extras_cms is None, (
"A TestEnvironment object cannot be nested")
@@ -136,7 +141,7 @@ class TestEnvironment:
for env in self.env_extras:
cm = env(self.options, self.config)
- cm.__enter__()
+ self._stack.enter_context(cm)
self.env_extras_cms.append(cm)
self.servers = serve.start(self.server_logger,
@@ -147,33 +152,27 @@ class TestEnvironment:
webtransport_h3=self.enable_webtransport)
if self.options.get("supports_debugger") and self.debug_info and self.debug_info.interactive:
- self.ignore_interrupts()
+ self._stack.enter_context(self.ignore_interrupts())
return self
def __exit__(self, exc_type, exc_val, exc_tb):
- self.process_interrupts()
-
for servers in self.servers.values():
for _, server in servers:
server.request_shutdown()
for servers in self.servers.values():
for _, server in servers:
server.wait()
- for cm in self.env_extras_cms:
- cm.__exit__(exc_type, exc_val, exc_tb)
+ self._stack.__exit__(exc_type, exc_val, exc_tb)
self.env_extras_cms = None
- self.cache_manager.__exit__(exc_type, exc_val, exc_tb)
- self.stash.__exit__()
- self.config_ctx.__exit__(exc_type, exc_val, exc_tb)
- self.server_logging_ctx.__exit__(exc_type, exc_val, exc_tb)
-
+ @contextlib.contextmanager
def ignore_interrupts(self):
- signal.signal(signal.SIGINT, signal.SIG_IGN)
-
- def process_interrupts(self):
- signal.signal(signal.SIGINT, signal.SIG_DFL)
+ prev_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
+ try:
+ yield
+ finally:
+ signal.signal(signal.SIGINT, prev_handler)
def build_config(self):
override_path = os.path.join(serve_path(self.test_paths), "config.json")
@@ -331,7 +330,11 @@ class TestdriverLoader:
return self._handler(request, response)
-def wait_for_service(logger, host, port, timeout=60, server_process=None):
+def wait_for_service(logger: StructuredLogger,
+ host: str,
+ port: int,
+ timeout: float = 60,
+ server_process: Optional[mozprocess.ProcessHandler] = None) -> bool:
"""Waits until network service given as a tuple of (host, port) becomes
available, `timeout` duration is reached, or the `server_process` exits at
which point ``socket.error`` is raised."""
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 6e671f4cfd..cb9c1a1508 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/actions.py
@@ -319,7 +319,7 @@ class ClickFedCMDialogButtonAction:
def __call__(self, payload):
dialog_button = payload["dialog_button"]
self.logger.debug(f"Clicking FedCM dialog button: {dialog_button}")
- return self.protocol.fedcm.click_fedcm_dialog_button()
+ return self.protocol.fedcm.click_fedcm_dialog_button(dialog_button)
class SelectFedCMAccountAction:
name = "select_fedcm_account"
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js
index 4a27dc27ef..d6616739e6 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testharnessreport-servo.js
@@ -1,4 +1,9 @@
-var props = {output:%(output)d, debug: %(debug)s};
+var props = {
+ output:%(output)d,
+ timeout_multiplier: %(timeout_multiplier)s,
+ explicit_timeout: %(explicit_timeout)s,
+ debug: %(debug)s
+};
var start_loc = document.createElement('a');
start_loc.href = location.href;
setup(props);
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py
index aa266548d7..098e443b5c 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py
@@ -530,6 +530,7 @@ def get_test_queue_builder(**kwargs: Any) -> Tuple[TestQueueBuilder, Mapping[str
TestGroup = namedtuple("TestGroup", ["group", "subsuite", "test_type", "metadata"])
+GroupMetadata = Mapping[str, Any]
class TestQueueBuilder:
@@ -573,7 +574,7 @@ class TestQueueBuilder:
def tests_by_group(self, tests_by_type: TestsByType) -> Mapping[str, List[str]]:
pass
- def group_metadata(self, state: Mapping[str, Any]) -> Mapping[str, Any]:
+ def group_metadata(self, state: Mapping[str, Any]) -> GroupMetadata:
return {"scope": "/"}
def process_count(self, requested_processes: int, num_test_groups: int) -> int:
@@ -654,7 +655,7 @@ class PathGroupedSource(TestQueueBuilder):
groups[group_name].append(test.id)
return groups
- def group_metadata(self, state: Mapping[str, Any]) -> Mapping[str, Any]:
+ def group_metadata(self, state: Mapping[str, Any]) -> GroupMetadata:
return {"scope": "/%s" % "/".join(state["prev_group_key"][2])}
diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
index 28d06f88ee..70da22f5b7 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
@@ -773,6 +773,8 @@ class TestRunnerManager(threading.Thread):
test.max_assertion_count)
file_result.extra["test_timeout"] = test.timeout * self.executor_kwargs['timeout_multiplier']
+ if self.browser.browser_pid:
+ file_result.extra["browser_pid"] = self.browser.browser_pid
self.logger.test_end(test.id,
status,
diff --git a/testing/web-platform/tests/tools/wptserve/wptserve/constants.py b/testing/web-platform/tests/tools/wptserve/wptserve/constants.py
index 584f2cc1c7..292f0085dc 100644
--- a/testing/web-platform/tests/tools/wptserve/wptserve/constants.py
+++ b/testing/web-platform/tests/tools/wptserve/wptserve/constants.py
@@ -25,7 +25,6 @@ content_types = utils.invert_dict({
"text/plain": ["txt", "md"],
"text/vtt": ["vtt"],
"video/mp4": ["mp4", "m4v"],
- "video/ogg": ["ogg", "ogv"],
"video/webm": ["webm"],
})
diff --git a/testing/web-platform/tests/tools/wptserve/wptserve/utils.py b/testing/web-platform/tests/tools/wptserve/wptserve/utils.py
index e711e40725..403c359d27 100644
--- a/testing/web-platform/tests/tools/wptserve/wptserve/utils.py
+++ b/testing/web-platform/tests/tools/wptserve/wptserve/utils.py
@@ -141,6 +141,7 @@ def is_bad_port(port: int) -> bool:
2049, # nfs
3659, # apple-sasl
4045, # lockd
+ 4190, # sieve
5060, # sip
5061, # sips
6000, # x11
@@ -150,6 +151,7 @@ def is_bad_port(port: int) -> bool:
6667, # irc (default)
6668, # irc (alternate)
6669, # irc (alternate)
+ 6679, # osaut
6697, # irc+tls
10080, # amanda
]