Skip to content
This repository has been archived by the owner on Dec 18, 2018. It is now read-only.

Commit

Permalink
Initial support for running tests with ssl enabled in Firefox.
Browse files Browse the repository at this point in the history
  • Loading branch information
jgraham committed Oct 28, 2014
1 parent 20af1c0 commit fce96d0
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 21 deletions.
2 changes: 1 addition & 1 deletion wptrunner/browsers/b2g.py
Expand Up @@ -36,7 +36,7 @@ def check_args(**kwargs):
pass


def browser_kwargs(**kwargs):
def browser_kwargs(test_environment, **kwargs):
return {"prefs_root": kwargs["prefs_root"],
"no_backup": kwargs.get("b2g_no_backup", False)}

Expand Down
4 changes: 4 additions & 0 deletions wptrunner/browsers/base.py
Expand Up @@ -100,6 +100,10 @@ def is_alive(self):
"""Boolean indicating whether the browser process is still running"""
pass

def setup_ssl(self, hosts):
"""Return a certificate to use for tests requiring ssl that will be trusted by the browser"""
raise NotImplementedError("ssl testing not supported")

def cleanup(self):
"""Browser-specific cleanup that is run after the testrun is finished"""
pass
Expand Down
2 changes: 1 addition & 1 deletion wptrunner/browsers/chrome.py
Expand Up @@ -25,7 +25,7 @@ def check_args(**kwargs):
require_arg(kwargs, "binary")


def browser_kwargs(**kwargs):
def browser_kwargs(test_environment, **kwargs):
return {"binary": kwargs["binary"]}


Expand Down
50 changes: 44 additions & 6 deletions wptrunner/browsers/firefox.py
Expand Up @@ -3,7 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import os
import subprocess

import mozinfo
from mozprocess import ProcessHandler
from mozprofile import FirefoxProfile, Preferences
from mozprofile.permissions import ServerLocations
Expand All @@ -28,15 +30,19 @@

def check_args(**kwargs):
require_arg(kwargs, "binary")
if kwargs["ssl_type"] != "none":
require_arg(kwargs, "certutil_binary")


def browser_kwargs(**kwargs):
return {"binary": kwargs["binary"],
"prefs_root": kwargs["prefs_root"],
"debug_args": kwargs["debug_args"],
"interactive": kwargs["interactive"],
"symbols_path":kwargs["symbols_path"],
"stackwalk_binary":kwargs["stackwalk_binary"]}
"symbols_path": kwargs["symbols_path"],
"stackwalk_binary": kwargs["stackwalk_binary"],
"certutil_binary": kwargs["certutil_binary"],
"ca_certificate_path": kwargs["ssl_env"].ca_cert_path()}


def executor_kwargs(http_server_url, **kwargs):
Expand All @@ -49,14 +55,16 @@ def env_options():
return {"host": "localhost",
"external_host": "web-platform.test",
"bind_hostname": "true",
"required_files": required_files}
"required_files": required_files,
"certificate_domain": "web-platform.test"}


class FirefoxBrowser(Browser):
used_ports = set()

def __init__(self, logger, binary, prefs_root, debug_args=None, interactive=None,
symbols_path=None, stackwalk_binary=None):
symbols_path=None, stackwalk_binary=None, certutil_binary=None,
ca_certificate_path=None):
Browser.__init__(self, logger)
self.binary = binary
self.prefs_root = prefs_root
Expand All @@ -68,6 +76,8 @@ def __init__(self, logger, binary, prefs_root, debug_args=None, interactive=None
self.profile = None
self.symbols_path = symbols_path
self.stackwalk_binary = stackwalk_binary
self.ca_certificate_path = ca_certificate_path
self.certutil_binary = certutil_binary

def start(self):
self.marionette_port = get_free_port(2828, exclude=self.used_ports)
Expand All @@ -93,6 +103,9 @@ def start(self):
"marionette.defaultPrefs.port": self.marionette_port,
"dom.disable_open_during_load": False})

if self.ca_certificate_path is not None:
self.setup_ssl()

