Commit f885408c authored by James Graham's avatar James Graham
Browse files

Bug 1759874 - Enable automatic downoading of geckodriver for mach test-intervention, r=twisniewski

For local running it's inconvenient to have to manually download or
build geckodriver, so if we don't already have a build then download
the latest stable release from GitHub. This shouldn't affect CI since
we always have a build in that case.

Differential Revision: https://phabricator.services.mozilla.com/D141244
parent 2390d257
Loading
Loading
Loading
Loading
+84 −3
Original line number Diff line number Diff line
@@ -3,7 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import argparse
import io
import os
import platform
import sys

from mach.decorators import Command
@@ -12,6 +14,28 @@ from mozbuild.base import MozbuildObject
here = os.path.abspath(os.path.dirname(__file__))


def get(url):
    import requests

    resp = requests.get(url)
    resp.raise_for_status()
    return resp


def untar(fileobj, dest):
    import tarfile

    with tarfile.open(fileobj=fileobj, mode="r") as tar_data:
        tar_data.extractall(path=dest)


def unzip(fileobj, dest):
    import zipfile

    with zipfile.ZipFile(fileobj) as zip_data:
        zip_data.extractall(path=dest)


def create_parser_interventions():
    from mozlog import commandline

@@ -43,18 +67,75 @@ def create_parser_interventions():


class InterventionTest(MozbuildObject):
    def set_default_kwargs(self, kwargs):
    def set_default_kwargs(self, logger, kwargs):
        if kwargs["binary"] is None:
            kwargs["binary"] = self.get_binary_path()

        if kwargs["webdriver_binary"] is None:
            kwargs["webdriver_binary"] = self.get_binary_path(
            webdriver_binary = self.get_binary_path(
                "geckodriver", validate_exists=False
            )

            if not os.path.exists(webdriver_binary):
                webdriver_binary = self.install_geckodriver(
                    logger, dest=os.path.dirname(webdriver_binary)
                )

            if not os.path.exists(webdriver_binary):
                logger.error("Can't find geckodriver")
                sys.exit(1)
            kwargs["webdriver_binary"] = webdriver_binary

    def get_capabilities(self, kwargs):
        return {"moz:firefoxOptions": {"binary": kwargs["binary"]}}

    def platform_string_geckodriver(self):
        uname = platform.uname()
        platform_name = {"Linux": "linux", "Windows": "win", "Darwin": "macos"}.get(
            uname[0]
        )

        if platform_name in ("linux", "win"):
            bits = "64" if uname[4] == "x86_64" else "32"
        elif platform_name == "macos":
            bits = ""
        else:
            raise ValueError(f"No precompiled geckodriver for platform {uname}")

        return f"{platform_name}{bits}"

    def install_geckodriver(self, logger, dest):
        """Install latest Geckodriver."""
        if dest is None:
            dest = os.path.join(self.distdir, "dist", "bin")

        is_windows = platform.uname()[0] == "Windows"

        release = get(
            "https://api.github.com/repos/mozilla/geckodriver/releases/latest"
        ).json()
        ext = "zip" if is_windows else "tar.gz"
        platform_name = self.platform_string_geckodriver()
        name_suffix = f"-{platform_name}.{ext}"
        for item in release["assets"]:
            if item["name"].endswith(name_suffix):
                url = item["browser_download_url"]
                break
        else:
            raise ValueError(f"Failed to find geckodriver for platform {platform_name}")

        logger.info(f"Installing geckodriver from {url}")

        data = io.BytesIO(get(url).content)
        data.seek(0)
        decompress = unzip if ext == "zip" else untar
        decompress(data, dest=dest)

        exe_ext = ".exe" if is_windows else ""
        path = os.path.join(dest, f"geckodriver{exe_ext}")

        return path

    def run(self, **kwargs):
        import runner
        import mozlog
@@ -66,7 +147,7 @@ class InterventionTest(MozbuildObject):
        status_handler = mozlog.handlers.StatusHandler()
        logger.add_handler(status_handler)

        self.set_default_kwargs(kwargs)
        self.set_default_kwargs(logger, kwargs)

        interventions = (
            ["enabled", "disabled"]