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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
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