Bug 1739680 [wpt PR 31525] - Move some tests to external/wpt/web-animations/responsiv...
[gecko.git] / testing / xpcshell / mach_commands.py
blob87f713e8a81ae249025f38dea5c3772920a24929
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 # Integrates the xpcshell test runner with mach.
7 from __future__ import absolute_import, division, print_function, unicode_literals
9 import errno
10 import logging
11 import os
12 import sys
14 from mozlog import structured
16 from mozbuild.base import (
17 MozbuildObject,
18 MachCommandConditions as conditions,
19 BinaryNotFoundException,
22 from mach.decorators import (
23 Command,
26 from multiprocessing import cpu_count
27 from xpcshellcommandline import parser_desktop, parser_remote
29 here = os.path.abspath(os.path.dirname(__file__))
32 # This should probably be consolidated with similar classes in other test
33 # runners.
34 class InvalidTestPathError(Exception):
35 """Exception raised when the test path is not valid."""
38 class XPCShellRunner(MozbuildObject):
39 """Run xpcshell tests."""
41 def run_suite(self, **kwargs):
42 return self._run_xpcshell_harness(**kwargs)
44 def run_test(self, **kwargs):
45 """Runs an individual xpcshell test."""
47 # TODO Bug 794506 remove once mach integrates with virtualenv.
48 build_path = os.path.join(self.topobjdir, "build")
49 if build_path not in sys.path:
50 sys.path.append(build_path)
52 src_build_path = os.path.join(self.topsrcdir, "mozilla", "build")
53 if os.path.isdir(src_build_path):
54 sys.path.append(src_build_path)
56 return self.run_suite(**kwargs)
58 def _run_xpcshell_harness(self, **kwargs):
59 # Obtain a reference to the xpcshell test runner.
60 import runxpcshelltests
62 log = kwargs.pop("log")
64 xpcshell = runxpcshelltests.XPCShellTests(log=log)
65 self.log_manager.enable_unstructured()
67 tests_dir = os.path.join(self.topobjdir, "_tests", "xpcshell")
68 # We want output from the test to be written immediately if we are only
69 # running a single test.
70 single_test = (
71 len(kwargs["testPaths"]) == 1
72 and os.path.isfile(kwargs["testPaths"][0])
73 or kwargs["manifest"]
74 and (len(kwargs["manifest"].test_paths()) == 1)
77 if single_test:
78 kwargs["verbose"] = True
80 if kwargs["xpcshell"] is None:
81 try:
82 kwargs["xpcshell"] = self.get_binary_path("xpcshell")
83 except BinaryNotFoundException as e:
84 self.log(
85 logging.ERROR, "xpcshell-test", {"error": str(e)}, "ERROR: {error}"
87 self.log(logging.INFO, "xpcshell-test", {"help": e.help()}, "{help}")
88 return 1
90 if kwargs["mozInfo"] is None:
91 kwargs["mozInfo"] = os.path.join(self.topobjdir, "mozinfo.json")
93 if kwargs["symbolsPath"] is None:
94 kwargs["symbolsPath"] = os.path.join(self.distdir, "crashreporter-symbols")
96 if kwargs["logfiles"] is None:
97 kwargs["logfiles"] = False
99 if kwargs["profileName"] is None:
100 kwargs["profileName"] = "firefox"
102 if kwargs["pluginsPath"] is None:
103 kwargs["pluginsPath"] = os.path.join(self.distdir, "plugins")
105 if kwargs["testingModulesDir"] is None:
106 kwargs["testingModulesDir"] = os.path.join(self.topobjdir, "_tests/modules")
108 if kwargs["utility_path"] is None:
109 kwargs["utility_path"] = self.bindir
111 if kwargs["manifest"] is None:
112 kwargs["manifest"] = os.path.join(tests_dir, "xpcshell.ini")
114 if kwargs["failure_manifest"] is None:
115 kwargs["failure_manifest"] = os.path.join(
116 self.statedir, "xpcshell.failures.ini"
119 # Use the object directory for the temp directory to minimize the chance
120 # of file scanning. The overhead from e.g. search indexers and anti-virus
121 # scanners like Windows Defender can add tons of overhead to test execution.
122 # We encourage people to disable these things in the object directory.
123 temp_dir = os.path.join(self.topobjdir, "temp")
124 try:
125 os.mkdir(temp_dir)
126 except OSError as e:
127 if e.errno != errno.EEXIST:
128 raise
129 kwargs["tempDir"] = temp_dir
131 result = xpcshell.runTests(kwargs)
133 self.log_manager.disable_unstructured()
135 if not result and not xpcshell.sequential:
136 print(
137 "Tests were run in parallel. Try running with --sequential "
138 "to make sure the failures were not caused by this."
140 return int(not result)
143 class AndroidXPCShellRunner(MozbuildObject):
144 """Run Android xpcshell tests."""
146 def run_test(self, **kwargs):
147 # TODO Bug 794506 remove once mach integrates with virtualenv.
148 build_path = os.path.join(self.topobjdir, "build")
149 if build_path not in sys.path:
150 sys.path.append(build_path)
152 import remotexpcshelltests
154 log = kwargs.pop("log")
155 self.log_manager.enable_unstructured()
157 if kwargs["xpcshell"] is None:
158 kwargs["xpcshell"] = "xpcshell"
160 if not kwargs["objdir"]:
161 kwargs["objdir"] = self.topobjdir
163 if not kwargs["localBin"]:
164 kwargs["localBin"] = os.path.join(self.topobjdir, "dist/bin")
166 if not kwargs["testingModulesDir"]:
167 kwargs["testingModulesDir"] = os.path.join(self.topobjdir, "_tests/modules")
169 if not kwargs["mozInfo"]:
170 kwargs["mozInfo"] = os.path.join(self.topobjdir, "mozinfo.json")
172 if not kwargs["manifest"]:
173 kwargs["manifest"] = os.path.join(
174 self.topobjdir, "_tests/xpcshell/xpcshell.ini"
177 if not kwargs["symbolsPath"]:
178 kwargs["symbolsPath"] = os.path.join(self.distdir, "crashreporter-symbols")
180 if self.substs.get("MOZ_BUILD_APP") == "b2g":
181 kwargs["localAPK"] = None
182 elif not kwargs["localAPK"]:
183 for root, _, paths in os.walk(os.path.join(kwargs["objdir"], "gradle")):
184 for file_name in paths:
185 if file_name.endswith(".apk") and file_name.startswith(
186 "test_runner-withGeckoBinaries"
188 kwargs["localAPK"] = os.path.join(root, file_name)
189 print("using APK: %s" % kwargs["localAPK"])
190 break
191 if kwargs["localAPK"]:
192 break
193 else:
194 raise Exception("APK not found in objdir. You must specify an APK.")
196 xpcshell = remotexpcshelltests.XPCShellRemote(kwargs, log)
198 result = xpcshell.runTests(
199 kwargs,
200 testClass=remotexpcshelltests.RemoteXPCShellTestThread,
201 mobileArgs=xpcshell.mobileArgs,
204 self.log_manager.disable_unstructured()
206 return int(not result)
209 def get_parser():
210 build_obj = MozbuildObject.from_environment(cwd=here)
211 if (
212 conditions.is_android(build_obj)
213 or build_obj.substs.get("MOZ_BUILD_APP") == "b2g"
215 return parser_remote()
216 else:
217 return parser_desktop()
220 @Command(
221 "xpcshell-test",
222 category="testing",
223 description="Run XPCOM Shell tests (API direct unit testing)",
224 conditions=[lambda *args: True],
225 parser=get_parser,
227 def run_xpcshell_test(command_context, test_objects=None, **params):
228 from mozbuild.controller.building import BuildDriver
230 if test_objects is not None:
231 from manifestparser import TestManifest
233 m = TestManifest()
234 m.tests.extend(test_objects)
235 params["manifest"] = m
237 driver = command_context._spawn(BuildDriver)
238 driver.install_tests()
240 # We should probably have a utility function to ensure the tree is
241 # ready to run tests. Until then, we just create the state dir (in
242 # case the tree wasn't built with mach).
243 command_context._ensure_state_subdir_exists(".")
245 if not params.get("log"):
246 log_defaults = {
247 command_context._mach_context.settings["test"]["format"]: sys.stdout
249 fmt_defaults = {
250 "level": command_context._mach_context.settings["test"]["level"],
251 "verbose": True,
253 params["log"] = structured.commandline.setup_logging(
254 "XPCShellTests", params, log_defaults, fmt_defaults
257 if not params["threadCount"]:
258 # pylint --py3k W1619
259 params["threadCount"] = int((cpu_count() * 3) / 2)
261 if (
262 conditions.is_android(command_context)
263 or command_context.substs.get("MOZ_BUILD_APP") == "b2g"
265 from mozrunner.devices.android_device import (
266 verify_android_device,
267 get_adb_path,
268 InstallIntent,
271 install = InstallIntent.YES if params["setup"] else InstallIntent.NO
272 device_serial = params.get("deviceSerial")
273 verify_android_device(
274 command_context,
275 network=True,
276 install=install,
277 device_serial=device_serial,
279 if not params["adbPath"]:
280 params["adbPath"] = get_adb_path(command_context)
281 xpcshell = command_context._spawn(AndroidXPCShellRunner)
282 else:
283 xpcshell = command_context._spawn(XPCShellRunner)
284 xpcshell.cwd = command_context._mach_context.cwd
286 try:
287 return xpcshell.run_test(**params)
288 except InvalidTestPathError as e:
289 print(str(e))
290 return 1