mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 23:37:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
831
testing/mach_commands.py
Normal file
831
testing/mach_commands.py
Normal file
|
|
@ -0,0 +1,831 @@
|
|||
# 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/.
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import subprocess
|
||||
import shutil
|
||||
from collections import defaultdict
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.base import MachCommandConditions as conditions
|
||||
import mozpack.path as mozpath
|
||||
from argparse import ArgumentParser
|
||||
|
||||
UNKNOWN_TEST = '''
|
||||
I was unable to find tests from the given argument(s).
|
||||
|
||||
You should specify a test directory, filename, test suite name, or
|
||||
abbreviation. If no arguments are given, there must be local file
|
||||
changes and corresponding IMPACTED_TESTS annotations in moz.build
|
||||
files relevant to those files.
|
||||
|
||||
It's possible my little brain doesn't know about the type of test you are
|
||||
trying to execute. If you suspect this, please request support by filing
|
||||
a bug at
|
||||
https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=General.
|
||||
'''.strip()
|
||||
|
||||
UNKNOWN_FLAVOR = '''
|
||||
I know you are trying to run a %s test. Unfortunately, I can't run those
|
||||
tests yet. Sorry!
|
||||
'''.strip()
|
||||
|
||||
MOCHITEST_CHUNK_BY_DIR = 4
|
||||
MOCHITEST_TOTAL_CHUNKS = 5
|
||||
|
||||
TEST_SUITES = {
|
||||
'cppunittest': {
|
||||
'aliases': ('Cpp', 'cpp'),
|
||||
'mach_command': 'cppunittest',
|
||||
'kwargs': {'test_file': None},
|
||||
},
|
||||
'crashtest': {
|
||||
'aliases': ('C', 'Rc', 'RC', 'rc'),
|
||||
'mach_command': 'crashtest',
|
||||
'kwargs': {'test_file': None},
|
||||
},
|
||||
'firefox-ui-functional': {
|
||||
'aliases': ('Fxfn',),
|
||||
'mach_command': 'firefox-ui-functional',
|
||||
'kwargs': {},
|
||||
},
|
||||
'firefox-ui-update': {
|
||||
'aliases': ('Fxup',),
|
||||
'mach_command': 'firefox-ui-update',
|
||||
'kwargs': {},
|
||||
},
|
||||
'jetpack': {
|
||||
'aliases': ('J',),
|
||||
'mach_command': 'jetpack-test',
|
||||
'kwargs': {},
|
||||
},
|
||||
'check-spidermonkey': {
|
||||
'aliases': ('Sm', 'sm'),
|
||||
'mach_command': 'check-spidermonkey',
|
||||
'kwargs': {'valgrind': False},
|
||||
},
|
||||
'mochitest-a11y': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'a11y', 'test_paths': None},
|
||||
},
|
||||
'mochitest-browser': {
|
||||
'aliases': ('bc', 'BC', 'Bc'),
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'browser-chrome', 'test_paths': None},
|
||||
},
|
||||
'mochitest-chrome': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'chrome', 'test_paths': None},
|
||||
},
|
||||
'mochitest-devtools': {
|
||||
'aliases': ('dt', 'DT', 'Dt'),
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'subsuite': 'devtools', 'test_paths': None},
|
||||
},
|
||||
'mochitest-plain': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'plain', 'test_paths': None},
|
||||
},
|
||||
'python': {
|
||||
'mach_command': 'python-test',
|
||||
'kwargs': {'tests': None},
|
||||
},
|
||||
'reftest': {
|
||||
'aliases': ('RR', 'rr', 'Rr'),
|
||||
'mach_command': 'reftest',
|
||||
'kwargs': {'tests': None},
|
||||
},
|
||||
'web-platform-tests': {
|
||||
'aliases': ('wpt',),
|
||||
'mach_command': 'web-platform-tests',
|
||||
'kwargs': {}
|
||||
},
|
||||
'valgrind': {
|
||||
'aliases': ('V', 'v'),
|
||||
'mach_command': 'valgrind-test',
|
||||
'kwargs': {},
|
||||
},
|
||||
'xpcshell': {
|
||||
'aliases': ('X', 'x'),
|
||||
'mach_command': 'xpcshell-test',
|
||||
'kwargs': {'test_file': 'all'},
|
||||
},
|
||||
}
|
||||
|
||||
# Maps test flavors to metadata on how to run that test.
|
||||
TEST_FLAVORS = {
|
||||
'a11y': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'a11y', 'test_paths': []},
|
||||
},
|
||||
'browser-chrome': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'browser-chrome', 'test_paths': []},
|
||||
},
|
||||
'crashtest': {},
|
||||
'chrome': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'chrome', 'test_paths': []},
|
||||
},
|
||||
'firefox-ui-functional': {
|
||||
'mach_command': 'firefox-ui-functional',
|
||||
'kwargs': {'tests': []},
|
||||
},
|
||||
'firefox-ui-update': {
|
||||
'mach_command': 'firefox-ui-update',
|
||||
'kwargs': {'tests': []},
|
||||
},
|
||||
'marionette': {
|
||||
'mach_command': 'marionette-test',
|
||||
'kwargs': {'tests': []},
|
||||
},
|
||||
'mochitest': {
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {'flavor': 'mochitest', 'test_paths': []},
|
||||
},
|
||||
'python': {
|
||||
'mach_command': 'python-test',
|
||||
'kwargs': {},
|
||||
},
|
||||
'reftest': {
|
||||
'mach_command': 'reftest',
|
||||
'kwargs': {'tests': []}
|
||||
},
|
||||
'steeplechase': {},
|
||||
'web-platform-tests': {
|
||||
'mach_command': 'web-platform-tests',
|
||||
'kwargs': {'include': []}
|
||||
},
|
||||
'xpcshell': {
|
||||
'mach_command': 'xpcshell-test',
|
||||
'kwargs': {'test_paths': []},
|
||||
},
|
||||
}
|
||||
|
||||
for i in range(1, MOCHITEST_TOTAL_CHUNKS + 1):
|
||||
TEST_SUITES['mochitest-%d' %i] = {
|
||||
'aliases': ('M%d' % i, 'm%d' % i),
|
||||
'mach_command': 'mochitest',
|
||||
'kwargs': {
|
||||
'flavor': 'mochitest',
|
||||
'subsuite': 'default',
|
||||
'chunk_by_dir': MOCHITEST_CHUNK_BY_DIR,
|
||||
'total_chunks': MOCHITEST_TOTAL_CHUNKS,
|
||||
'this_chunk': i,
|
||||
'test_paths': None,
|
||||
},
|
||||
}
|
||||
|
||||
TEST_HELP = '''
|
||||
Test or tests to run. Tests can be specified by filename, directory, suite
|
||||
name or suite alias.
|
||||
|
||||
The following test suites and aliases are supported: %s
|
||||
''' % ', '.join(sorted(TEST_SUITES))
|
||||
TEST_HELP = TEST_HELP.strip()
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Test(MachCommandBase):
|
||||
@Command('test', category='testing', description='Run tests (detects the kind of test and runs it).')
|
||||
@CommandArgument('what', default=None, nargs='*', help=TEST_HELP)
|
||||
def test(self, what):
|
||||
"""Run tests from names or paths.
|
||||
|
||||
mach test accepts arguments specifying which tests to run. Each argument
|
||||
can be:
|
||||
|
||||
* The path to a test file
|
||||
* A directory containing tests
|
||||
* A test suite name
|
||||
* An alias to a test suite name (codes used on TreeHerder)
|
||||
|
||||
If no input is provided, tests will be run based on files changed in
|
||||
the local tree. Relevant tests, tags, or flavors are determined by
|
||||
IMPACTED_TESTS annotations in moz.build files relevant to the
|
||||
changed files.
|
||||
|
||||
When paths or directories are given, they are first resolved to test
|
||||
files known to the build system.
|
||||
|
||||
If resolved tests belong to more than one test type/flavor/harness,
|
||||
the harness for each relevant type/flavor will be invoked. e.g. if
|
||||
you specify a directory with xpcshell and browser chrome mochitests,
|
||||
both harnesses will be invoked.
|
||||
"""
|
||||
from mozbuild.testing import TestResolver
|
||||
|
||||
# Parse arguments and assemble a test "plan."
|
||||
run_suites = set()
|
||||
run_tests = []
|
||||
resolver = self._spawn(TestResolver)
|
||||
|
||||
for entry in what:
|
||||
# If the path matches the name or alias of an entire suite, run
|
||||
# the entire suite.
|
||||
if entry in TEST_SUITES:
|
||||
run_suites.add(entry)
|
||||
continue
|
||||
suitefound = False
|
||||
for suite, v in TEST_SUITES.items():
|
||||
if entry in v.get('aliases', []):
|
||||
run_suites.add(suite)
|
||||
suitefound = True
|
||||
if suitefound:
|
||||
continue
|
||||
|
||||
# Now look for file/directory matches in the TestResolver.
|
||||
relpath = self._wrap_path_argument(entry).relpath()
|
||||
tests = list(resolver.resolve_tests(paths=[relpath]))
|
||||
run_tests.extend(tests)
|
||||
|
||||
if not tests:
|
||||
print('UNKNOWN TEST: %s' % entry, file=sys.stderr)
|
||||
|
||||
if not what:
|
||||
# TODO: This isn't really related to try, and should be
|
||||
# extracted to a common library for vcs interactions when it is
|
||||
# introduced in bug 1185599.
|
||||
from autotry import AutoTry
|
||||
at = AutoTry(self.topsrcdir, resolver, self._mach_context)
|
||||
changed_files = at.find_changed_files()
|
||||
if changed_files:
|
||||
print("Tests will be run based on modifications to the "
|
||||
"following files:\n\t%s" % "\n\t".join(changed_files))
|
||||
|
||||
from mozbuild.frontend.reader import (
|
||||
BuildReader,
|
||||
EmptyConfig,
|
||||
)
|
||||
config = EmptyConfig(self.topsrcdir)
|
||||
reader = BuildReader(config)
|
||||
files_info = reader.files_info(changed_files)
|
||||
|
||||
paths, tags, flavors = set(), set(), set()
|
||||
for info in files_info.values():
|
||||
paths |= info.test_files
|
||||
tags |= info.test_tags
|
||||
flavors |= info.test_flavors
|
||||
|
||||
# This requires multiple calls to resolve_tests, because the test
|
||||
# resolver returns tests that match every condition, while we want
|
||||
# tests that match any condition. Bug 1210213 tracks implementing
|
||||
# more flexible querying.
|
||||
if tags:
|
||||
run_tests = list(resolver.resolve_tests(tags=tags))
|
||||
if paths:
|
||||
run_tests += [t for t in resolver.resolve_tests(paths=paths)
|
||||
if not (tags & set(t.get('tags', '').split()))]
|
||||
if flavors:
|
||||
run_tests = [t for t in run_tests if t['flavor'] not in flavors]
|
||||
for flavor in flavors:
|
||||
run_tests += list(resolver.resolve_tests(flavor=flavor))
|
||||
|
||||
if not run_suites and not run_tests:
|
||||
print(UNKNOWN_TEST)
|
||||
return 1
|
||||
|
||||
status = None
|
||||
for suite_name in run_suites:
|
||||
suite = TEST_SUITES[suite_name]
|
||||
|
||||
if 'mach_command' in suite:
|
||||
res = self._mach_context.commands.dispatch(
|
||||
suite['mach_command'], self._mach_context,
|
||||
**suite['kwargs'])
|
||||
if res:
|
||||
status = res
|
||||
|
||||
buckets = {}
|
||||
for test in run_tests:
|
||||
key = (test['flavor'], test.get('subsuite', ''))
|
||||
buckets.setdefault(key, []).append(test)
|
||||
|
||||
for (flavor, subsuite), tests in sorted(buckets.items()):
|
||||
if flavor not in TEST_FLAVORS:
|
||||
print(UNKNOWN_FLAVOR % flavor)
|
||||
status = 1
|
||||
continue
|
||||
|
||||
m = TEST_FLAVORS[flavor]
|
||||
if 'mach_command' not in m:
|
||||
print(UNKNOWN_FLAVOR % flavor)
|
||||
status = 1
|
||||
continue
|
||||
|
||||
kwargs = dict(m['kwargs'])
|
||||
kwargs['subsuite'] = subsuite
|
||||
|
||||
res = self._mach_context.commands.dispatch(
|
||||
m['mach_command'], self._mach_context,
|
||||
test_objects=tests, **kwargs)
|
||||
if res:
|
||||
status = res
|
||||
|
||||
return status
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command('cppunittest', category='testing',
|
||||
description='Run cpp unit tests (C++ tests).')
|
||||
@CommandArgument('test_files', nargs='*', metavar='N',
|
||||
help='Test to run. Can be specified as one or more files or ' \
|
||||
'directories, or omitted. If omitted, the entire test suite is ' \
|
||||
'executed.')
|
||||
|
||||
def run_cppunit_test(self, **params):
|
||||
import mozinfo
|
||||
from mozlog import commandline
|
||||
log = commandline.setup_logging("cppunittest",
|
||||
{},
|
||||
{"tbpl": sys.stdout})
|
||||
|
||||
# See if we have crash symbols
|
||||
symbols_path = os.path.join(self.distdir, 'crashreporter-symbols')
|
||||
if not os.path.isdir(symbols_path):
|
||||
symbols_path = None
|
||||
|
||||
# If no tests specified, run all tests in main manifest
|
||||
tests = params['test_files']
|
||||
if len(tests) == 0:
|
||||
tests = [os.path.join(self.distdir, 'cppunittests')]
|
||||
manifest_path = os.path.join(self.topsrcdir, 'testing', 'cppunittest.ini')
|
||||
else:
|
||||
manifest_path = None
|
||||
|
||||
if conditions.is_android(self):
|
||||
from mozrunner.devices.android_device import verify_android_device
|
||||
verify_android_device(self, install=False)
|
||||
return self.run_android_test(tests, symbols_path, manifest_path, log)
|
||||
|
||||
return self.run_desktop_test(tests, symbols_path, manifest_path, log)
|
||||
|
||||
def run_desktop_test(self, tests, symbols_path, manifest_path, log):
|
||||
import runcppunittests as cppunittests
|
||||
from mozlog import commandline
|
||||
|
||||
parser = cppunittests.CPPUnittestOptions()
|
||||
commandline.add_logging_group(parser)
|
||||
options, args = parser.parse_args()
|
||||
|
||||
options.symbols_path = symbols_path
|
||||
options.manifest_path = manifest_path
|
||||
options.xre_path = self.bindir
|
||||
|
||||
try:
|
||||
result = cppunittests.run_test_harness(options, tests)
|
||||
except Exception as e:
|
||||
log.error("Caught exception running cpp unit tests: %s" % str(e))
|
||||
result = False
|
||||
raise
|
||||
|
||||
return 0 if result else 1
|
||||
|
||||
def run_android_test(self, tests, symbols_path, manifest_path, log):
|
||||
import remotecppunittests as remotecppunittests
|
||||
from mozlog import commandline
|
||||
|
||||
parser = remotecppunittests.RemoteCPPUnittestOptions()
|
||||
commandline.add_logging_group(parser)
|
||||
options, args = parser.parse_args()
|
||||
|
||||
options.symbols_path = symbols_path
|
||||
options.manifest_path = manifest_path
|
||||
options.xre_path = self.bindir
|
||||
options.dm_trans = "adb"
|
||||
options.local_lib = self.bindir.replace('bin', 'fennec')
|
||||
for file in os.listdir(os.path.join(self.topobjdir, "dist")):
|
||||
if file.endswith(".apk") and file.startswith("fennec"):
|
||||
options.local_apk = os.path.join(self.topobjdir, "dist", file)
|
||||
log.info("using APK: " + options.local_apk)
|
||||
break
|
||||
|
||||
try:
|
||||
result = remotecppunittests.run_test_harness(options, tests)
|
||||
except Exception as e:
|
||||
log.error("Caught exception running cpp unit tests: %s" % str(e))
|
||||
result = False
|
||||
raise
|
||||
|
||||
return 0 if result else 1
|
||||
|
||||
def executable_name(name):
|
||||
return name + '.exe' if sys.platform.startswith('win') else name
|
||||
|
||||
@CommandProvider
|
||||
class CheckSpiderMonkeyCommand(MachCommandBase):
|
||||
@Command('check-spidermonkey', category='testing', description='Run SpiderMonkey tests (JavaScript engine).')
|
||||
@CommandArgument('--valgrind', action='store_true', help='Run jit-test suite with valgrind flag')
|
||||
|
||||
def run_checkspidermonkey(self, **params):
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
js = os.path.join(self.bindir, executable_name('js'))
|
||||
|
||||
print('Running jit-tests')
|
||||
jittest_cmd = [os.path.join(self.topsrcdir, 'js', 'src', 'jit-test', 'jit_test.py'),
|
||||
js, '--no-slow', '--jitflags=all']
|
||||
if params['valgrind']:
|
||||
jittest_cmd.append('--valgrind')
|
||||
|
||||
jittest_result = subprocess.call(jittest_cmd)
|
||||
|
||||
print('running jstests')
|
||||
jstest_cmd = [os.path.join(self.topsrcdir, 'js', 'src', 'tests', 'jstests.py'),
|
||||
js, '--jitflags=all']
|
||||
jstest_result = subprocess.call(jstest_cmd)
|
||||
|
||||
print('running jsapi-tests')
|
||||
jsapi_tests_cmd = [os.path.join(self.bindir, executable_name('jsapi-tests'))]
|
||||
jsapi_tests_result = subprocess.call(jsapi_tests_cmd)
|
||||
|
||||
print('running check-style')
|
||||
check_style_cmd = [sys.executable, os.path.join(self.topsrcdir, 'config', 'check_spidermonkey_style.py')]
|
||||
check_style_result = subprocess.call(check_style_cmd, cwd=os.path.join(self.topsrcdir, 'js', 'src'))
|
||||
|
||||
print('running check-masm')
|
||||
check_masm_cmd = [sys.executable, os.path.join(self.topsrcdir, 'config', 'check_macroassembler_style.py')]
|
||||
check_masm_result = subprocess.call(check_masm_cmd, cwd=os.path.join(self.topsrcdir, 'js', 'src'))
|
||||
|
||||
print('running check-js-msg-encoding')
|
||||
check_js_msg_cmd = [sys.executable, os.path.join(self.topsrcdir, 'config', 'check_js_msg_encoding.py')]
|
||||
check_js_msg_result = subprocess.call(check_js_msg_cmd, cwd=self.topsrcdir)
|
||||
|
||||
all_passed = jittest_result and jstest_result and jsapi_tests_result and check_style_result and check_masm_result and check_js_msg_result
|
||||
|
||||
return all_passed
|
||||
|
||||
@CommandProvider
|
||||
class JsapiTestsCommand(MachCommandBase):
|
||||
@Command('jsapi-tests', category='testing', description='Run jsapi tests (JavaScript engine).')
|
||||
@CommandArgument('test_name', nargs='?', metavar='N',
|
||||
help='Test to run. Can be a prefix or omitted. If omitted, the entire ' \
|
||||
'test suite is executed.')
|
||||
|
||||
def run_jsapitests(self, **params):
|
||||
import subprocess
|
||||
|
||||
bin_suffix = ''
|
||||
if sys.platform.startswith('win'):
|
||||
bin_suffix = '.exe'
|
||||
|
||||
print('running jsapi-tests')
|
||||
jsapi_tests_cmd = [os.path.join(self.bindir, executable_name('jsapi-tests'))]
|
||||
if params['test_name']:
|
||||
jsapi_tests_cmd.append(params['test_name'])
|
||||
|
||||
jsapi_tests_result = subprocess.call(jsapi_tests_cmd)
|
||||
|
||||
return jsapi_tests_result
|
||||
|
||||
def autotry_parser():
|
||||
from autotry import arg_parser
|
||||
return arg_parser()
|
||||
|
||||
@CommandProvider
|
||||
class PushToTry(MachCommandBase):
|
||||
def normalise_list(self, items, allow_subitems=False):
|
||||
from autotry import parse_arg
|
||||
|
||||
rv = defaultdict(list)
|
||||
for item in items:
|
||||
parsed = parse_arg(item)
|
||||
for key, values in parsed.iteritems():
|
||||
rv[key].extend(values)
|
||||
|
||||
if not allow_subitems:
|
||||
if not all(item == [] for item in rv.itervalues()):
|
||||
raise ValueError("Unexpected subitems in argument")
|
||||
return rv.keys()
|
||||
else:
|
||||
return rv
|
||||
|
||||
def validate_args(self, **kwargs):
|
||||
from autotry import AutoTry
|
||||
if not kwargs["paths"] and not kwargs["tests"] and not kwargs["tags"]:
|
||||
print("Paths, tags, or tests must be specified as an argument to autotry.")
|
||||
sys.exit(1)
|
||||
|
||||
if kwargs["platforms"] is None:
|
||||
if 'AUTOTRY_PLATFORM_HINT' in os.environ:
|
||||
kwargs["platforms"] = [os.environ['AUTOTRY_PLATFORM_HINT']]
|
||||
else:
|
||||
print("Platforms must be specified as an argument to autotry.")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
platforms = self.normalise_list(kwargs["platforms"])
|
||||
except ValueError as e:
|
||||
print("Error parsing -p argument:\n%s" % e.message)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
tests = (self.normalise_list(kwargs["tests"], allow_subitems=True)
|
||||
if kwargs["tests"] else {})
|
||||
except ValueError as e:
|
||||
print("Error parsing -u argument (%s):\n%s" % (kwargs["tests"], e.message))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
talos = (self.normalise_list(kwargs["talos"], allow_subitems=True)
|
||||
if kwargs["talos"] else [])
|
||||
except ValueError as e:
|
||||
print("Error parsing -t argument:\n%s" % e.message)
|
||||
sys.exit(1)
|
||||
|
||||
paths = []
|
||||
for p in kwargs["paths"]:
|
||||
p = mozpath.normpath(os.path.abspath(p))
|
||||
if not (os.path.isdir(p) and p.startswith(self.topsrcdir)):
|
||||
print('Specified path "%s" is not a directory under the srcdir,'
|
||||
' unable to specify tests outside of the srcdir' % p)
|
||||
sys.exit(1)
|
||||
if len(p) <= len(self.topsrcdir):
|
||||
print('Specified path "%s" is at the top of the srcdir and would'
|
||||
' select all tests.' % p)
|
||||
sys.exit(1)
|
||||
paths.append(os.path.relpath(p, self.topsrcdir))
|
||||
|
||||
try:
|
||||
tags = self.normalise_list(kwargs["tags"]) if kwargs["tags"] else []
|
||||
except ValueError as e:
|
||||
print("Error parsing --tags argument:\n%s" % e.message)
|
||||
sys.exit(1)
|
||||
|
||||
extra_values = {k['dest'] for k in AutoTry.pass_through_arguments.values()}
|
||||
extra_args = {k: v for k, v in kwargs.items()
|
||||
if k in extra_values and v}
|
||||
|
||||
return kwargs["builds"], platforms, tests, talos, paths, tags, extra_args
|
||||
|
||||
|
||||
@Command('try',
|
||||
category='testing',
|
||||
description='Push selected tests to the try server',
|
||||
parser=autotry_parser)
|
||||
|
||||
def autotry(self, **kwargs):
|
||||
"""Autotry is in beta, please file bugs blocking 1149670.
|
||||
|
||||
Push the current tree to try, with the specified syntax.
|
||||
|
||||
Build options, platforms and regression tests may be selected
|
||||
using the usual try options (-b, -p and -u respectively). In
|
||||
addition, tests in a given directory may be automatically
|
||||
selected by passing that directory as a positional argument to the
|
||||
command. For example:
|
||||
|
||||
mach try -b d -p linux64 dom testing/web-platform/tests/dom
|
||||
|
||||
would schedule a try run for linux64 debug consisting of all
|
||||
tests under dom/ and testing/web-platform/tests/dom.
|
||||
|
||||
Test selection using positional arguments is available for
|
||||
mochitests, reftests, xpcshell tests and web-platform-tests.
|
||||
|
||||
Tests may be also filtered by passing --tag to the command,
|
||||
which will run only tests marked as having the specified
|
||||
tags e.g.
|
||||
|
||||
mach try -b d -p win64 --tag media
|
||||
|
||||
would run all tests tagged 'media' on Windows 64.
|
||||
|
||||
If both positional arguments or tags and -u are supplied, the
|
||||
suites in -u will be run in full. Where tests are selected by
|
||||
positional argument they will be run in a single chunk.
|
||||
|
||||
If no build option is selected, both debug and opt will be
|
||||
scheduled. If no platform is selected a default is taken from
|
||||
the AUTOTRY_PLATFORM_HINT environment variable, if set.
|
||||
|
||||
The command requires either its own mercurial extension ("push-to-try",
|
||||
installable from mach mercurial-setup) or a git repo using git-cinnabar
|
||||
(available at https://github.com/glandium/git-cinnabar).
|
||||
|
||||
"""
|
||||
|
||||
from mozbuild.testing import TestResolver
|
||||
from autotry import AutoTry
|
||||
|
||||
print("mach try is under development, please file bugs blocking 1149670.")
|
||||
|
||||
resolver_func = lambda: self._spawn(TestResolver)
|
||||
at = AutoTry(self.topsrcdir, resolver_func, self._mach_context)
|
||||
|
||||
if kwargs["list"]:
|
||||
at.list_presets()
|
||||
sys.exit()
|
||||
|
||||
if kwargs["load"] is not None:
|
||||
defaults = at.load_config(kwargs["load"])
|
||||
|
||||
if defaults is None:
|
||||
print("No saved configuration called %s found in autotry.ini" % kwargs["load"],
|
||||
file=sys.stderr)
|
||||
|
||||
for key, value in kwargs.iteritems():
|
||||
if value in (None, []) and key in defaults:
|
||||
kwargs[key] = defaults[key]
|
||||
|
||||
if kwargs["push"] and at.find_uncommited_changes():
|
||||
print('ERROR please commit changes before continuing')
|
||||
sys.exit(1)
|
||||
|
||||
if not any(kwargs[item] for item in ("paths", "tests", "tags")):
|
||||
kwargs["paths"], kwargs["tags"] = at.find_paths_and_tags(kwargs["verbose"])
|
||||
|
||||
builds, platforms, tests, talos, paths, tags, extra = self.validate_args(**kwargs)
|
||||
|
||||
if paths or tags:
|
||||
paths = [os.path.relpath(os.path.normpath(os.path.abspath(item)), self.topsrcdir)
|
||||
for item in paths]
|
||||
paths_by_flavor = at.paths_by_flavor(paths=paths, tags=tags)
|
||||
|
||||
if not paths_by_flavor and not tests:
|
||||
print("No tests were found when attempting to resolve paths:\n\n\t%s" %
|
||||
paths)
|
||||
sys.exit(1)
|
||||
|
||||
if not kwargs["intersection"]:
|
||||
paths_by_flavor = at.remove_duplicates(paths_by_flavor, tests)
|
||||
else:
|
||||
paths_by_flavor = {}
|
||||
|
||||
try:
|
||||
msg = at.calc_try_syntax(platforms, tests, talos, builds, paths_by_flavor, tags,
|
||||
extra, kwargs["intersection"])
|
||||
except ValueError as e:
|
||||
print(e.message)
|
||||
sys.exit(1)
|
||||
|
||||
if kwargs["verbose"] and paths_by_flavor:
|
||||
print('The following tests will be selected: ')
|
||||
for flavor, paths in paths_by_flavor.iteritems():
|
||||
print("%s: %s" % (flavor, ",".join(paths)))
|
||||
|
||||
if kwargs["verbose"] or not kwargs["push"]:
|
||||
print('The following try syntax was calculated:\n%s' % msg)
|
||||
|
||||
if kwargs["push"]:
|
||||
at.push_to_try(msg, kwargs["verbose"])
|
||||
|
||||
if kwargs["save"] is not None:
|
||||
at.save_config(kwargs["save"], msg)
|
||||
|
||||
|
||||
def get_parser(argv=None):
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument(dest="suite_name",
|
||||
nargs=1,
|
||||
choices=['mochitest'],
|
||||
type=str,
|
||||
help="The test for which chunk should be found. It corresponds "
|
||||
"to the mach test invoked (only 'mochitest' currently).")
|
||||
|
||||
parser.add_argument(dest="test_path",
|
||||
nargs=1,
|
||||
type=str,
|
||||
help="The test (any mochitest) for which chunk should be found.")
|
||||
|
||||
parser.add_argument('--total-chunks',
|
||||
type=int,
|
||||
dest='total_chunks',
|
||||
required=True,
|
||||
help='Total number of chunks to split tests into.',
|
||||
default=None)
|
||||
|
||||
parser.add_argument('--chunk-by-runtime',
|
||||
action='store_true',
|
||||
dest='chunk_by_runtime',
|
||||
help='Group tests such that each chunk has roughly the same runtime.',
|
||||
default=False)
|
||||
|
||||
parser.add_argument('--chunk-by-dir',
|
||||
type=int,
|
||||
dest='chunk_by_dir',
|
||||
help='Group tests together in the same chunk that are in the same top '
|
||||
'chunkByDir directories.',
|
||||
default=None)
|
||||
|
||||
parser.add_argument('--disable-e10s',
|
||||
action='store_false',
|
||||
dest='e10s',
|
||||
help='Find test on chunk with electrolysis preferences disabled.',
|
||||
default=True)
|
||||
|
||||
parser.add_argument('-p', '--platform',
|
||||
choices=['linux', 'linux64', 'mac', 'macosx64', 'win32', 'win64'],
|
||||
dest='platform',
|
||||
help="Platform for the chunk to find the test.",
|
||||
default=None)
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_true',
|
||||
dest='debug',
|
||||
help="Find the test on chunk in a debug build.",
|
||||
default=False)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def download_mozinfo(platform=None, debug_build=False):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
temp_path = os.path.join(temp_dir, "mozinfo.json")
|
||||
args = [
|
||||
'mozdownload',
|
||||
'-t', 'tinderbox',
|
||||
'--ext', 'mozinfo.json',
|
||||
'-d', temp_path,
|
||||
]
|
||||
if platform:
|
||||
if platform == 'macosx64':
|
||||
platform = 'mac64'
|
||||
args.extend(['-p', platform])
|
||||
if debug_build:
|
||||
args.extend(['--debug-build'])
|
||||
|
||||
subprocess.call(args)
|
||||
return temp_dir, temp_path
|
||||
|
||||
@CommandProvider
|
||||
class ChunkFinder(MachCommandBase):
|
||||
@Command('find-test-chunk', category='testing',
|
||||
description='Find which chunk a test belongs to (works for mochitest).',
|
||||
parser=get_parser)
|
||||
def chunk_finder(self, **kwargs):
|
||||
total_chunks = kwargs['total_chunks']
|
||||
test_path = kwargs['test_path'][0]
|
||||
suite_name = kwargs['suite_name'][0]
|
||||
_, dump_tests = tempfile.mkstemp()
|
||||
|
||||
from mozbuild.testing import TestResolver
|
||||
resolver = self._spawn(TestResolver)
|
||||
relpath = self._wrap_path_argument(test_path).relpath()
|
||||
tests = list(resolver.resolve_tests(paths=[relpath]))
|
||||
if len(tests) != 1:
|
||||
print('No test found for test_path: %s' % test_path)
|
||||
sys.exit(1)
|
||||
|
||||
flavor = tests[0]['flavor']
|
||||
subsuite = tests[0]['subsuite']
|
||||
args = {
|
||||
'totalChunks': total_chunks,
|
||||
'dump_tests': dump_tests,
|
||||
'chunkByDir': kwargs['chunk_by_dir'],
|
||||
'chunkByRuntime': kwargs['chunk_by_runtime'],
|
||||
'e10s': kwargs['e10s'],
|
||||
'subsuite': subsuite,
|
||||
}
|
||||
|
||||
temp_dir = None
|
||||
if kwargs['platform'] or kwargs['debug']:
|
||||
self._activate_virtualenv()
|
||||
self.virtualenv_manager.install_pip_package('mozdownload==1.17')
|
||||
temp_dir, temp_path = download_mozinfo(kwargs['platform'], kwargs['debug'])
|
||||
args['extra_mozinfo_json'] = temp_path
|
||||
|
||||
found = False
|
||||
for this_chunk in range(1, total_chunks+1):
|
||||
args['thisChunk'] = this_chunk
|
||||
try:
|
||||
self._mach_context.commands.dispatch(suite_name, self._mach_context, flavor=flavor, resolve_tests=False, **args)
|
||||
except SystemExit:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
fp = open(os.path.expanduser(args['dump_tests']), 'r')
|
||||
tests = json.loads(fp.read())['active_tests']
|
||||
for test in tests:
|
||||
if test_path == test['path']:
|
||||
if 'disabled' in test:
|
||||
print('The test %s for flavor %s is disabled on the given platform' % (test_path, flavor))
|
||||
else:
|
||||
print('The test %s for flavor %s is present in chunk number: %d' % (test_path, flavor, this_chunk))
|
||||
found = True
|
||||
break
|
||||
|
||||
if found:
|
||||
break
|
||||
|
||||
if not found:
|
||||
raise Exception("Test %s not found." % test_path)
|
||||
# Clean up the file
|
||||
os.remove(dump_tests)
|
||||
if temp_dir:
|
||||
shutil.rmtree(temp_dir)
|
||||
Loading…
Add table
Add a link
Reference in a new issue