self.runner = FirefoxRunner(profile=self.profile,
binary=self.binary,
cmdargs=[cmd_arg("marionette"), "about:blank"],
Expand Down Expand Up @@ -152,6 +165,31 @@ def executor_browser(self):

def log_crash(self, process, test):
dump_dir = os.path.join(self.profile.profile, "minidumps")
mozcrash.log_crashes(self.logger, dump_dir, symbols_path=self.symbols_path,

mozcrash.log_crashes(self.logger,
dump_dir,
symbols_path=self.symbols_path,
stackwalk_binary=self.stackwalk_binary,
process=process, test=test)
process=process,
test=test)

def setup_ssl(self):
self.logger.info("Setting up ssl")
def certutil(*args):
binary = os.path.join(self.certutil_binary)
cmd = [str(item) for item in [binary] + list(args)]
print cmd
return subprocess.check_call(cmd)

pw_path = os.path.join(self.profile.profile, ".crtdbpw")
with open(pw_path, "w") as f:
f.write("\n")

cert_db_path = self.profile.profile

# Create a new certificate db
certutil("-N", "-d", cert_db_path, "-f", pw_path)

root, ext = os.path.splitext(os.path.split(self.ca_certificate_path)[1])
certutil("-A", "-d", cert_db_path, "-f", pw_path, "-n", root, "-t", "CT,,",
"-i", self.ca_certificate_path)
2 changes: 1 addition & 1 deletion wptrunner/browsers/servo.py
Expand Up @@ -23,7 +23,7 @@ def check_args(**kwargs):
require_arg(kwargs, "binary")


def browser_kwargs(**kwargs):
def browser_kwargs(test_environment, **kwargs):
return {"binary": kwargs["binary"],
"debug_args": kwargs["debug_args"],
"interactive": kwargs["interactive"]}
Expand Down
2 changes: 1 addition & 1 deletion wptrunner/config.json
@@ -1,6 +1,6 @@
{"host": "%(host)s",
"ports":{"http":[8000, 8001],
"https":[],
"https":[8443],
"ws":[8888]},
"check_subdomains":false,
"bind_hostname":%(bind_hostname)s}
5 changes: 4 additions & 1 deletion wptrunner/products.py
Expand Up @@ -49,4 +49,7 @@ def load_product(config, product):
cls = getattr(module, cls_name)
executor_classes[test_type] = cls

return check_args, browser_cls, browser_kwargs, executor_classes, executor_kwargs, env_options
return (check_args,
browser_cls, browser_kwargs,
executor_classes, executor_kwargs,
env_options)
8 changes: 8 additions & 0 deletions wptrunner/wptcommandline.py
Expand Up @@ -120,6 +120,14 @@ def create_parser(product_choices=None):
parser.add_argument("--stackwalk-binary", action="store", type=abs_path,
help="Path to stackwalker program used to analyse minidumps.")

parser.add_argument("--ssl-type", action="store", default="openssl",
choices=["openssl", "pregenerated", "none"],
help="Type of ssl support to enable (running without ssl may lead to spurious errors)")
parser.add_argument("--openssl-binary", action="store",
help="Path to openssl binary", default="openssl")
parser.add_argument("--certutil-binary", action="store",
help="Path to certutil binary for use with Firefox + ssl")

parser.add_argument("--b2g-no-backup", action="store_true", default=False,
help="Don't backup device before testrun with --product=b2g")

Expand Down
60 changes: 50 additions & 10 deletions wptrunner/wptrunner.py
Expand Up @@ -67,24 +67,33 @@ def setup_stdlib_logger():


def do_delayed_imports(serve_root):
global serve, manifest
global serve, manifest, sslutils

sys.path.insert(0, serve_root)
sys.path.insert(0, str(os.path.join(serve_root, "tools")))
sys.path.insert(0, str(os.path.join(serve_root, "tools", "scripts")))
failed = []

print sys.path

sys.path.insert(0, os.path.join(serve_root))
sys.path.insert(0, os.path.join(serve_root, "tools", "scripts"))
failed = None
try:
import serve
except ImportError:
failed = "serve"
failed.append("serve")
try:
import manifest
except ImportError:
failed = "manifest"
failed.append("manifest")
try:
import sslutils
except ImportError:
raise
failed.append("sslutils")

if failed:
logger.critical(
"Failed to import %s. Ensure that tests path %s contains web-platform-tests" %
(failed, serve_root))
(", ".join(failed), serve_root))
sys.exit(1)


