blob: d08b0f9380712d618ae96593634c84458fc25621 [file] [log] [blame]
import argparse
import os
import platform
import sys
from distutils.spawn import find_executable
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, utils, virtualenv
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(WptrunnerHelpAction, self).__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)
parser.add_argument("product", action="store",
help="Browser to run tests in")
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("--channel", action="store",
choices=install.channel_by_name.keys(),
default=None, help='Name of browser release channel. '
'"stable" and "release" are synonyms for the latest browser stable '
'release, "nightly", "dev", "experimental", and "preview" are all '
'synonyms for the latest available development release. (For WebDriver '
'installs, we attempt to select an appropriate, compatible version for '
'the latest browser release on the selected channel.) '
'This flag overrides --browser-channel.')
parser._add_container_actions(wptcommandline.create_parser())
return parser
def exit(msg):
logger.error(msg)
sys.exit(1)
def args_general(kwargs):
kwargs.set_if_none("tests_root", wpt_root)
kwargs.set_if_none("metadata_root", wpt_root)
kwargs.set_if_none("manifest_update", True)
kwargs.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 ("firefox", "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 = "%s\System32\drivers\etc\hosts" % os.environ.get("SystemRoot", "C:\Windows")
else:
hosts_path = "/etc/hosts"
with open(hosts_path, "r") 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 wpt make-hosts-file | Out-File %s -Encoding ascii -Append
in PowerShell with Administrator privileges.""" % hosts_path
else:
message = """Missing hosts file configuration. Run
./wpt make-hosts-file | sudo tee -a %s""" % hosts_path
raise WptrunError(message)
class BrowserSetup(object):
name = None
browser_cls = None
def __init__(self, venv, prompt=True, sub_product=None):
self.browser = self.browser_cls()
self.venv = venv
self.prompt = prompt
self.sub_product = sub_product
def prompt_install(self, component):
if not self.prompt:
return True
while True:
resp = raw_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, venv, channel=None):
if self.prompt_install(self.name):
return self.browser.install(venv.path, channel)
def install_requirements(self):
self.venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", self.browser.requirements))
def setup(self, kwargs):
self.setup_kwargs(kwargs)
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:
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:
print("Using certutil %s" % certutil)
kwargs["certutil_binary"] = certutil
if kwargs["webdriver_binary"] is None and "wdspec" in kwargs["test_types"]:
webdriver_binary = self.browser.find_webdriver()
if webdriver_binary is None:
install = self.prompt_install("geckodriver")
if install:
print("Downloading geckodriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
print("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
else:
print("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:
kwargs["headless"] = True
logger.info("Running in headless mode, pass --no-headless to disable")
# Allow WebRTC tests to call getUserMedia.
kwargs["extra_prefs"].append("media.navigator.streams.fake=true")
class Fennec(BrowserSetup):
name = "fennec"
browser_cls = browser.Fennec
def setup_kwargs(self, kwargs):
pass
class Chrome(BrowserSetup):
name = "chrome"
browser_cls = browser.Chrome
def setup_kwargs(self, kwargs):
if kwargs["webdriver_binary"] is None:
webdriver_binary = self.browser.find_webdriver()
if webdriver_binary is None:
install = self.prompt_install("chromedriver")
if install:
print("Downloading chromedriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
print("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
else:
raise WptrunError("Unable to locate or install chromedriver binary")
if kwargs["browser_channel"] == "dev":
logger.info("Automatically turning on experimental features for Chrome Dev")
kwargs["binary_args"].append("--enable-experimental-web-platform-features")
# Allow WebRTC tests to call getUserMedia.
kwargs["binary_args"] += ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream"]
class ChromeAndroid(BrowserSetup):
name = "chrome_android"
browser_cls = browser.ChromeAndroid
def setup_kwargs(self, kwargs):
if kwargs["webdriver_binary"] is None:
webdriver_binary = self.browser.find_webdriver()
if webdriver_binary is None:
install = self.prompt_install("chromedriver")
if install:
print("Downloading chromedriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
print("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 ChromeWebDriver(Chrome):
name = "chrome_webdriver"
browser_cls = browser.ChromeWebDriver
class Opera(BrowserSetup):
name = "opera"
browser_cls = browser.Opera
def setup_kwargs(self, kwargs):
if kwargs["webdriver_binary"] is None:
webdriver_binary = self.browser.find_webdriver()
if webdriver_binary is None:
install = self.prompt_install("operadriver")
if install:
print("Downloading operadriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
print("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 Edge(BrowserSetup):
name = "edge"
browser_cls = browser.Edge
def install(self, venv, 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, venv, 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, venv, 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 locate safaridriver binary")
kwargs["webdriver_binary"] = webdriver_binary
class SafariWebDriver(Safari):
name = "safari_webdriver"
browser_cls = browser.SafariWebDriver
class Sauce(BrowserSetup):
name = "sauce"
browser_cls = browser.Sauce
def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
kwargs.set_if_none("sauce_browser", self.sub_product[0])
kwargs.set_if_none("sauce_version", self.sub_product[1])
kwargs["test_types"] = ["testharness", "reftest"]
class Servo(BrowserSetup):
name = "servo"
browser_cls = browser.Servo
def install(self, venv, channel=None):
if self.prompt_install(self.name):
return self.browser.install(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 on the PATH")
kwargs["binary"] = binary
class WebKit(BrowserSetup):
name = "webkit"
browser_cls = browser.WebKit
def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
pass
product_setup = {
"fennec": Fennec,
"firefox": Firefox,
"chrome": Chrome,
"chrome_android": ChromeAndroid,
"chrome_webdriver": ChromeWebDriver,
"edge": Edge,
"edge_webdriver": EdgeWebDriver,
"ie": InternetExplorer,
"safari": Safari,
"safari_webdriver": SafariWebDriver,
"servo": Servo,
"sauce": Sauce,
"opera": Opera,
"webkit": WebKit,
}
def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
from wptrunner import wptrunner, wptcommandline
global logger
kwargs = utils.Kwargs(kwargs.iteritems())
product_parts = kwargs["product"].split(":")
kwargs["product"] = product_parts[0]
sub_product = product_parts[1:]
wptrunner.setup_logging(kwargs, {"mach": sys.stdout})
logger = wptrunner.logger
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, prompt, sub_product)
setup_cls.install_requirements()
if 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 != kwargs["channel"]:
logger.info("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
channel))
kwargs["browser_channel"] = channel
del kwargs["channel"]
if install_browser:
logger.info("Installing browser")
kwargs["binary"] = setup_cls.install(venv, channel=channel)
setup_cls.setup(kwargs)
wptcommandline.check_args(kwargs)
wptrunner_path = os.path.join(wpt_root, "tools", "wptrunner")
venv.install_requirements(os.path.join(wptrunner_path, "requirements.txt"))
kwargs['browser_version'] = setup_cls.browser.version(kwargs.get("binary"))
return kwargs
def run(venv, **kwargs):
# Remove arguments that aren't passed to wptrunner
prompt = kwargs.pop("prompt", True)
install_browser = kwargs.pop("install_browser", False)
kwargs = setup_wptrunner(venv,
prompt=prompt,
install_browser=install_browser,
**kwargs)
rv = run_single(venv, **kwargs) > 0
return rv
def run_single(venv, **kwargs):
from wptrunner import wptrunner
return wptrunner.start(**kwargs)
def main():
try:
parser = create_parser()
args = parser.parse_args()
venv = virtualenv.Virtualenv(os.path.join(wpt_root, "_venv_%s") % platform.uname()[0])
venv.start()
venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", "requirements.txt"))
venv.install("requests")
return run(venv, vars(args))
except WptrunError as e:
exit(e.message)
if __name__ == "__main__":
import pdb
from tools import localpaths # noqa: flake8
try:
main()
except Exception:
pdb.post_mortem()