123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- # 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/.
- # Integrates the xpcshell test runner with mach.
- from __future__ import absolute_import, unicode_literals, print_function
- import argparse
- import errno
- import os
- import sys
- from mozlog import structured
- from mozbuild.base import (
- MachCommandBase,
- MozbuildObject,
- MachCommandConditions as conditions,
- )
- from mach.decorators import (
- CommandProvider,
- Command,
- )
- from xpcshellcommandline import parser_desktop, parser_remote
- here = os.path.abspath(os.path.dirname(__file__))
- if sys.version_info[0] < 3:
- unicode_type = unicode
- else:
- unicode_type = str
- # This should probably be consolidated with similar classes in other test
- # runners.
- class InvalidTestPathError(Exception):
- """Exception raised when the test path is not valid."""
- class XPCShellRunner(MozbuildObject):
- """Run xpcshell tests."""
- def run_suite(self, **kwargs):
- return self._run_xpcshell_harness(**kwargs)
- def run_test(self, **kwargs):
- """Runs an individual xpcshell test."""
- # 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)
- src_build_path = os.path.join(self.topsrcdir, 'mozilla', 'build')
- if os.path.isdir(src_build_path):
- sys.path.append(src_build_path)
- return self.run_suite(**kwargs)
- def _run_xpcshell_harness(self, **kwargs):
- # Obtain a reference to the xpcshell test runner.
- import runxpcshelltests
- log = kwargs.pop("log")
- xpcshell = runxpcshelltests.XPCShellTests(log=log)
- self.log_manager.enable_unstructured()
- tests_dir = os.path.join(self.topobjdir, '_tests', 'xpcshell')
- # We want output from the test to be written immediately if we are only
- # running a single test.
- single_test = (len(kwargs["testPaths"]) == 1 and
- os.path.isfile(kwargs["testPaths"][0]) or
- kwargs["manifest"] and
- (len(kwargs["manifest"].test_paths()) == 1))
- if single_test:
- kwargs["verbose"] = True
- if kwargs["xpcshell"] is None:
- kwargs["xpcshell"] = self.get_binary_path('xpcshell')
- if kwargs["mozInfo"] is None:
- kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json')
- if kwargs["symbolsPath"] is None:
- kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols')
- if kwargs["logfiles"] is None:
- kwargs["logfiles"] = False
- if kwargs["profileName"] is None:
- kwargs["profileName"] = "firefox"
- if kwargs["pluginsPath"] is None:
- kwargs['pluginsPath'] = os.path.join(self.distdir, 'plugins')
- if kwargs["testingModulesDir"] is None:
- kwargs["testingModulesDir"] = os.path.join(self.topobjdir, '_tests/modules')
- if kwargs["utility_path"] is None:
- kwargs['utility_path'] = self.bindir
- if kwargs["manifest"] is None:
- kwargs["manifest"] = os.path.join(tests_dir, "xpcshell.ini")
- if kwargs["failure_manifest"] is None:
- kwargs["failure_manifest"] = os.path.join(self.statedir, 'xpcshell.failures.ini')
- # Use the object directory for the temp directory to minimize the chance
- # of file scanning. The overhead from e.g. search indexers and anti-virus
- # scanners like Windows Defender can add tons of overhead to test execution.
- # We encourage people to disable these things in the object directory.
- temp_dir = os.path.join(self.topobjdir, 'temp')
- try:
- os.mkdir(temp_dir)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- kwargs['tempDir'] = temp_dir
- # Python through 2.7.2 has issues with unicode in some of the
- # arguments. Work around that.
- filtered_args = {}
- for k, v in kwargs.iteritems():
- if isinstance(v, unicode_type):
- v = v.encode('utf-8')
- if isinstance(k, unicode_type):
- k = k.encode('utf-8')
- filtered_args[k] = v
- result = xpcshell.runTests(**filtered_args)
- self.log_manager.disable_unstructured()
- if not result and not xpcshell.sequential:
- print("Tests were run in parallel. Try running with --sequential "
- "to make sure the failures were not caused by this.")
- return int(not result)
- class AndroidXPCShellRunner(MozbuildObject):
- """Get specified DeviceManager"""
- def get_devicemanager(self, devicemanager, ip, port, remote_test_root):
- import mozdevice
- dm = None
- if devicemanager == "adb":
- if ip:
- dm = mozdevice.DroidADB(ip, port, packageName=None, deviceRoot=remote_test_root)
- else:
- dm = mozdevice.DroidADB(packageName=None, deviceRoot=remote_test_root)
- else:
- if ip:
- dm = mozdevice.DroidSUT(ip, port, deviceRoot=remote_test_root)
- else:
- raise Exception("You must provide a device IP to connect to via the --ip option")
- return dm
- """Run Android xpcshell tests."""
- def run_test(self, **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)
- import remotexpcshelltests
- dm = self.get_devicemanager(kwargs["dm_trans"], kwargs["deviceIP"], kwargs["devicePort"],
- kwargs["remoteTestRoot"])
- log = kwargs.pop("log")
- self.log_manager.enable_unstructured()
- if kwargs["xpcshell"] is None:
- kwargs["xpcshell"] = "xpcshell"
- if not kwargs["objdir"]:
- kwargs["objdir"] = self.topobjdir
- if not kwargs["localLib"]:
- kwargs["localLib"] = os.path.join(self.topobjdir, 'dist/fennec')
- if not kwargs["localBin"]:
- kwargs["localBin"] = os.path.join(self.topobjdir, 'dist/bin')
- if not kwargs["testingModulesDir"]:
- kwargs["testingModulesDir"] = os.path.join(self.topobjdir, '_tests/modules')
- if not kwargs["mozInfo"]:
- kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json')
- if not kwargs["manifest"]:
- kwargs["manifest"] = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini')
- if not kwargs["symbolsPath"]:
- kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols')
- if not kwargs["localAPK"]:
- for file_name in os.listdir(os.path.join(kwargs["objdir"], "dist")):
- if file_name.endswith(".apk") and file_name.startswith("fennec"):
- kwargs["localAPK"] = os.path.join(kwargs["objdir"], "dist", file_name)
- print ("using APK: %s" % kwargs["localAPK"])
- break
- else:
- raise Exception("APK not found in objdir. You must specify an APK.")
- if not kwargs["sequential"]:
- kwargs["sequential"] = True
- options = argparse.Namespace(**kwargs)
- xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, log)
- result = xpcshell.runTests(testClass=remotexpcshelltests.RemoteXPCShellTestThread,
- mobileArgs=xpcshell.mobileArgs,
- **vars(options))
- self.log_manager.disable_unstructured()
- return int(not result)
- def get_parser():
- build_obj = MozbuildObject.from_environment(cwd=here)
- if conditions.is_android(build_obj):
- return parser_remote()
- else:
- return parser_desktop()
- @CommandProvider
- class MachCommands(MachCommandBase):
- @Command('xpcshell-test', category='testing',
- description='Run XPCOM Shell tests (API direct unit testing)',
- conditions=[lambda *args: True],
- parser=get_parser)
- def run_xpcshell_test(self, test_objects=None, **params):
- from mozbuild.controller.building import BuildDriver
- if test_objects is not None:
- from manifestparser import TestManifest
- m = TestManifest()
- m.tests.extend(test_objects)
- params['manifest'] = m
- driver = self._spawn(BuildDriver)
- driver.install_tests(test_objects)
- # We should probably have a utility function to ensure the tree is
- # ready to run tests. Until then, we just create the state dir (in
- # case the tree wasn't built with mach).
- self._ensure_state_subdir_exists('.')
- params['log'] = structured.commandline.setup_logging("XPCShellTests",
- params,
- {"mach": sys.stdout},
- {"verbose": True})
- if conditions.is_android(self):
- from mozrunner.devices.android_device import verify_android_device
- verify_android_device(self)
- xpcshell = self._spawn(AndroidXPCShellRunner)
- else:
- xpcshell = self._spawn(XPCShellRunner)
- xpcshell.cwd = self._mach_context.cwd
- try:
- return xpcshell.run_test(**params)
- except InvalidTestPathError as e:
- print(e.message)
- return 1
|