summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/wpt/run.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/tools/wpt/run.py
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/tools/wpt/run.py')
-rw-r--r--testing/web-platform/tests/tools/wpt/run.py873
1 files changed, 873 insertions, 0 deletions
diff --git a/testing/web-platform/tests/tools/wpt/run.py b/testing/web-platform/tests/tools/wpt/run.py
new file mode 100644
index 0000000000..468bea3c51
--- /dev/null
+++ b/testing/web-platform/tests/tools/wpt/run.py
@@ -0,0 +1,873 @@
+# mypy: allow-untyped-defs
+
+import argparse
+import os
+import platform
+import sys
+from distutils.spawn import find_executable
+from typing import ClassVar, Tuple, Type
+
+wpt_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
+
+from . import browser, install, testfiles
+from ..serve import serve
+
+logger = None
+
+
+class WptrunError(Exception):
+ pass
+
+
+class WptrunnerHelpAction(argparse.Action):
+ def __init__(self,
+ option_strings,
+ dest=argparse.SUPPRESS,
+ default=argparse.SUPPRESS,
+ help=None):
+ super().__init__(
+ option_strings=option_strings,
+ dest=dest,
+ default=default,
+ nargs=0,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ from wptrunner import wptcommandline
+ wptparser = wptcommandline.create_parser()
+ wptparser.usage = parser.usage
+ wptparser.print_help()
+ parser.exit()
+
+
+def create_parser():
+ from wptrunner import wptcommandline
+
+ parser = argparse.ArgumentParser(add_help=False, parents=[install.channel_args])
+ parser.add_argument("product", action="store",
+ help="Browser to run tests in")
+ parser.add_argument("--affected", action="store", default=None,
+ help="Run affected tests since revish")
+ parser.add_argument("--yes", "-y", dest="prompt", action="store_false", default=True,
+ help="Don't prompt before installing components")
+ parser.add_argument("--install-browser", action="store_true",
+ help="Install the browser from the release channel specified by --channel "
+ "(or the nightly channel by default).")
+ parser.add_argument("--install-webdriver", action="store_true",
+ help="Install WebDriver from the release channel specified by --channel "
+ "(or the nightly channel by default).")
+ parser._add_container_actions(wptcommandline.create_parser())
+ return parser
+
+
+def exit(msg=None):
+ if msg:
+ logger.critical(msg)
+ sys.exit(1)
+ else:
+ sys.exit(0)
+
+
+def args_general(kwargs):
+
+ def set_if_none(name, value):
+ if kwargs.get(name) is None:
+ kwargs[name] = value
+ logger.info("Set %s to %s" % (name, value))
+
+ set_if_none("tests_root", wpt_root)
+ set_if_none("metadata_root", wpt_root)
+ set_if_none("manifest_update", True)
+ set_if_none("manifest_download", True)
+
+ if kwargs["ssl_type"] in (None, "pregenerated"):
+ cert_root = os.path.join(wpt_root, "tools", "certs")
+ if kwargs["ca_cert_path"] is None:
+ kwargs["ca_cert_path"] = os.path.join(cert_root, "cacert.pem")
+
+ if kwargs["host_key_path"] is None:
+ kwargs["host_key_path"] = os.path.join(cert_root, "web-platform.test.key")
+
+ if kwargs["host_cert_path"] is None:
+ kwargs["host_cert_path"] = os.path.join(cert_root, "web-platform.test.pem")
+ elif kwargs["ssl_type"] == "openssl":
+ if not find_executable(kwargs["openssl_binary"]):
+ if os.uname()[0] == "Windows":
+ raise WptrunError("""OpenSSL binary not found. If you need HTTPS tests, install OpenSSL from
+
+https://slproweb.com/products/Win32OpenSSL.html
+
+Ensuring that libraries are added to /bin and add the resulting bin directory to
+your PATH.
+
+Otherwise run with --ssl-type=none""")
+ else:
+ raise WptrunError("""OpenSSL not found. If you don't need HTTPS support run with --ssl-type=none,
+otherwise install OpenSSL and ensure that it's on your $PATH.""")
+
+
+def check_environ(product):
+ if product not in ("android_weblayer", "android_webview", "chrome",
+ "chrome_android", "chrome_ios", "content_shell",
+ "firefox", "firefox_android", "servo"):
+ config_builder = serve.build_config(os.path.join(wpt_root, "config.json"))
+ # Override the ports to avoid looking for free ports
+ config_builder.ssl = {"type": "none"}
+ config_builder.ports = {"http": [8000]}
+
+ is_windows = platform.uname()[0] == "Windows"
+
+ with config_builder as config:
+ expected_hosts = set(config.domains_set)
+ if is_windows:
+ expected_hosts.update(config.not_domains_set)
+
+ missing_hosts = set(expected_hosts)
+ if is_windows:
+ hosts_path = r"%s\System32\drivers\etc\hosts" % os.environ.get(
+ "SystemRoot", r"C:\Windows")
+ else:
+ hosts_path = "/etc/hosts"
+
+ if os.path.abspath(os.curdir) == wpt_root:
+ wpt_path = "wpt"
+ else:
+ wpt_path = os.path.join(wpt_root, "wpt")
+
+ with open(hosts_path) as f:
+ for line in f:
+ line = line.split("#", 1)[0].strip()
+ parts = line.split()
+ hosts = parts[1:]
+ for host in hosts:
+ missing_hosts.discard(host)
+ if missing_hosts:
+ if is_windows:
+ message = """Missing hosts file configuration. Run
+
+python %s make-hosts-file | Out-File %s -Encoding ascii -Append
+
+in PowerShell with Administrator privileges.""" % (wpt_path, hosts_path)
+ else:
+ message = """Missing hosts file configuration. Run
+
+%s make-hosts-file | sudo tee -a %s""" % ("./wpt" if wpt_path == "wpt" else wpt_path,
+ hosts_path)
+ raise WptrunError(message)
+
+
+class BrowserSetup:
+ name = None # type: ClassVar[str]
+ browser_cls = None # type: ClassVar[Type[browser.Browser]]
+
+ def __init__(self, venv, prompt=True):
+ self.browser = self.browser_cls(logger)
+ self.venv = venv
+ self.prompt = prompt
+
+ def prompt_install(self, component):
+ if not self.prompt:
+ return True
+ while True:
+ resp = input("Download and install %s [Y/n]? " % component).strip().lower()
+ if not resp or resp == "y":
+ return True
+ elif resp == "n":
+ return False
+
+ def install(self, channel=None):
+ if self.prompt_install(self.name):
+ return self.browser.install(self.venv.path, channel)
+
+ def install_requirements(self):
+ if not self.venv.skip_virtualenv_setup and self.browser.requirements:
+ self.venv.install_requirements(os.path.join(
+ wpt_root, "tools", "wptrunner", self.browser.requirements))
+
+
+ def setup(self, kwargs):
+ self.setup_kwargs(kwargs)
+
+
+def safe_unsetenv(env_var):
+ """Safely remove an environment variable.
+
+ Python3 does not support os.unsetenv in Windows for python<3.9, so we better
+ remove the variable directly from os.environ.
+ """
+ try:
+ del os.environ[env_var]
+ except KeyError:
+ pass
+
+
+class Firefox(BrowserSetup):
+ name = "firefox"
+ browser_cls = browser.Firefox
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["binary"] is None:
+ if kwargs["browser_channel"] is None:
+ kwargs["browser_channel"] = "nightly"
+ logger.info("No browser channel specified. Running nightly instead.")
+
+ binary = self.browser.find_binary(self.venv.path,
+ kwargs["browser_channel"])
+ if binary is None:
+ raise WptrunError("""Firefox binary not found on $PATH.
+
+Install Firefox or use --binary to set the binary path""")
+ kwargs["binary"] = binary
+
+ if kwargs["certutil_binary"] is None and kwargs["ssl_type"] != "none":
+ certutil = self.browser.find_certutil()
+
+ if certutil is None:
+ # Can't download this for now because it's missing the libnss3 library
+ logger.info("""Can't find certutil, certificates will not be checked.
+Consider installing certutil via your OS package manager or directly.""")
+ else:
+ logger.info("Using certutil %s" % certutil)
+
+ kwargs["certutil_binary"] = certutil
+
+ if kwargs["webdriver_binary"] is None and "wdspec" in kwargs["test_types"]:
+ webdriver_binary = None
+ if not kwargs["install_webdriver"]:
+ webdriver_binary = self.browser.find_webdriver()
+
+ if webdriver_binary is None:
+ install = self.prompt_install("geckodriver")
+
+ if install:
+ logger.info("Downloading geckodriver")
+ webdriver_binary = self.browser.install_webdriver(
+ dest=self.venv.bin_path,
+ channel=kwargs["browser_channel"],
+ browser_binary=kwargs["binary"])
+ else:
+ logger.info("Using webdriver binary %s" % webdriver_binary)
+
+ if webdriver_binary:
+ kwargs["webdriver_binary"] = webdriver_binary
+ else:
+ logger.info("Unable to find or install geckodriver, skipping wdspec tests")
+ kwargs["test_types"].remove("wdspec")
+
+ if kwargs["prefs_root"] is None:
+ prefs_root = self.browser.install_prefs(kwargs["binary"],
+ self.venv.path,
+ channel=kwargs["browser_channel"])
+ kwargs["prefs_root"] = prefs_root
+
+ if kwargs["headless"] is None and not kwargs["debug_test"]:
+ kwargs["headless"] = True
+ logger.info("Running in headless mode, pass --no-headless to disable")
+
+ # Turn off Firefox WebRTC ICE logging on WPT (turned on by mozrunner)
+ safe_unsetenv('R_LOG_LEVEL')
+ safe_unsetenv('R_LOG_DESTINATION')
+ safe_unsetenv('R_LOG_VERBOSE')
+
+ # Allow WebRTC tests to call getUserMedia.
+ kwargs["extra_prefs"].append("media.navigator.streams.fake=true")
+
+
+class FirefoxAndroid(BrowserSetup):
+ name = "firefox_android"
+ browser_cls = browser.FirefoxAndroid
+
+ def setup_kwargs(self, kwargs):
+ from . import android
+ import mozdevice
+
+ # We don't support multiple channels for android yet
+ if kwargs["browser_channel"] is None:
+ kwargs["browser_channel"] = "nightly"
+
+ if kwargs["prefs_root"] is None:
+ prefs_root = self.browser.install_prefs(kwargs["binary"],
+ self.venv.path,
+ channel=kwargs["browser_channel"])
+ kwargs["prefs_root"] = prefs_root
+
+ if kwargs["package_name"] is None:
+ kwargs["package_name"] = "org.mozilla.geckoview.test_runner"
+ app = kwargs["package_name"]
+
+ if not kwargs["device_serial"]:
+ kwargs["device_serial"] = ["emulator-5554"]
+
+ for device_serial in kwargs["device_serial"]:
+ if device_serial.startswith("emulator-"):
+ # We're running on an emulator so ensure that's set up
+ emulator = android.install(logger,
+ reinstall=False,
+ no_prompt=not self.prompt,
+ device_serial=device_serial)
+ android.start(logger,
+ emulator=emulator,
+ reinstall=False,
+ device_serial=device_serial)
+
+ if "ADB_PATH" not in os.environ:
+ adb_path = os.path.join(android.get_sdk_path(None),
+ "platform-tools",
+ "adb")
+ os.environ["ADB_PATH"] = adb_path
+ adb_path = os.environ["ADB_PATH"]
+
+ for device_serial in kwargs["device_serial"]:
+ device = mozdevice.ADBDeviceFactory(adb=adb_path,
+ device=device_serial)
+
+ if self.browser.apk_path:
+ device.uninstall_app(app)
+ device.install_app(self.browser.apk_path)
+ elif not device.is_app_installed(app):
+ raise WptrunError("app %s not installed on device %s" %
+ (app, device_serial))
+
+
+class Chrome(BrowserSetup):
+ name = "chrome"
+ browser_cls = browser.Chrome # type: ClassVar[Type[browser.ChromeChromiumBase]]
+ experimental_channels = ("dev", "canary", "nightly") # type: ClassVar[Tuple[str, ...]]
+
+ def setup_kwargs(self, kwargs):
+ browser_channel = kwargs["browser_channel"]
+ if kwargs["binary"] is None:
+ binary = self.browser.find_binary(venv_path=self.venv.path, channel=browser_channel)
+ if binary:
+ kwargs["binary"] = binary
+ else:
+ raise WptrunError(f"Unable to locate {self.name.capitalize()} binary")
+
+ if kwargs["mojojs_path"]:
+ kwargs["enable_mojojs"] = True
+ logger.info("--mojojs-path is provided, enabling MojoJS")
+ else:
+ path = self.browser.install_mojojs(dest=self.venv.path,
+ browser_binary=kwargs["binary"])
+ if path:
+ kwargs["mojojs_path"] = path
+ kwargs["enable_mojojs"] = True
+ logger.info(f"MojoJS enabled automatically (mojojs_path: {path})")
+ else:
+ kwargs["enable_mojojs"] = False
+ logger.info("MojoJS is disabled for this run.")
+
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = None
+ if not kwargs["install_webdriver"]:
+ webdriver_binary = self.browser.find_webdriver(self.venv.bin_path)
+ if webdriver_binary and not self.browser.webdriver_supports_browser(
+ webdriver_binary, kwargs["binary"], browser_channel):
+ webdriver_binary = None
+
+ if webdriver_binary is None:
+ install = self.prompt_install("chromedriver")
+
+ if install:
+ webdriver_binary = self.browser.install_webdriver(
+ dest=self.venv.bin_path,
+ channel=browser_channel,
+ browser_binary=kwargs["binary"],
+ )
+ else:
+ logger.info("Using webdriver binary %s" % webdriver_binary)
+
+ if webdriver_binary:
+ kwargs["webdriver_binary"] = webdriver_binary
+ else:
+ raise WptrunError("Unable to locate or install matching ChromeDriver binary")
+ if browser_channel in self.experimental_channels:
+ # HACK(Hexcles): work around https://github.com/web-platform-tests/wpt/issues/16448
+ kwargs["webdriver_args"].append("--disable-build-check")
+ if kwargs["enable_experimental"] is None:
+ logger.info(
+ "Automatically turning on experimental features for Chrome Dev/Canary or Chromium trunk")
+ kwargs["enable_experimental"] = True
+ if kwargs["enable_webtransport_h3"] is None:
+ # To start the WebTransport over HTTP/3 test server.
+ kwargs["enable_webtransport_h3"] = True
+ if os.getenv("TASKCLUSTER_ROOT_URL"):
+ # We are on Taskcluster, where our Docker container does not have
+ # enough capabilities to run Chrome with sandboxing. (gh-20133)
+ kwargs["binary_args"].append("--no-sandbox")
+
+
+class ContentShell(BrowserSetup):
+ name = "content_shell"
+ browser_cls = browser.ContentShell
+ experimental_channels = ("dev", "canary", "nightly")
+
+ def setup_kwargs(self, kwargs):
+ browser_channel = kwargs["browser_channel"]
+ if kwargs["binary"] is None:
+ binary = self.browser.find_binary(venv_path=self.venv.path, channel=browser_channel)
+ if binary:
+ kwargs["binary"] = binary
+ else:
+ raise WptrunError(f"Unable to locate {self.name.capitalize()} binary")
+
+ if kwargs["mojojs_path"]:
+ kwargs["enable_mojojs"] = True
+ logger.info("--mojojs-path is provided, enabling MojoJS")
+ elif kwargs["enable_mojojs"]:
+ logger.warning(f"Cannot install MojoJS for {self.name}, "
+ "which does not return version information. "
+ "Provide '--mojojs-path' explicitly instead.")
+ logger.warning("MojoJS is disabled for this run.")
+
+ kwargs["enable_webtransport_h3"] = True
+
+
+class Chromium(Chrome):
+ name = "chromium"
+ browser_cls = browser.Chromium # type: ClassVar[Type[browser.ChromeChromiumBase]]
+ experimental_channels = ("nightly",)
+
+
+class ChromeAndroidBase(BrowserSetup):
+ experimental_channels = ("dev", "canary")
+
+ def setup_kwargs(self, kwargs):
+ if kwargs.get("device_serial"):
+ self.browser.device_serial = kwargs["device_serial"]
+ if kwargs.get("adb_binary"):
+ self.browser.adb_binary = kwargs["adb_binary"]
+ browser_channel = kwargs["browser_channel"]
+ if kwargs["package_name"] is None:
+ kwargs["package_name"] = self.browser.find_binary(
+ channel=browser_channel)
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = None
+ if not kwargs["install_webdriver"]:
+ webdriver_binary = self.browser.find_webdriver()
+
+ if webdriver_binary is None:
+ install = self.prompt_install("chromedriver")
+
+ if install:
+ logger.info("Downloading chromedriver")
+ webdriver_binary = self.browser.install_webdriver(
+ dest=self.venv.bin_path,
+ channel=browser_channel,
+ browser_binary=kwargs["package_name"],
+ )
+ else:
+ logger.info("Using webdriver binary %s" % webdriver_binary)
+
+ if webdriver_binary:
+ kwargs["webdriver_binary"] = webdriver_binary
+ else:
+ raise WptrunError("Unable to locate or install chromedriver binary")
+
+
+class ChromeAndroid(ChromeAndroidBase):
+ name = "chrome_android"
+ browser_cls = browser.ChromeAndroid
+
+ def setup_kwargs(self, kwargs):
+ super().setup_kwargs(kwargs)
+ if kwargs["browser_channel"] in self.experimental_channels:
+ # HACK(Hexcles): work around https://github.com/web-platform-tests/wpt/issues/16448
+ kwargs["webdriver_args"].append("--disable-build-check")
+ if kwargs["enable_experimental"] is None:
+ logger.info("Automatically turning on experimental features for Chrome Dev/Canary")
+ kwargs["enable_experimental"] = True
+
+
+class ChromeiOS(BrowserSetup):
+ name = "chrome_ios"
+ browser_cls = browser.ChromeiOS
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["webdriver_binary"] is None:
+ raise WptrunError("Unable to locate or install chromedriver binary")
+
+
+class AndroidWeblayer(ChromeAndroidBase):
+ name = "android_weblayer"
+ browser_cls = browser.AndroidWeblayer
+
+ def setup_kwargs(self, kwargs):
+ super().setup_kwargs(kwargs)
+ if kwargs["browser_channel"] in self.experimental_channels and kwargs["enable_experimental"] is None:
+ logger.info("Automatically turning on experimental features for WebLayer Dev/Canary")
+ kwargs["enable_experimental"] = True
+
+
+class AndroidWebview(ChromeAndroidBase):
+ name = "android_webview"
+ browser_cls = browser.AndroidWebview
+
+
+class Opera(BrowserSetup):
+ name = "opera"
+ browser_cls = browser.Opera
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = None
+ if not kwargs["install_webdriver"]:
+ webdriver_binary = self.browser.find_webdriver()
+
+ if webdriver_binary is None:
+ install = self.prompt_install("operadriver")
+
+ if install:
+ logger.info("Downloading operadriver")
+ webdriver_binary = self.browser.install_webdriver(
+ dest=self.venv.bin_path,
+ channel=kwargs["browser_channel"])
+ else:
+ logger.info("Using webdriver binary %s" % webdriver_binary)
+
+ if webdriver_binary:
+ kwargs["webdriver_binary"] = webdriver_binary
+ else:
+ raise WptrunError("Unable to locate or install operadriver binary")
+
+
+class EdgeChromium(BrowserSetup):
+ name = "MicrosoftEdge"
+ browser_cls = browser.EdgeChromium
+
+ def setup_kwargs(self, kwargs):
+ browser_channel = kwargs["browser_channel"]
+ if kwargs["binary"] is None:
+ binary = self.browser.find_binary(channel=browser_channel)
+ if binary:
+ logger.info("Using Edge binary %s" % binary)
+ kwargs["binary"] = binary
+ else:
+ raise WptrunError("Unable to locate Edge binary")
+
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = None
+ if not kwargs["install_webdriver"]:
+ webdriver_binary = self.browser.find_webdriver()
+ if (webdriver_binary and not self.browser.webdriver_supports_browser(
+ webdriver_binary, kwargs["binary"])):
+ webdriver_binary = None
+
+ if webdriver_binary is None:
+ install = self.prompt_install("msedgedriver")
+
+ if install:
+ logger.info("Downloading msedgedriver")
+ webdriver_binary = self.browser.install_webdriver(
+ dest=self.venv.bin_path,
+ channel=browser_channel)
+ else:
+ logger.info("Using webdriver binary %s" % webdriver_binary)
+
+ if webdriver_binary:
+ kwargs["webdriver_binary"] = webdriver_binary
+ else:
+ raise WptrunError("Unable to locate or install msedgedriver binary")
+ if browser_channel in ("dev", "canary") and kwargs["enable_experimental"] is None:
+ logger.info("Automatically turning on experimental features for Edge Dev/Canary")
+ kwargs["enable_experimental"] = True
+
+
+class Edge(BrowserSetup):
+ name = "edge"
+ browser_cls = browser.Edge
+
+ def install(self, channel=None):
+ raise NotImplementedError
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = self.browser.find_webdriver()
+
+ if webdriver_binary is None:
+ raise WptrunError("""Unable to find WebDriver and we aren't yet clever enough to work out which
+version to download. Please go to the following URL and install the correct
+version for your Edge/Windows release somewhere on the %PATH%:
+
+https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
+""")
+ kwargs["webdriver_binary"] = webdriver_binary
+
+
+class EdgeWebDriver(Edge):
+ name = "edge_webdriver"
+ browser_cls = browser.EdgeWebDriver
+
+
+class InternetExplorer(BrowserSetup):
+ name = "ie"
+ browser_cls = browser.InternetExplorer
+
+ def install(self, channel=None):
+ raise NotImplementedError
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = self.browser.find_webdriver()
+
+ if webdriver_binary is None:
+ raise WptrunError("""Unable to find WebDriver and we aren't yet clever enough to work out which
+version to download. Please go to the following URL and install the driver for Internet Explorer
+somewhere on the %PATH%:
+
+https://selenium-release.storage.googleapis.com/index.html
+""")
+ kwargs["webdriver_binary"] = webdriver_binary
+
+
+class Safari(BrowserSetup):
+ name = "safari"
+ browser_cls = browser.Safari
+
+ def install(self, channel=None):
+ raise NotImplementedError
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = self.browser.find_webdriver(channel=kwargs["browser_channel"])
+
+ if webdriver_binary is None:
+ raise WptrunError("Unable to locate safaridriver binary")
+
+ kwargs["webdriver_binary"] = webdriver_binary
+
+
+class Sauce(BrowserSetup):
+ name = "sauce"
+ browser_cls = browser.Sauce
+
+ def install(self, channel=None):
+ raise NotImplementedError
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["sauce_browser"] is None:
+ raise WptrunError("Missing required argument --sauce-browser")
+ if kwargs["sauce_version"] is None:
+ raise WptrunError("Missing required argument --sauce-version")
+ kwargs["test_types"] = ["testharness", "reftest"]
+
+
+class Servo(BrowserSetup):
+ name = "servo"
+ browser_cls = browser.Servo
+
+ def install(self, channel=None):
+ if self.prompt_install(self.name):
+ return self.browser.install(self.venv.path)
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["binary"] is None:
+ binary = self.browser.find_binary(self.venv.path, None)
+
+ if binary is None:
+ raise WptrunError("Unable to find servo binary in PATH")
+ kwargs["binary"] = binary
+
+
+class ServoWebDriver(Servo):
+ name = "servodriver"
+ browser_cls = browser.ServoWebDriver
+
+
+class WebKit(BrowserSetup):
+ name = "webkit"
+ browser_cls = browser.WebKit
+
+ def install(self, channel=None):
+ raise NotImplementedError
+
+ def setup_kwargs(self, kwargs):
+ pass
+
+
+class WebKitGTKMiniBrowser(BrowserSetup):
+ name = "webkitgtk_minibrowser"
+ browser_cls = browser.WebKitGTKMiniBrowser
+
+ def install(self, channel=None):
+ if self.prompt_install(self.name):
+ return self.browser.install(self.venv.path, channel, self.prompt)
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["binary"] is None:
+ binary = self.browser.find_binary(
+ venv_path=self.venv.path, channel=kwargs["browser_channel"])
+
+ if binary is None:
+ raise WptrunError("Unable to find MiniBrowser binary")
+ kwargs["binary"] = binary
+
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = self.browser.find_webdriver(
+ venv_path=self.venv.path, channel=kwargs["browser_channel"])
+
+ if webdriver_binary is None:
+ raise WptrunError("Unable to find WebKitWebDriver in PATH")
+ kwargs["webdriver_binary"] = webdriver_binary
+
+
+class Epiphany(BrowserSetup):
+ name = "epiphany"
+ browser_cls = browser.Epiphany
+
+ def install(self, channel=None):
+ raise NotImplementedError
+
+ def setup_kwargs(self, kwargs):
+ if kwargs["binary"] is None:
+ binary = self.browser.find_binary()
+
+ if binary is None:
+ raise WptrunError("Unable to find epiphany in PATH")
+ kwargs["binary"] = binary
+
+ if kwargs["webdriver_binary"] is None:
+ webdriver_binary = self.browser.find_webdriver()
+
+ if webdriver_binary is None:
+ raise WptrunError("Unable to find WebKitWebDriver in PATH")
+ kwargs["webdriver_binary"] = webdriver_binary
+
+
+product_setup = {
+ "android_weblayer": AndroidWeblayer,
+ "android_webview": AndroidWebview,
+ "firefox": Firefox,
+ "firefox_android": FirefoxAndroid,
+ "chrome": Chrome,
+ "chrome_android": ChromeAndroid,
+ "chrome_ios": ChromeiOS,
+ "chromium": Chromium,
+ "content_shell": ContentShell,
+ "edgechromium": EdgeChromium,
+ "edge": Edge,
+ "edge_webdriver": EdgeWebDriver,
+ "ie": InternetExplorer,
+ "safari": Safari,
+ "servo": Servo,
+ "servodriver": ServoWebDriver,
+ "sauce": Sauce,
+ "opera": Opera,
+ "webkit": WebKit,
+ "webkitgtk_minibrowser": WebKitGTKMiniBrowser,
+ "epiphany": Epiphany,
+}
+
+
+def setup_logging(kwargs, default_config=None, formatter_defaults=None):
+ import mozlog
+ from wptrunner import wptrunner
+
+ global logger
+
+ # Use the grouped formatter by default where mozlog 3.9+ is installed
+ if default_config is None:
+ if hasattr(mozlog.formatters, "GroupingFormatter"):
+ default_formatter = "grouped"
+ else:
+ default_formatter = "mach"
+ default_config = {default_formatter: sys.stdout}
+ wptrunner.setup_logging(kwargs, default_config, formatter_defaults=formatter_defaults)
+ logger = wptrunner.logger
+ return logger
+
+
+def setup_wptrunner(venv, **kwargs):
+ from wptrunner import wptcommandline
+
+ kwargs = kwargs.copy()
+
+ kwargs["product"] = kwargs["product"].replace("-", "_")
+
+ check_environ(kwargs["product"])
+ args_general(kwargs)
+
+ if kwargs["product"] not in product_setup:
+ raise WptrunError("Unsupported product %s" % kwargs["product"])
+
+ setup_cls = product_setup[kwargs["product"]](venv, kwargs["prompt"])
+ setup_cls.install_requirements()
+
+ affected_revish = kwargs.get("affected")
+ if affected_revish is not None:
+ files_changed, _ = testfiles.files_changed(
+ affected_revish, include_uncommitted=True, include_new=True)
+ # TODO: Perhaps use wptrunner.testloader.ManifestLoader here
+ # and remove the manifest-related code from testfiles.
+ # https://github.com/web-platform-tests/wpt/issues/14421
+ tests_changed, tests_affected = testfiles.affected_testfiles(
+ files_changed, manifest_path=kwargs.get("manifest_path"), manifest_update=kwargs["manifest_update"])
+ test_list = tests_changed | tests_affected
+ logger.info("Identified %s affected tests" % len(test_list))
+ test_list = [os.path.relpath(item, wpt_root) for item in test_list]
+ kwargs["test_list"] += test_list
+ kwargs["default_exclude"] = True
+
+ if kwargs["install_browser"] and not kwargs["channel"]:
+ logger.info("--install-browser is given but --channel is not set, default to nightly channel")
+ kwargs["channel"] = "nightly"
+
+ if kwargs["channel"]:
+ channel = install.get_channel(kwargs["product"], kwargs["channel"])
+ if channel is not None:
+ if channel != kwargs["channel"]:
+ logger.info("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+ channel))
+ kwargs["browser_channel"] = channel
+ else:
+ logger.info("Valid channels for %s not known; using argument unmodified" %
+ kwargs["product"])
+ kwargs["browser_channel"] = kwargs["channel"]
+
+ if kwargs["install_browser"]:
+ logger.info("Installing browser")
+ kwargs["binary"] = setup_cls.install(channel=channel)
+
+ setup_cls.setup(kwargs)
+
+ # Remove kwargs we handle here
+ wptrunner_kwargs = kwargs.copy()
+ for kwarg in ["affected",
+ "install_browser",
+ "install_webdriver",
+ "channel",
+ "prompt"]:
+ del wptrunner_kwargs[kwarg]
+
+ wptcommandline.check_args(wptrunner_kwargs)
+
+ wptrunner_path = os.path.join(wpt_root, "tools", "wptrunner")
+
+ if not venv.skip_virtualenv_setup:
+ venv.install_requirements(os.path.join(wptrunner_path, "requirements.txt"))
+
+ # Only update browser_version if it was not given as a command line
+ # argument, so that it can be overridden on the command line.
+ if not wptrunner_kwargs["browser_version"]:
+ wptrunner_kwargs["browser_version"] = setup_cls.browser.version(
+ binary=wptrunner_kwargs.get("binary") or wptrunner_kwargs.get("package_name"),
+ webdriver_binary=wptrunner_kwargs.get("webdriver_binary"),
+ )
+
+ return wptrunner_kwargs
+
+
+def run(venv, **kwargs):
+ setup_logging(kwargs)
+
+ wptrunner_kwargs = setup_wptrunner(venv, **kwargs)
+
+ rv = run_single(venv, **wptrunner_kwargs) > 0
+
+ return rv
+
+
+def run_single(venv, **kwargs):
+ from wptrunner import wptrunner
+ return wptrunner.start(**kwargs)