From 966017183675a8a728e227dfdf00e734edab8945 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Lopez Perez Date: Tue, 19 Nov 2024 16:14:58 +0000 Subject: [PATCH] [wptrunner] Add a wpewebkit_minibrowser product/browser. This adds a new browser type to run tests with the WPE WebKit port. It can be passed an optional `--headless` parameter to enable headless testing with WPT. Otherwise wayland is required. A pre-built nightly bundle can be also automatically downloaded and installed by passing `--install-browser` to the WPT runner. It shares with webkitgtk_minibrowser most of the logic to download and install the built product. Documentation is also added and the webkitgtk_minibrowser one updated accordingly. Unit tests are also added. --- docs/running-tests/from-local-system.md | 1 + docs/running-tests/webkitgtk_minibrowser.md | 77 ++++++++-- docs/running-tests/wpewebkit_minibrowser.md | 67 +++++++++ tools/wpt/browser.py | 96 +++++++++---- tools/wpt/install.py | 1 + tools/wpt/run.py | 25 +++- tools/wpt/tests/test_browser.py | 133 ++++++++++++++++-- .../wptrunner/wptrunner/browsers/__init__.py | 1 + .../browsers/wpewebkit_minibrowser.py | 77 ++++++++++ 9 files changed, 417 insertions(+), 61 deletions(-) create mode 100644 docs/running-tests/wpewebkit_minibrowser.md create mode 100644 tools/wptrunner/wptrunner/browsers/wpewebkit_minibrowser.py diff --git a/docs/running-tests/from-local-system.md b/docs/running-tests/from-local-system.md index 0d524ea356ae70..cccb17e43f9b2b 100644 --- a/docs/running-tests/from-local-system.md +++ b/docs/running-tests/from-local-system.md @@ -173,6 +173,7 @@ here](command-line-arguments.html#run). android_webview safari webkitgtk_minibrowser + wpewebkit_minibrowser ``` ### Running in parallel diff --git a/docs/running-tests/webkitgtk_minibrowser.md b/docs/running-tests/webkitgtk_minibrowser.md index 5dd047536ed055..c2305efa93e19b 100644 --- a/docs/running-tests/webkitgtk_minibrowser.md +++ b/docs/running-tests/webkitgtk_minibrowser.md @@ -1,22 +1,71 @@ # WebKitGTK MiniBrowser +To be able to run tests with the [WebKitGTK](https://webkitgtk.org/) +MiniBrowser you need the following packages installed: -To be able to run tests with the WebKitGTK MiniBrowser you need the -following packages installed: - -* Fedora: `webkit2gtk3-devel` -* Debian or Ubuntu: `webkit2gtk-driver` - +* Fedora: `webkitgtk6.0` +* Debian or Ubuntu: `webkitgtk-driver` or `webkit2gtk-driver` +* Arch: `webkitgtk-6.0` The WebKitGTK MiniBrowser is not installed on the default binary path. The `wpt` script will try to automatically locate it, but if you need to run it manually you can find it on any of this paths: -* Fedora: `/usr/libexec/webkit2gtk-${VERSION}/MiniBrowser` -* Debian or Ubuntu: `/usr/lib/x86_64-linux-gnu/webkit2gtk-${VERSION}/MiniBrowser` -* Note: - * `VERSION` is `4.0` or `4.1`. - * If not Fedora and the machine architecture is not `x86_64`, then it will - be located inside: - `/usr/lib/${TRIPLET}/webkit2gtk-${VERSION}/MiniBrowser` - where `TRIPLET=$(gcc -dumpmachine)` +* Fedora: `/usr/libexec/webkitgtk-${APIVERSION}/MiniBrowser` +* Arch: `/usr/lib/webkitgtk-${APIVERSION}/MiniBrowser` +* Debian or Ubuntu: `/usr/lib/${TRIPLET}/webkitgtk-${APIVERSION}/MiniBrowser` + * Note: `${TRIPLET}` is the output of the command `gcc -dumpmachine` + +# Nightly universal bundle + +Alternatively you can pass to `wpt` the flags `--install-browser --channel=nightly` +and then `wpt` will automatically download the last bundle and unpack it on the +default `wpt` working directory (usually subdir `_venv3/browsers` in your `wpt` checkout) +Then it will use the unpacked `MiniBrowser` and `WebKitWebDriver` binaries to run the tests. + +This universal bundles should work on any Linux distribution as they include inside +the tarball all the system libraries and resources needed to run WebKitGTK, from libc +up to the Mesa graphics drivers without requiring the usage of containers. + +If you are not using open source graphics drivers (Mesa) and you experience issues +with this bundle then a possible workaround is to try to run the tests headless +inside a virtualized display like `Xvfb` (see command `xvfb-run -a` on Debian/Ubuntu). +You can do this also from inside a virtual machine or docker container. + +# Headless mode + +WebKitGTK does not have a native headless mode, but you can workaround that +by running the tests inside a virtualized display. For example you can use +`weston` with the headless backend for a virtualized `Wayland` display, +or you can use `Xvfb` for a virtualized `X11` display. + +Example: + ``` + xvfb-run -a ./wpt run [more-options] webkitgtk_minibrowser [tests-to-run] + ``` + +# Using a custom WebKitGTK build + +If you want to test with a custom WebKitGTK build the easiest way is that you +install this build in a temporary directory and then tell wpt to run it from there. + +Steps: + + 1. Build WebKitGTK passing the arguments `-DENABLE_MINIBROWSER=ON -DCMAKE_INSTALL_PREFIX=/home/user/testdir_install` + 2. Install it: `ninja install` (or `make install`) + 3. Locate the `MiniBrowser` and `WebKitWebDriver` binaries under `/home/user/testdir_install` + 4. Run `wpt` passing this two paths like this: + ``` + ./wpt run --webdriver-binary=/home/user/testdir_install/bin/WebKitWebDriver \ + --binary=/home/user/testdir_install/libexec/MiniBrowser \ + [more-options] webkitgtk_minibrowser [tests-to-run] + ``` + + * Note: It is important that you build WebKitGTK against the libraries of your system. +Do not build WebKitGTK inside Flatpak or other container unless you run `wpt` also +from inside this container. + +# Running tests locally + +Is a good idea that you increase the verbosity of `wpt` by passing to it the flag `--log-mach=-` +Also, please check the documentation about [Running Tests from the Local System](from-local-system). diff --git a/docs/running-tests/wpewebkit_minibrowser.md b/docs/running-tests/wpewebkit_minibrowser.md new file mode 100644 index 00000000000000..6be3b6dd1af806 --- /dev/null +++ b/docs/running-tests/wpewebkit_minibrowser.md @@ -0,0 +1,67 @@ +# WPE WebKit MiniBrowser + +To be able to run tests with the [WPE WebKit](https://wpewebkit.org) +MiniBrowser you need the following packages installed: + +* Fedora: N/A (build your own or use the nighly bundle) +* Debian or Ubuntu: `wpewebkit-driver` and `libwpewebkit` +* Arch: `wpewebkit` + +The WPE WebKit MiniBrowser is not installed on the default binary path. +The `wpt` script will try to automatically locate it, but if you need +to run it manually you can find it on any of this paths: + +* Arch: `/usr/lib/wpe-webkit-${APIVERSION}/MiniBrowser` +* Debian or Ubuntu: `/usr/lib/${TRIPLET}/wpe-webkit-${APIVERSION}/MiniBrowser` + * Note: `${TRIPLET}` is the output of the command `gcc -dumpmachine` + +# Nightly universal bundle + +Alternatively you can pass to `wpt` the flags `--install-browser --channel=nightly` +and then `wpt` will automatically download the last bundle and unpack it on the +default `wpt` working directory (usually subdir `_venv3/browsers` in your `wpt` checkout) +Then it will use the unpacked `MiniBrowser` and `WPEWebDriver` binaries to run the tests. + +This universal bundles should work on any Linux distribution as they include inside +the tarball all the system libraries and resources needed to run WebKitGTK, from libc +up to the Mesa graphics drivers without requiring the usage of containers. + +If you are not using open source graphics drivers (Mesa) and you experience issues +with this bundle then a possible workaround is to try to run the tests in headless +mode, for that pass the flag `--headless` to `wpt` + +# Headless mode + +The WPE MiniBrowser needs a Wayland display to run, but if you don't have one +or you want to enable headless mode you can pass the flag `--headless` to `wpt`. + +Example: + ``` + ./wpt run [more-options] --headless wpewebkit_minibrowser [tests-to-run] + ``` + +# Using a custom WPE WebKit build + +If you want to test with a custom WPE WebKit build the easiest way is that you +install this build in a temporary directory and then tell wpt to run it from there. + +Steps: + + 1. Build WPE WebKit passing the arguments `-DENABLE_MINIBROWSER=ON -DCMAKE_INSTALL_PREFIX=/home/user/testdir_install' + 2. Install it: `ninja install` (or `make install`) + 3. Locate the `MiniBrowser` and `WPEWebDriver` binaries under /home/user/testdir_install` + 4. Run `wpt` passing this two paths like this: + ``` + ./wpt run --webdriver-binary=/home/user/testdir_install/bin/WPEWebDriver \ + --binary=/home/user/testdir_install/libexec/MiniBrowser \ + [more-options] webkitgtk_minibrowser [tests-to-run] + ``` + +Note: It is important that you build WPE WebKit against the libraries of your system. +Do not build WPE WebKit inside Flatpak or other container unless you run `wpt` also +from inside this container. + +# Running tests locally + +Is a good idea that you increase the verbosity of `wpt` by passing to it the flag `--log-mach=-` +Also, please check the documentation about [Running Tests from the Local System](from-local-system). diff --git a/tools/wpt/browser.py b/tools/wpt/browser.py index 923bf9904f1940..0ac1b982ed0780 100644 --- a/tools/wpt/browser.py +++ b/tools/wpt/browser.py @@ -2374,17 +2374,34 @@ def version(self, binary=None, webdriver_binary=None): return f.read().strip() -class WebKitGTKMiniBrowser(WebKit): +class WebKitGlibBaseMiniBrowser(WebKit): + """WebKitGTK and WPE MiniBrowser specific interface (base class).""" + + # This class is not meant to be used directly. + # And the class variables below should be defined on the subclasses. + BASE_DOWNLOAD_URI = "" + PORT_PRETTY_NAME = "" + WEBDRIVER_BINARY_NAME = "" + LIBEXEC_SUBDIR_PREFIXES = [""] + product = "" + + def __init__(self, *args, **kwargs): + if self.__class__.__name__ == "WebKitGlibBaseMiniBrowser": + raise RuntimeError("class WebKitGlibBaseMiniBrowser should not be used directly, but subclassed") + for required_class_var in ["BASE_DOWNLOAD_URI", "PORT_PRETTY_NAME", "WEBDRIVER_BINARY_NAME", "LIBEXEC_SUBDIR_PREFIXES", "product"]: + class_var_value = getattr(self, required_class_var, "") + if all(len(i) == 0 for i in class_var_value): + raise NotImplementedError('subclass "%s" should define class variable "%s"' % (self.__class__.__name__, required_class_var)) + return super().__init__(*args, **kwargs) def download(self, dest=None, channel=None, rename=None): - base_dowload_uri = "https://webkitgtk.org/built-products/" - base_download_dir = base_dowload_uri + platform.machine() + "/release/" + channel + "/MiniBrowser/" + base_download_dir = self.BASE_DOWNLOAD_URI + platform.machine() + "/release/" + channel + "/MiniBrowser/" try: response = get(base_download_dir + "LAST-IS") except requests.exceptions.HTTPError as e: if e.response.status_code == 404: - raise RuntimeError("Can't find a WebKitGTK MiniBrowser %s bundle for %s at %s" - % (channel, platform.machine(), base_dowload_uri)) + raise RuntimeError("Can't find a %s MiniBrowser %s bundle for %s at %s" + % (self.PORT_PRETTY_NAME, channel, platform.machine(), self.BASE_DOWNLOAD_URI)) raise bundle_filename = response.text.strip() @@ -2393,7 +2410,7 @@ def download(self, dest=None, channel=None, rename=None): dest = self._get_browser_download_dir(dest, channel) bundle_file_path = os.path.join(dest, bundle_filename) - self.logger.info("Downloading WebKitGTK MiniBrowser bundle from %s" % bundle_url) + self.logger.info("Downloading %s MiniBrowser bundle from %s" % (self.PORT_PRETTY_NAME, bundle_url)) with open(bundle_file_path, "w+b") as f: get_download_to_descriptor(f, bundle_url) @@ -2405,13 +2422,13 @@ def download(self, dest=None, channel=None, rename=None): if bundle_expected_hash != bundle_computed_hash: self.logger.error("Calculated SHA256 hash is %s but was expecting %s" % (bundle_computed_hash, bundle_expected_hash)) - raise RuntimeError("The WebKitGTK MiniBrowser bundle at %s has incorrect SHA256 hash." % bundle_file_path) + raise RuntimeError("The %s MiniBrowser bundle at %s has incorrect SHA256 hash." % (self.PORT_PRETTY_NAME, bundle_file_path)) return bundle_file_path def install(self, dest=None, channel=None, prompt=True): dest = self._get_browser_binary_dir(dest, channel) bundle_path = self.download(dest, channel) - bundle_uncompress_directory = os.path.join(dest, "webkitgtk_minibrowser") + bundle_uncompress_directory = os.path.join(dest, self.product) # Clean it from previous runs if os.path.exists(bundle_uncompress_directory): @@ -2425,17 +2442,17 @@ def install(self, dest=None, channel=None, prompt=True): elif ".tar." in bundle_file_name: untar(f, bundle_uncompress_directory) else: - raise NotImplementedError("Unable to install WebKitGTK MiniBrowser bundle from file:" % bundle_file_name) + raise NotImplementedError("Don't know how to install the file: %s" % bundle_file_name) os.remove(bundle_path) - for expected_binary in ["MiniBrowser", "WebKitWebDriver"]: + for expected_binary in ["MiniBrowser", self.WEBDRIVER_BINARY_NAME]: binary_path = os.path.join(bundle_uncompress_directory, expected_binary) if not (os.path.isfile(binary_path) and os.access(binary_path, os.X_OK)): raise RuntimeError("Can't find a %s binary at %s" % (expected_binary, binary_path)) minibrowser_path = os.path.join(bundle_uncompress_directory, "MiniBrowser") version_str = subprocess.check_output([minibrowser_path, "--version"]).decode("utf-8").strip() - self.logger.info("WebKitGTK MiniBrowser bundle for channel %s installed: %s" % (channel, version_str)) + self.logger.info("%s MiniBrowser bundle for channel %s installed: %s" % (self.PORT_PRETTY_NAME, channel, version_str)) install_ok_file = os.path.join(bundle_uncompress_directory, ".installation-ok") open(install_ok_file, "w").close() # touch return minibrowser_path @@ -2443,41 +2460,44 @@ def install(self, dest=None, channel=None, prompt=True): def _find_executable_in_channel_bundle(self, binary, venv_path=None, channel=None): if venv_path: venv_base_path = self._get_browser_binary_dir(venv_path, channel) - bundle_dir = os.path.join(venv_base_path, "webkitgtk_minibrowser") + bundle_dir = os.path.join(venv_base_path, self.product) install_ok_file = os.path.join(bundle_dir, ".installation-ok") if os.path.isfile(install_ok_file): - return which(binary, path=bundle_dir) + return shutil.which(binary, path=bundle_dir) return None def find_binary(self, venv_path=None, channel=None): minibrowser_path = self._find_executable_in_channel_bundle("MiniBrowser", venv_path, channel) if minibrowser_path: + self.logger.info("Found %s MiniBrowser %s at path: %s" % (self.PORT_PRETTY_NAME, channel, minibrowser_path)) return minibrowser_path + # Find MiniBrowser on the system which is usually installed on the libexec dir triplet = "x86_64-linux-gnu" # Try to use GCC to detect this machine triplet - gcc = which("gcc") + gcc = shutil.which("gcc") if gcc: try: triplet = call(gcc, "-dumpmachine").strip() except subprocess.CalledProcessError: pass - - versions = ["4.0", "4.1"] - libexecpaths = [] - - for version in versions: - # Fedora paths. - libexecpaths.append(f"/usr/libexec/webkit2gtk-{version}") - # Debian/Ubuntu paths - libexecpaths.append(f"/usr/lib/{triplet}/webkit2gtk-{version}") - - return which("MiniBrowser", path=os.pathsep.join(libexecpaths)) + for libexec_dir in ["/usr/libexec", f"/usr/lib/{triplet}", "/usr/lib"]: + if os.path.isdir(libexec_dir): + for libexec_entry in sorted(os.listdir(libexec_dir), reverse=True): + for libexec_subdir_prefix in self.LIBEXEC_SUBDIR_PREFIXES: + if libexec_entry.startswith(libexec_subdir_prefix): + minibrowser_candidate_path = os.path.join(libexec_dir, libexec_entry, 'MiniBrowser') + if os.path.isfile(minibrowser_candidate_path) and os.access(minibrowser_candidate_path, os.X_OK): + self.logger.info("Found %s MiniBrowser at path: %s" % (self.PORT_PRETTY_NAME, minibrowser_candidate_path)) + return minibrowser_candidate_path + return None def find_webdriver(self, venv_path=None, channel=None): - webdriver_path = self._find_executable_in_channel_bundle("WebKitWebDriver", venv_path, channel) + webdriver_path = self._find_executable_in_channel_bundle(self.WEBDRIVER_BINARY_NAME, venv_path, channel) if not webdriver_path: - webdriver_path = which("WebKitWebDriver") + webdriver_path = shutil.which(self.WEBDRIVER_BINARY_NAME) + if webdriver_path: + self.logger.info("Found %s WebDriver at path: %s" % (self.PORT_PRETTY_NAME, webdriver_path)) return webdriver_path def version(self, binary=None, webdriver_binary=None): @@ -2489,7 +2509,7 @@ def version(self, binary=None, webdriver_binary=None): return None # Example output: "WebKitGTK 2.26.1" if output: - m = re.match(r"WebKitGTK (.+)", output) + m = re.match(r"%s (.+)" % self.PORT_PRETTY_NAME, output) if not m: self.logger.warning("Failed to extract version from: %s" % output) return None @@ -2497,6 +2517,26 @@ def version(self, binary=None, webdriver_binary=None): return None +class WebKitGTKMiniBrowser(WebKitGlibBaseMiniBrowser): + """WebKitGTK MiniBrowser specific interface.""" + + BASE_DOWNLOAD_URI = "https://webkitgtk.org/built-products/" + PORT_PRETTY_NAME = "WebKitGTK" + WEBDRIVER_BINARY_NAME = "WebKitWebDriver" + LIBEXEC_SUBDIR_PREFIXES = ["webkitgtk", "webkit2gtk"] + product = "webkitgtk_minibrowser" + + +class WPEWebKitMiniBrowser(WebKitGlibBaseMiniBrowser): + """WPE WebKit MiniBrowser specific interface.""" + + BASE_DOWNLOAD_URI = "https://wpewebkit.org/built-products/" + PORT_PRETTY_NAME = "WPE WebKit" + WEBDRIVER_BINARY_NAME = "WPEWebDriver" + LIBEXEC_SUBDIR_PREFIXES = ["wpe-webkit"] + product = "wpewebkit_minibrowser" + + class Epiphany(Browser): """Epiphany-specific interface.""" diff --git a/tools/wpt/install.py b/tools/wpt/install.py index 1e6408b0be633c..e8f0a36a084ff1 100644 --- a/tools/wpt/install.py +++ b/tools/wpt/install.py @@ -14,6 +14,7 @@ 'safari': 'preview', 'servo': 'nightly', 'webkitgtk_minibrowser': 'nightly', + 'wpewebkit_minibrowser': 'nightly', 'wktr': 'main', } diff --git a/tools/wpt/run.py b/tools/wpt/run.py index 9c6acbc2a46523..ee854bda2f9232 100644 --- a/tools/wpt/run.py +++ b/tools/wpt/run.py @@ -816,9 +816,8 @@ def setup_kwargs(self, kwargs): kwargs["binary"] = binary -class WebKitGTKMiniBrowser(BrowserSetup): - name = "webkitgtk_minibrowser" - browser_cls = browser.WebKitGTKMiniBrowser +class WebKitGlibBaseMiniBrowser(BrowserSetup): + """ Base class for WebKitGTKMiniBrowser and WPEWebKitMiniBrowser """ def install(self, channel=None): if self.prompt_install(self.name): @@ -838,10 +837,25 @@ def setup_kwargs(self, kwargs): venv_path=self.venv.path, channel=kwargs["browser_channel"]) if webdriver_binary is None: - raise WptrunError("Unable to find WebKitWebDriver in PATH") + raise WptrunError('Unable to find "%s" binary in PATH' % self.browser_cls.WEBDRIVER_BINARY_NAME) kwargs["webdriver_binary"] = webdriver_binary +class WebKitGTKMiniBrowser(WebKitGlibBaseMiniBrowser): + name = "webkitgtk_minibrowser" + browser_cls = browser.WebKitGTKMiniBrowser + + +class WPEWebKitMiniBrowser(WebKitGlibBaseMiniBrowser): + name = "wpewebkit_minibrowser" + browser_cls = browser.WPEWebKitMiniBrowser + + def setup_kwargs(self, kwargs): + if kwargs["headless"]: + kwargs["binary_args"].append("--headless") + super().setup_kwargs(kwargs) + + class Epiphany(BrowserSetup): name = "epiphany" browser_cls = browser.Epiphany @@ -883,6 +897,7 @@ def setup_kwargs(self, kwargs): "webkit": WebKit, "wktr": WebKitTestRunner, "webkitgtk_minibrowser": WebKitGTKMiniBrowser, + "wpewebkit_minibrowser": WPEWebKitMiniBrowser, "epiphany": Epiphany, "ladybird": Ladybird, } @@ -961,7 +976,7 @@ def setup_wptrunner(venv, **kwargs): if kwargs["install_browser"]: logger.info("Installing browser") - kwargs["binary"] = setup_cls.install(channel=channel) + kwargs["binary"] = setup_cls.install(channel=kwargs["browser_channel"]) setup_cls.setup(kwargs) diff --git a/tools/wpt/tests/test_browser.py b/tools/wpt/tests/test_browser.py index 3a45dab16e2729..692a3af374a9cc 100644 --- a/tools/wpt/tests/test_browser.py +++ b/tools/wpt/tests/test_browser.py @@ -341,8 +341,9 @@ def test_webkitgtk_minibrowser_version(mocked_check_output): assert webkitgtk_minibrowser.version(binary='MiniBrowser') == '2.26.1' # nightly version - mocked_check_output.return_value = b'WebKitGTK 2.27.1 (r250823)\n' - assert webkitgtk_minibrowser.version(binary='MiniBrowser') == '2.27.1 (r250823)' + mocked_check_output.return_value = b'WebKitGTK 2.47.1 (286783@main)\n' + assert webkitgtk_minibrowser.version(binary='MiniBrowser') == '2.47.1 (286783@main)' + @mock.patch('subprocess.check_output') def test_webkitgtk_minibrowser_version_errors(mocked_check_output): @@ -365,33 +366,137 @@ def test_webkitgtk_minibrowser_version_errors(mocked_check_output): # on Windows only works if the binary name ends with a ".exe" suffix. # But, WebKitGTK itself doesn't support Windows, so lets skip the test. @pytest.mark.skipif(sys.platform.startswith('win'), reason='test not needed on Windows') +@mock.patch('os.path.isdir', return_value=True) @mock.patch('os.access', return_value=True) -@mock.patch('os.path.exists') -def test_webkitgtk_minibrowser_find_binary(mocked_os_path_exists, _mocked_os_access): +@mock.patch('shutil.which') +@mock.patch('os.listdir') +@mock.patch('os.path.isfile') +def test_webkitgtk_minibrowser_find_binary(mocked_os_path_isfile, mocked_os_listdir, mocked_which, _mocked_os_access, _mocked_os_isdir): webkitgtk_minibrowser = browser.WebKitGTKMiniBrowser(logger) - # No MiniBrowser found - mocked_os_path_exists.side_effect = lambda path: path == '/etc/passwd' + # No WebKitGTK MiniBrowser found (WPE one shouldn't match) + mocked_os_path_isfile.side_effect = lambda path: path == '/usr/libexec/wpe-webkit-1.0/MiniBrowser' + mocked_os_listdir.side_effect = lambda contents: ['wpe-webkit-1.0', 'webkitgtk-6.0', 'webkit2gtk-4.0'] + mocked_which.side_effect = lambda found: None assert webkitgtk_minibrowser.find_binary() is None # Found on the default Fedora path fedora_minibrowser_path = '/usr/libexec/webkit2gtk-4.0/MiniBrowser' - mocked_os_path_exists.side_effect = lambda path: path == fedora_minibrowser_path + mocked_os_path_isfile.side_effect = lambda path: path == fedora_minibrowser_path + mocked_os_listdir.side_effect = lambda contents: ['wpe-webkit-1.0', 'webkitgtk-6.0', 'webkit2gtk-4.0'] + mocked_which.side_effect = lambda found: None assert webkitgtk_minibrowser.find_binary() == fedora_minibrowser_path # Found on the default Debian path for AMD64 (gcc not available) debian_minibrowser_path_amd64 = '/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/MiniBrowser' - mocked_os_path_exists.side_effect = lambda path: path == debian_minibrowser_path_amd64 + mocked_os_path_isfile.side_effect = lambda path: path == debian_minibrowser_path_amd64 + mocked_os_listdir.side_effect = lambda contents: ['wpe-webkit-1.0', 'webkitgtk-6.0', 'webkit2gtk-4.0'] + mocked_which.side_effect = lambda found: None assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_amd64 # Found on the default Debian path for AMD64 (gcc available but gives an error) debian_minibrowser_path_amd64 = '/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/MiniBrowser' - mocked_os_path_exists.side_effect = lambda path: path in [debian_minibrowser_path_amd64, '/usr/bin/gcc'] + mocked_os_path_isfile.side_effect = lambda path: path in [debian_minibrowser_path_amd64, '/usr/bin/gcc'] + mocked_os_listdir.side_effect = lambda contents: ['wpe-webkit-1.0', 'webkitgtk-6.0', 'webkit2gtk-4.0'] + mocked_which.side_effect = lambda found: '/usr/bin/gcc' with mock.patch('subprocess.check_output', return_value = b'error', side_effect = subprocess.CalledProcessError(1, 'cmd')): assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_amd64 - # Found on the default Debian path for ARM64 (gcc available) - debian_minibrowser_path_arm64 = '/usr/lib/aarch64-linux-gnu/webkit2gtk-4.0/MiniBrowser' - mocked_os_path_exists.side_effect = lambda path: path in [debian_minibrowser_path_arm64, '/usr/bin/gcc'] - with mock.patch('subprocess.check_output', return_value = b'aarch64-linux-gnu'): - assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_arm64 + # Found on the default Debian path for ARM64 (gcc available) + debian_minibrowser_path_arm64 = '/usr/lib/aarch64-linux-gnu/webkit2gtk-4.0/MiniBrowser' + mocked_os_path_isfile.side_effect = lambda path: path in [debian_minibrowser_path_arm64, '/usr/bin/gcc'] + mocked_os_listdir.side_effect = lambda contents: sorted(['wpe-webkit-1.0', 'webkitgtk-6.0', 'webkit2gtk-4.0']) + mocked_which.side_effect = lambda found: '/usr/bin/gcc' + with mock.patch('subprocess.check_output', return_value = b'aarch64-linux-gnu'): + assert webkitgtk_minibrowser.find_binary() == debian_minibrowser_path_arm64 + + # Find first the MiniBrowser on the directory with the higher number in case two available + mocked_os_path_isfile.side_effect = lambda path: True + mocked_os_listdir.side_effect = lambda contents: ['wpe-webkit-1.0', 'webkitgtk-6.0', 'webkit2gtk-4.0'] + mocked_which.side_effect = lambda found: None + assert webkitgtk_minibrowser.find_binary() == '/usr/libexec/webkitgtk-6.0/MiniBrowser' + + +@mock.patch('subprocess.check_output') +def test_wpewebkit_minibrowser_version(mocked_check_output): + wpewebkit_minibrowser = browser.WPEWebKitMiniBrowser(logger) + + # stable version + mocked_check_output.return_value = b'WPE WebKit 2.26.1\n' + assert wpewebkit_minibrowser.version(binary='MiniBrowser') == '2.26.1' + + # nightly version + mocked_check_output.return_value = b'WPE WebKit 2.47.1 (286783@main)\n' + assert wpewebkit_minibrowser.version(binary='MiniBrowser') == '2.47.1 (286783@main)' + + +@mock.patch('subprocess.check_output') +def test_wpewebkit_minibrowser_version_errors(mocked_check_output): + wpewebkit_minibrowser = browser.WPEWebKitMiniBrowser(logger) + + # No binary + assert wpewebkit_minibrowser.version() is None + + # `MiniBrowser --version` return gibberish + mocked_check_output.return_value = b'gibberish' + assert wpewebkit_minibrowser.version(binary='MiniBrowser') is None + + # `MiniBrowser --version` fails (as it does for MiniBrowser <= 2.26.0) + mocked_check_output.return_value = b'dummy' + mocked_check_output.side_effect = subprocess.CalledProcessError(1, 'cmd') + assert wpewebkit_minibrowser.version(binary='MiniBrowser') is None + + +# The test below doesn't work on Windows because find_binary() +# on Windows only works if the binary name ends with a ".exe" suffix. +# But, WPE WebKit itself doesn't support Windows, so lets skip the test. +@pytest.mark.skipif(sys.platform.startswith('win'), reason='test not needed on Windows') +@mock.patch('os.path.isdir', return_value=True) +@mock.patch('os.access', return_value=True) +@mock.patch('shutil.which') +@mock.patch('os.listdir') +@mock.patch('os.path.isfile') +def test_wpewebkit_minibrowser_find_binary(mocked_os_path_isfile, mocked_os_listdir, mocked_which, _mocked_os_access, _mocked_os_isdir): + wpewebkit_minibrowser = browser.WPEWebKitMiniBrowser(logger) + + # No WPE MiniBrowser found (WebKitGTK one shouldn't match) + mocked_os_path_isfile.side_effect = lambda path: path == '/usr/libexec/wpewebkit-6.0/MiniBrowser' + mocked_os_listdir.side_effect = lambda contents: ['wpewebkit-6.0', 'webkit2gtk-4.0', 'wpe-webkit-1.0'] + mocked_which.side_effect = lambda found: None + assert wpewebkit_minibrowser.find_binary() is None + + # Found on the default Arch path + arch_minibrowser_path = '/usr/lib/wpe-webkit-1.0/MiniBrowser' + mocked_os_path_isfile.side_effect = lambda path: path == arch_minibrowser_path + mocked_os_listdir.side_effect = lambda contents: ['wpewebkit-6.0', 'webkit2gtk-4.0', 'wpe-webkit-1.0'] + mocked_which.side_effect = lambda found: None + assert wpewebkit_minibrowser.find_binary() == arch_minibrowser_path + + # Found on the default Debian path for AMD64 (gcc not available) + debian_minibrowser_path_amd64 = '/usr/lib/x86_64-linux-gnu/wpe-webkit-1.0/MiniBrowser' + mocked_os_path_isfile.side_effect = lambda path: path == debian_minibrowser_path_amd64 + mocked_os_listdir.side_effect = lambda contents: ['wpewebkit-6.0', 'webkit2gtk-4.0', 'wpe-webkit-1.0'] + mocked_which.side_effect = lambda found: None + assert wpewebkit_minibrowser.find_binary() == debian_minibrowser_path_amd64 + + # Found on the default Debian path for AMD64 (gcc available but gives an error) + debian_minibrowser_path_amd64 = '/usr/lib/x86_64-linux-gnu/wpe-webkit-1.0/MiniBrowser' + mocked_os_path_isfile.side_effect = lambda path: path in [debian_minibrowser_path_amd64, '/usr/bin/gcc'] + mocked_os_listdir.side_effect = lambda contents: ['wpewebkit-6.0', 'webkit2gtk-4.0', 'wpe-webkit-1.0'] + mocked_which.side_effect = lambda found: '/usr/bin/gcc' + with mock.patch('subprocess.check_output', return_value = b'error', side_effect = subprocess.CalledProcessError(1, 'cmd')): + assert wpewebkit_minibrowser.find_binary() == debian_minibrowser_path_amd64 + + # Found on the default Debian path for ARM64 (gcc available) + debian_minibrowser_path_arm64 = '/usr/lib/aarch64-linux-gnu/wpe-webkit-1.0/MiniBrowser' + mocked_os_path_isfile.side_effect = lambda path: path in [debian_minibrowser_path_arm64, '/usr/bin/gcc'] + mocked_os_listdir.side_effect = lambda contents: ['wpewebkit-6.0', 'webkit2gtk-4.0', 'wpe-webkit-1.0'] + mocked_which.side_effect = lambda found: '/usr/bin/gcc' + with mock.patch('subprocess.check_output', return_value = b'aarch64-linux-gnu'): + assert wpewebkit_minibrowser.find_binary() == debian_minibrowser_path_arm64 + + # Find first the MiniBrowser on the directory with the higher number in case two available + mocked_os_path_isfile.side_effect = lambda path: True + mocked_os_listdir.side_effect = lambda contents: sorted(['wpewebkit-6.0', 'webkit2gtk-4.0', 'wpe-webkit-2.0', 'wpe-webkit-1.0']) + mocked_which.side_effect = lambda found: None + assert wpewebkit_minibrowser.find_binary() == '/usr/libexec/wpe-webkit-2.0/MiniBrowser' diff --git a/tools/wptrunner/wptrunner/browsers/__init__.py b/tools/wptrunner/wptrunner/browsers/__init__.py index aaf91a1dc86efc..c27ae7281dc075 100644 --- a/tools/wptrunner/wptrunner/browsers/__init__.py +++ b/tools/wptrunner/wptrunner/browsers/__init__.py @@ -38,6 +38,7 @@ "opera", "webkit", "webkitgtk_minibrowser", + "wpewebkit_minibrowser", "wktr", "epiphany", "ladybird"] diff --git a/tools/wptrunner/wptrunner/browsers/wpewebkit_minibrowser.py b/tools/wptrunner/wptrunner/browsers/wpewebkit_minibrowser.py new file mode 100644 index 00000000000000..80f5acce1c52cf --- /dev/null +++ b/tools/wptrunner/wptrunner/browsers/wpewebkit_minibrowser.py @@ -0,0 +1,77 @@ +# mypy: allow-untyped-defs + +from .base import (NullBrowser, # noqa: F401 + certificate_domain_list, + get_timeout_multiplier, # noqa: F401 + maybe_add_args) +from .webkit import WebKitBrowser +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.base import WdspecExecutor # noqa: F401 +from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 + WebDriverRefTestExecutor, # noqa: F401 + WebDriverCrashtestExecutor) # noqa: F401 + +__wptrunner__ = {"product": "wpewebkit_minibrowser", + "check_args": "check_args", + "browser": "WPEWebKitMiniBrowser", + "browser_kwargs": "browser_kwargs", + "executor": {"testharness": "WebDriverTestharnessExecutor", + "reftest": "WebDriverRefTestExecutor", + "wdspec": "WdspecExecutor", + "crashtest": "WebDriverCrashtestExecutor"}, + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options", + "run_info_extras": "run_info_extras", + "timeout_multiplier": "get_timeout_multiplier"} + + +def check_args(**kwargs): + pass + + +def browser_kwargs(logger, test_type, run_info_data, config, **kwargs): + # Workaround for https://gitlab.gnome.org/GNOME/libsoup/issues/172 + webdriver_required_args = ["--host=127.0.0.1"] + webdriver_args = maybe_add_args(webdriver_required_args, kwargs.get("webdriver_args")) + return {"binary": kwargs["binary"], + "webdriver_binary": kwargs["webdriver_binary"], + "webdriver_args": webdriver_args} + + +def capabilities(server_config, **kwargs): + browser_required_args = ["--automation"] + args = kwargs.get("binary_args", []) + args = maybe_add_args(browser_required_args, args) + return { + "browserName": "MiniBrowser", + "wpe:browserOptions": { + "binary": kwargs["binary"], + "args": args, + "certificates": certificate_domain_list(server_config.domains_set, kwargs["host_cert_path"])}} + + +def executor_kwargs(logger, test_type, test_environment, run_info_data, + **kwargs): + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) + executor_kwargs["close_after_done"] = True + executor_kwargs["capabilities"] = capabilities(test_environment.config, **kwargs) + if test_type == "wdspec": + executor_kwargs["binary_args"] = executor_kwargs["capabilities"]["wpe:browserOptions"]["args"] + return executor_kwargs + + +def env_extras(**kwargs): + return [] + + +def env_options(): + return {} + + +def run_info_extras(logger, **kwargs): + return {"webkit_port": "wpe"} + + +class WPEWebKitMiniBrowser(WebKitBrowser): + pass