Source code
Revision control
Copy as Markdown
Other Tools
# 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
import filecmp
import os
import shutil
from collections import defaultdict
from pathlib import Path
from mozperftest.layers import Layer
from mozperftest.utils import NoPerfMetricsError, temp_dir
def copy_tree_update(src_path, dst_path):
for src_file in src_path.rglob("*"):
dst_file = dst_path / src_file.relative_to(src_path)
if src_file.is_dir() and not dst_file.exists():
dst_file.mkdir(parents=True)
elif not dst_file.exists() or not filecmp.cmp(
src_file, dst_file, shallow=False
):
dst_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src_file, dst_file)
class XPCShellTestError(Exception):
pass
class XPCShellData:
def open_data(self, data):
return {
"name": "xpcshell",
"subtest": data["name"],
"data": [
{"file": "xpcshell", "value": value, "xaxis": xaxis}
for xaxis, value in enumerate(data["values"])
],
}
def transform(self, data):
return data
merge = transform
class XPCShell(Layer):
"""Runs an xpcshell test."""
name = "xpcshell"
activated = True
arguments = {
"cycles": {"type": int, "default": 13, "help": "Number of full cycles"},
"binary": {
"type": str,
"default": None,
"help": (
"xpcshell binary path. If not provided, "
"looks for it in the source tree."
),
},
"mozinfo": {
"type": str,
"default": None,
"help": (
"mozinfo binary path. If not provided, looks for it in the obj tree."
),
},
"xre-path": {"type": str, "default": None, "help": "XRE path."},
"nodejs": {"type": str, "default": None, "help": "nodejs binary path."},
}
def __init__(self, env, mach_cmd):
super(XPCShell, self).__init__(env, mach_cmd)
self.topsrcdir = mach_cmd.topsrcdir
self._mach_context = mach_cmd._mach_context
self.python_path = mach_cmd.virtualenv_manager.python_path
self.topobjdir = mach_cmd.topobjdir
self.distdir = mach_cmd.distdir
self.bindir = mach_cmd.bindir
self.statedir = mach_cmd.statedir
self.metrics = []
self.topsrcdir = mach_cmd.topsrcdir
def setup(self):
pass
def run(self, metadata):
test = Path(metadata.script["filename"])
# let's grab the manifest
manifest = Path(test.parent, "xpcshell.ini")
if not manifest.exists():
manifest = Path(test.parent, "xpcshell.toml")
if not manifest.exists():
raise FileNotFoundError(str(manifest))
nodejs = self.get_arg("nodejs")
if nodejs is not None:
os.environ["MOZ_NODE_PATH"] = nodejs
import runxpcshelltests
verbose = self.get_arg("verbose")
xpcshell = runxpcshelltests.XPCShellTests(log=self)
kwargs = {}
kwargs["testPaths"] = test.name
kwargs["verbose"] = verbose
binary = self.get_arg("xpcshell_binary")
if binary is None:
binary = self.mach_cmd.get_binary_path("xpcshell")
kwargs["xpcshell"] = binary
binary = Path(binary)
mozinfo = self.get_arg("mozinfo")
if mozinfo is None:
mozinfo = binary.parent / ".." / "mozinfo.json"
if not mozinfo.exists():
mozinfo = Path(self.topobjdir, "mozinfo.json")
else:
mozinfo = Path(mozinfo)
kwargs["mozInfo"] = str(mozinfo)
kwargs["symbolsPath"] = str(Path(self.distdir, "crashreporter-symbols"))
kwargs["logfiles"] = True
kwargs["profileName"] = "firefox"
plugins = binary.parent / "plugins"
if not plugins.exists():
plugins = Path(self.distdir, "plugins")
kwargs["pluginsPath"] = str(plugins)
modules = Path(self.topobjdir, "_tests", "modules")
if not modules.exists():
modules = binary.parent / "modules"
kwargs["testingModulesDir"] = str(modules)
kwargs["utility_path"] = self.bindir
kwargs["manifest"] = str(manifest)
kwargs["totalChunks"] = 1
xre_path = self.get_arg("xre-path")
if xre_path is not None:
self.info(f"Copying {xre_path} elements to {binary.parent}")
copy_tree_update(Path(xre_path), binary.parent)
http3server = binary.parent / "http3server"
if http3server.exists():
kwargs["http3server"] = str(http3server)
cycles = self.get_arg("cycles", 1)
self.info("Running %d cycles" % cycles)
for cycle in range(cycles):
self.info("Cycle %d" % (cycle + 1))
with temp_dir() as tmp:
kwargs["tempDir"] = tmp
if not xpcshell.runTests(kwargs):
raise XPCShellTestError()
self.info("tests done.")
results = defaultdict(list)
for m in self.metrics:
for key, val in m.items():
results[key].append(val)
if len(results.items()) == 0:
raise NoPerfMetricsError("xpcshell")
metadata.add_result(
{
"name": test.name,
"framework": {"name": "mozperftest"},
"transformer": "mozperftest.test.xpcshell:XPCShellData",
"results": [
{"values": measures, "name": subtest}
for subtest, measures in results.items()
],
}
)
return metadata
def log_raw(self, data, **kw):
if data["action"] != "log":
return
if data["message"].strip('"') != "perfMetrics":
self.info(data["message"])
return
self.metrics.append(data["extra"])
def process_output(self, procid, line, command):
self.info(line)
def dummy(self, *args, **kw):
pass
test_end = suite_start = suite_end = test_start = dummy