# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import re
import sys
from argparse
import Namespace
from mach.decorators
import Command
from mozbuild.base
import MachCommandConditions
as conditions
from mozbuild.base
import MozbuildObject
parser =
None
class ReftestRunner(MozbuildObject):
"""Easily run reftests.
This currently contains just the basics
for running reftests. We may want
to hook up result parsing, etc.
"""
def __init__(self, *args, **kwargs):
MozbuildObject.__init__(self, *args, **kwargs)
# TODO Bug 794506 remove once mach integrates with virtualenv.
build_path = os.path.join(self.topobjdir,
"build")
if build_path
not in sys.path:
sys.path.append(build_path)
self.tests_dir = os.path.join(self.topobjdir,
"_tests")
self.reftest_dir = os.path.join(self.tests_dir,
"reftest")
def _make_shell_string(self, s):
return "'%s'" % re.sub(
"'", r
"'\''", s)
def _setup_objdir(self, args):
# reftest imports will happen from the objdir
sys.path.insert(0, self.reftest_dir)
tests = os.path.join(self.reftest_dir,
"tests")
if not os.path.isdir(tests)
and not os.path.islink(tests):
# This symbolic link is used by the desktop tests to
# locate the actual test files when running using file:.
os.symlink(self.topsrcdir, tests)
def run_desktop_test(self, **kwargs):
"""Runs a reftest, in desktop Firefox."""
import runreftest
args = Namespace(**kwargs)
if args.suite
not in (
"reftest",
"crashtest",
"jstestbrowser"):
raise Exception(
"None or unrecognized reftest suite type.")
default_manifest = {
"reftest": (self.topsrcdir,
"layout",
"reftests",
"reftest.list"),
"crashtest": (self.topsrcdir,
"testing",
"crashtest",
"crashtests.list"),
"jstestbrowser": (
self.topobjdir,
"dist",
"test-stage",
"jsreftest",
"tests",
"js",
"src",
"tests",
"jstests.list",
),
}
args.extraProfileFiles.append(os.path.join(self.topobjdir,
"dist",
"plugins"))
args.symbolsPath = os.path.join(self.topobjdir,
"dist",
"crashreporter-symbols")
args.sandboxReadWhitelist.extend([self.topsrcdir, self.topobjdir])
if not args.tests:
args.tests = [os.path.join(*default_manifest[args.suite])]
if args.suite ==
"jstestbrowser":
args.extraProfileFiles.append(
os.path.join(
self.topobjdir,
"dist",
"test-stage",
"jsreftest",
"tests",
"js",
"src",
"tests",
"user.js",
)
)
self.log_manager.enable_unstructured()
try:
rv = runreftest.run_test_harness(parser, args)
finally:
self.log_manager.disable_unstructured()
return rv
def run_android_test(self, **kwargs):
"""Runs a reftest, in an Android application."""
args = Namespace(**kwargs)
if args.suite
not in (
"reftest",
"crashtest",
"jstestbrowser"):
raise Exception(
"None or unrecognized reftest suite type.")
self._setup_objdir(args)
import remotereftest
default_manifest = {
"reftest": (self.topsrcdir,
"layout",
"reftests",
"reftest.list"),
"crashtest": (self.topsrcdir,
"testing",
"crashtest",
"crashtests.list"),
"jstestbrowser": (
self.topobjdir,
"dist",
"test-stage",
"jsreftest",
"tests",
"js",
"src",
"tests",
"jstests.list",
),
}
if not args.tests:
args.tests = [os.path.join(*default_manifest[args.suite])]
args.extraProfileFiles.append(
os.path.join(self.topsrcdir,
"mobile",
"android",
"fonts")
)
hyphenation_path = os.path.join(self.topsrcdir,
"intl",
"locales")
for dirpath, dirnames, filenames
in os.walk(hyphenation_path):
for filename
in filenames:
if filename.endswith(
".dic"):
args.extraProfileFiles.append(os.path.join(dirpath, filename))
if not args.httpdPath:
args.httpdPath = os.path.join(self.tests_dir,
"modules")
if not args.symbolsPath:
args.symbolsPath = os.path.join(self.topobjdir,
"crashreporter-symbols")
if not args.xrePath:
args.xrePath = os.environ.get(
"MOZ_HOST_BIN")
if not args.app:
args.app =
"org.mozilla.geckoview.test_runner"
if not args.utilityPath:
args.utilityPath = args.xrePath
args.ignoreWindowSize =
True
from mozrunner.devices.android_device
import get_adb_path
if not args.adb_path:
args.adb_path = get_adb_path(self)
if "geckoview" not in args.app:
args.e10s =
False
print(
"using e10s=False for non-geckoview app")
# A symlink and some path manipulations are required so that test
# manifests can be found both locally and remotely (via a url)
# using the same relative path.
if args.suite ==
"jstestbrowser":
staged_js_dir = os.path.join(
self.topobjdir,
"dist",
"test-stage",
"jsreftest"
)
tests = os.path.join(self.reftest_dir,
"jsreftest")
if not os.path.isdir(tests)
and not os.path.islink(tests):
os.symlink(staged_js_dir, tests)
args.extraProfileFiles.append(
os.path.join(staged_js_dir,
"tests",
"js",
"src",
"tests",
"user.js")
)
else:
tests = os.path.join(self.reftest_dir,
"tests")
if not os.path.isdir(tests)
and not os.path.islink(tests):
os.symlink(self.topsrcdir, tests)
for i, path
in enumerate(args.tests):
# Non-absolute paths are relative to the packaged directory, which
# has an extra tests/ at the start
if os.path.exists(os.path.abspath(path)):
path = os.path.relpath(path, os.path.join(self.topsrcdir))
args.tests[i] = os.path.join(
"tests", path)
self.log_manager.enable_unstructured()
try:
rv = remotereftest.run_test_harness(parser, args)
finally:
self.log_manager.disable_unstructured()
return rv
def process_test_objects(kwargs):
"""|mach test| works by providing a test_objects argument, from
which the test path must be extracted
and converted into a normal
reftest tests argument.
"""
if "test_objects" in kwargs:
if kwargs[
"tests"]
is None:
kwargs[
"tests"] = []
kwargs[
"tests"].extend(item[
"path"]
for item
in kwargs[
"test_objects"])
del kwargs[
"test_objects"]
def get_parser():
import reftestcommandline
global parser
here = os.path.abspath(os.path.dirname(__file__))
build_obj = MozbuildObject.from_environment(cwd=here)
if conditions.is_android(build_obj):
parser = reftestcommandline.RemoteArgumentsParser()
else:
parser = reftestcommandline.DesktopArgumentsParser()
return parser
@Command(
"reftest",
category=
"testing",
description=
"Run reftests (layout and graphics correctness).",
parser=get_parser,
)
def run_reftest(command_context, **kwargs):
kwargs[
"suite"] =
"reftest"
return _run_reftest(command_context, **kwargs)
@Command(
"jstestbrowser",
category=
"testing",
description=
"Run js/src/tests in the browser.",
parser=get_parser,
)
def run_jstestbrowser(command_context, **kwargs):
if command_context.substs.get(
"JS_DISABLE_SHELL"):
raise Exception(
"jstestbrowser requires --enable-js-shell be specified in mozconfig."
)
command_context._mach_context.commands.dispatch(
"build", command_context._mach_context, what=[
"stage-jstests"]
)
kwargs[
"suite"] =
"jstestbrowser"
return _run_reftest(command_context, **kwargs)
@Command(
"crashtest",
category=
"testing",
description=
"Run crashtests (Check if crashes on a page).",
parser=get_parser,
)
def run_crashtest(command_context, **kwargs):
kwargs[
"suite"] =
"crashtest"
return _run_reftest(command_context, **kwargs)
def _run_reftest(command_context, **kwargs):
kwargs[
"topsrcdir"] = command_context.topsrcdir
process_test_objects(kwargs)
reftest = command_context._spawn(ReftestRunner)
# Unstructured logging must be enabled prior to calling
# adb which uses an unstructured logger in its constructor.
reftest.log_manager.enable_unstructured()
if conditions.is_android(command_context):
from mozrunner.devices.android_device
import (
InstallIntent,
verify_android_device,
)
install = InstallIntent.NO
if kwargs.get(
"no_install")
else InstallIntent.YES
verbose =
False
if (
kwargs.get(
"log_mach_verbose")
or kwargs.get(
"log_tbpl_level") ==
"debug"
or kwargs.get(
"log_mach_level") ==
"debug"
or kwargs.get(
"log_raw_level") ==
"debug"
):
verbose =
True
verify_android_device(
command_context,
install=install,
xre=
True,
network=
True,
app=kwargs[
"app"],
device_serial=kwargs[
"deviceSerial"],
verbose=verbose,
)
return reftest.run_android_test(**kwargs)
return reftest.run_desktop_test(**kwargs)