Expand All @@ -93,11 +102,12 @@ class TestEnvironmentError(Exception):


class TestEnvironment(object):
def __init__(self, serve_path, test_paths, options):
def __init__(self, serve_path, test_paths, ssl_env, options):
"""Context manager that owns the test environment i.e. the http and
websockets servers"""
self.serve_path = serve_path
self.test_paths = test_paths
self.ssl_env = ssl_env
self.server = None
self.config = None
self.external_config = None
Expand All @@ -107,16 +117,19 @@ def __init__(self, serve_path, test_paths, options):
self.files_to_restore = []

def __enter__(self):
self.ssl_env.__enter__()
self.copy_required_files()
self.setup_routes()
self.config = self.load_config()
serve.set_computed_defaults(self.config)

serve.logger = serve.default_logger("info")
self.external_config, self.servers = serve.start(self.config)
self.external_config, self.servers = serve.start(self.config, self.ssl_env)
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.ssl_env.__exit__(exc_type, exc_val, exc_tb)

self.restore_files()
for scheme, servers in self.servers.iteritems():
for port, server in servers:
Expand All @@ -133,11 +146,26 @@ def load_config(self):
data = f.read()
local_config = json.loads(data % self.options)

#TODO: allow non-default configuration for ssl

local_config["external_host"] = self.options.get("external_host", None)

config = serve.merge_json(default_config, local_config)
config["doc_root"] = self.serve_path

if self.ssl_env.ssl_enabled:
config["ports"]["https"] = [8443]
else:
config["ports"]["https"] = [None]

host = self.options.get("certificate_domain", config["host"])
hosts = [host]
hosts.extend("%s.%s" % (item, host) for item in serve.get_subdomains(host).values())
key_file, certificate = self.ssl_env.host_cert_path(hosts)

config["key_file"] = key_file
config["certificate"] = certificate

return config

def setup_routes(self):
Expand Down Expand Up @@ -265,6 +293,7 @@ def list_test_groups(serve_root, test_paths, test_types, product, **kwargs):
for item in sorted(test_loader.groups(test_types)):
print item


def list_disabled(serve_root, test_paths, test_types, product, **kwargs):
do_delayed_imports(serve_root)
rv = []
Expand All @@ -280,6 +309,13 @@ def list_disabled(serve_root, test_paths, test_types, product, **kwargs):
print json.dumps(rv, indent=2)


def get_ssl_kwargs(**kwargs):
if kwargs["ssl_type"] == "openssl":
return {"openssl_binary": kwargs["openssl_binary"]}
elif kwargs["ssl_type"] == "pregenerated":
raise NotImplementedError


def run_tests(config, serve_root, test_paths, product, **kwargs):
logging_queue = None
logging_thread = None
Expand All @@ -305,7 +341,8 @@ def run_tests(config, serve_root, test_paths, product, **kwargs):

check_args(**kwargs)

browser_kwargs = get_browser_kwargs(**kwargs)
ssl_env_cls = sslutils.environments[kwargs["ssl_type"]]
ssl_env = ssl_env_cls(logger, **get_ssl_kwargs(**kwargs))

unexpected_total = 0

Expand Down Expand Up @@ -336,15 +373,18 @@ def run_tests(config, serve_root, test_paths, product, **kwargs):

with TestEnvironment(serve_root,
test_paths,
ssl_env,
env_options) as test_environment:
try:
test_environment.ensure_started()
except TestEnvironmentError as e:
logger.critical("Error starting test environment: %s" % e.message)
raise

browser_kwargs = get_browser_kwargs(ssl_env=ssl_env, **kwargs)
base_server = "http://%s:%i" % (test_environment.external_config["host"],
test_environment.external_config["ports"]["http"][0])

repeat = kwargs["repeat"]
for repeat_count in xrange(repeat):
if repeat > 1:
Expand Down

0 comments on commit fce96d0

Please sign in to comment.