зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1397852 - Enable flake8 linter on testing/xpcshell. r=ahal
MozReview-Commit-ID: CvZVXQPx8jF --HG-- extra : rebase_source : 359f148397ef5584028e343080c6774407f74db6
This commit is contained in:
Родитель
890c883dee
Коммит
5d8117b9de
|
@ -6,7 +6,6 @@
|
|||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
import argparse
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
|
|
|
@ -8,7 +8,8 @@ from __future__ import absolute_import, print_function
|
|||
|
||||
import logging
|
||||
import posixpath
|
||||
import sys, os
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import runxpcshelltests as xpcshell
|
||||
import tempfile
|
||||
|
@ -25,9 +26,11 @@ from xpcshellcommandline import parser_remote
|
|||
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def remoteJoin(path1, path2):
|
||||
return posixpath.join(path1, path2)
|
||||
|
||||
|
||||
class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
|
||||
def __init__(self, *args, **kwargs):
|
||||
xpcshell.XPCShellTestThread.__init__(self, *args, **kwargs)
|
||||
|
@ -45,7 +48,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
|
|||
else:
|
||||
remoteName = remoteJoin(remoteDir, os.path.basename(name))
|
||||
return ['-e', 'const _TEST_FILE = ["%s"];' %
|
||||
remoteName.replace('\\', '/')]
|
||||
remoteName.replace('\\', '/')]
|
||||
|
||||
def remoteForLocal(self, local):
|
||||
for mapping in self.pathMapping:
|
||||
|
@ -170,12 +173,14 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
|
|||
# The minidumps directory is automatically created when Fennec
|
||||
# (first) starts, so its lack of presence is a hint that
|
||||
# something went wrong.
|
||||
print("Automation Error: No crash directory (%s) found on remote device" % self.remoteMinidumpDir)
|
||||
print("Automation Error: No crash directory (%s) found on remote device" %
|
||||
self.remoteMinidumpDir)
|
||||
# Whilst no crash was found, the run should still display as a failure
|
||||
return True
|
||||
with mozfile.TemporaryDirectory() as dumpDir:
|
||||
self.device.getDirectory(self.remoteMinidumpDir, dumpDir)
|
||||
crashed = xpcshell.XPCShellTestThread.checkForCrashes(self, dumpDir, symbols_path, test_name)
|
||||
crashed = xpcshell.XPCShellTestThread.checkForCrashes(
|
||||
self, dumpDir, symbols_path, test_name)
|
||||
self.clearRemoteDir(self.remoteMinidumpDir)
|
||||
return crashed
|
||||
|
||||
|
@ -217,8 +222,8 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
|
|||
except mozdevice.DMError:
|
||||
self.log.error("failed to delete %s: '%s'" % (remoteDir, str(out)))
|
||||
|
||||
#TODO: consider creating a separate log dir. We don't have the test file structure,
|
||||
# so we use filename.log. Would rather see ./logs/filename.log
|
||||
# TODO: consider creating a separate log dir. We don't have the test file structure,
|
||||
# so we use filename.log. Would rather see ./logs/filename.log
|
||||
def createLogFile(self, test, stdout):
|
||||
try:
|
||||
f = None
|
||||
|
@ -385,11 +390,11 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
|
|||
if (not self.device.dirExists(self.remoteBinDir)):
|
||||
# device.mkDir may fail here where shellCheckOutput may succeed -- see bug 817235
|
||||
try:
|
||||
self.device.shellCheckOutput(["mkdir", self.remoteBinDir]);
|
||||
self.device.shellCheckOutput(["mkdir", self.remoteBinDir])
|
||||
except mozdevice.DMError:
|
||||
# Might get a permission error; try again as root, if available
|
||||
self.device.shellCheckOutput(["mkdir", self.remoteBinDir], root=True);
|
||||
self.device.shellCheckOutput(["chmod", "777", self.remoteBinDir], root=True);
|
||||
self.device.shellCheckOutput(["mkdir", self.remoteBinDir], root=True)
|
||||
self.device.shellCheckOutput(["chmod", "777", self.remoteBinDir], root=True)
|
||||
|
||||
remotePrefDir = remoteJoin(self.remoteBinDir, "defaults/pref")
|
||||
if (self.device.dirExists(self.remoteTmpDir)):
|
||||
|
@ -423,7 +428,8 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
|
|||
remoteFile = remoteJoin(self.remoteBinDir, fname)
|
||||
self.device.pushFile(local, remoteFile)
|
||||
else:
|
||||
print("*** Expected binary %s not found in %s!" % (fname, self.localBin), file=sys.stderr)
|
||||
print("*** Expected binary %s not found in %s!" %
|
||||
(fname, self.localBin), file=sys.stderr)
|
||||
|
||||
local = os.path.join(self.localBin, "components/httpd.js")
|
||||
remoteFile = remoteJoin(self.remoteComponentsDir, "httpd.js")
|
||||
|
@ -512,7 +518,8 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
|
|||
self.device.mkDir(self.remoteMinidumpDir)
|
||||
|
||||
def buildTestList(self, test_tags=None, test_paths=None, verify=False):
|
||||
xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags, test_paths=test_paths, verify=verify)
|
||||
xpcshell.XPCShellTests.buildTestList(
|
||||
self, test_tags=test_tags, test_paths=test_paths, verify=verify)
|
||||
uniqueTestPaths = set([])
|
||||
for test in self.alltests:
|
||||
uniqueTestPaths.add(test['here'])
|
||||
|
@ -521,6 +528,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
|
|||
remoteScriptDir = remoteJoin(self.remoteScriptsDir, abbrevTestDir)
|
||||
self.pathMapping.append(PathMapping(testdir, remoteScriptDir))
|
||||
|
||||
|
||||
def verifyRemoteOptions(parser, options):
|
||||
if isinstance(options, Namespace):
|
||||
options = vars(options)
|
||||
|
@ -556,14 +564,16 @@ def verifyRemoteOptions(parser, options):
|
|||
parser.error("Couldn't find local binary dir, specify --local-bin-dir")
|
||||
return options
|
||||
|
||||
|
||||
class PathMapping:
|
||||
|
||||
def __init__(self, localDir, remoteDir):
|
||||
self.local = localDir
|
||||
self.remote = remoteDir
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info < (2,7):
|
||||
if sys.version_info < (2, 7):
|
||||
print("Error: You must use python version 2.7 or newer but less than 3.0", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
from __future__ import absolute_import, print_function
|
||||
|
||||
import copy
|
||||
import importlib
|
||||
import json
|
||||
import math
|
||||
import mozdebug
|
||||
import mozinfo
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
|
@ -22,7 +19,7 @@ import tempfile
|
|||
import time
|
||||
import traceback
|
||||
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from argparse import Namespace
|
||||
from collections import defaultdict, deque, namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
from distutils import dir_util
|
||||
|
@ -89,9 +86,13 @@ from mozrunner.utils import get_stack_fixer_function
|
|||
# except TAB (U+0009), CR (U+000D), LF (U+000A) and backslash (U+005C).
|
||||
# A raw string is deliberately not used.
|
||||
_cleanup_encoding_re = re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f\\\\]')
|
||||
|
||||
|
||||
def _cleanup_encoding_repl(m):
|
||||
c = m.group(0)
|
||||
return '\\\\' if c == '\\' else '\\x{0:02X}'.format(ord(c))
|
||||
|
||||
|
||||
def cleanup_encoding(s):
|
||||
"""S is either a byte or unicode string. Either way it may
|
||||
contain control characters, unpaired surrogates, reserved code
|
||||
|
@ -105,15 +106,19 @@ def cleanup_encoding(s):
|
|||
# Replace all C0 and C1 control characters with \xNN escapes.
|
||||
return _cleanup_encoding_re.sub(_cleanup_encoding_repl, s)
|
||||
|
||||
|
||||
""" Control-C handling """
|
||||
gotSIGINT = False
|
||||
|
||||
|
||||
def markGotSIGINT(signum, stackFrame):
|
||||
global gotSIGINT
|
||||
gotSIGINT = True
|
||||
|
||||
|
||||
class XPCShellTestThread(Thread):
|
||||
def __init__(self, test_object, retry=True, verbose=False, usingTSan=False,
|
||||
**kwargs):
|
||||
**kwargs):
|
||||
Thread.__init__(self)
|
||||
self.daemon = True
|
||||
|
||||
|
@ -169,7 +174,7 @@ class XPCShellTestThread(Thread):
|
|||
|
||||
# event from main thread to signal work done
|
||||
self.event = kwargs.get('event')
|
||||
self.done = False # explicitly set flag so we don't rely on thread.isAlive
|
||||
self.done = False # explicitly set flag so we don't rely on thread.isAlive
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
|
@ -254,7 +259,7 @@ class XPCShellTestThread(Thread):
|
|||
else:
|
||||
popen_func = Popen
|
||||
proc = popen_func(cmd, stdout=stdout, stderr=stderr,
|
||||
env=env, cwd=cwd)
|
||||
env=env, cwd=cwd)
|
||||
return proc
|
||||
|
||||
def checkForCrashes(self,
|
||||
|
@ -331,7 +336,7 @@ class XPCShellTestThread(Thread):
|
|||
On a remote system, this may be overloaded to use a remote path structure.
|
||||
"""
|
||||
return ['-e', 'const _TEST_FILE = ["%s"];' %
|
||||
name.replace('\\', '/')]
|
||||
name.replace('\\', '/')]
|
||||
|
||||
def setupTempDir(self):
|
||||
tempDir = mkdtemp(prefix='xpc-other-', dir=self._rootTempDir)
|
||||
|
@ -387,18 +392,19 @@ class XPCShellTestThread(Thread):
|
|||
Build the command line arguments for the head files,
|
||||
along with the address of the webserver which some tests require.
|
||||
|
||||
On a remote system, this is overloaded to resolve quoting issues over a secondary command line.
|
||||
On a remote system, this is overloaded to resolve quoting issues over a
|
||||
secondary command line.
|
||||
"""
|
||||
cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
|
||||
for f in headfiles])
|
||||
for f in headfiles])
|
||||
|
||||
dbgport = 0 if self.jsDebuggerInfo is None else self.jsDebuggerInfo.port
|
||||
|
||||
return xpcscmd + \
|
||||
['-e', 'const _SERVER_ADDR = "localhost"',
|
||||
'-e', 'const _HEAD_FILES = [%s];' % cmdH,
|
||||
'-e', 'const _JSDEBUGGER_PORT = %d;' % dbgport,
|
||||
]
|
||||
return xpcscmd + [
|
||||
'-e', 'const _SERVER_ADDR = "localhost"',
|
||||
'-e', 'const _HEAD_FILES = [%s];' % cmdH,
|
||||
'-e', 'const _JSDEBUGGER_PORT = %d;' % dbgport,
|
||||
]
|
||||
|
||||
def getHeadFiles(self, test):
|
||||
"""Obtain lists of head- files. Returns a list of head files.
|
||||
|
@ -423,8 +429,9 @@ class XPCShellTestThread(Thread):
|
|||
|
||||
def buildXpcsCmd(self):
|
||||
"""
|
||||
Load the root head.js file as the first file in our test path, before other head, and test files.
|
||||
On a remote system, we overload this to add additional command line arguments, so this gets overloaded.
|
||||
Load the root head.js file as the first file in our test path, before other head,
|
||||
and test files. On a remote system, we overload this to add additional command
|
||||
line arguments, so this gets overloaded.
|
||||
"""
|
||||
# - NOTE: if you rename/add any of the constants set here, update
|
||||
# do_load_child_test_harness() in head.js
|
||||
|
@ -469,8 +476,9 @@ class XPCShellTestThread(Thread):
|
|||
if not os.path.exists(directory):
|
||||
return
|
||||
|
||||
TRY_LIMIT = 25 # up to TRY_LIMIT attempts (one every second), because
|
||||
# the Windows filesystem is slow to react to the changes
|
||||
# up to TRY_LIMIT attempts (one every second), because
|
||||
# the Windows filesystem is slow to react to the changes
|
||||
TRY_LIMIT = 25
|
||||
try_count = 0
|
||||
while try_count < TRY_LIMIT:
|
||||
try:
|
||||
|
@ -526,7 +534,7 @@ class XPCShellTestThread(Thread):
|
|||
if 'message' in line:
|
||||
line['message'] = self.fix_text_output(line['message'])
|
||||
if 'xpcshell_process' in line:
|
||||
line['thread'] = ' '.join([current_thread().name, line['xpcshell_process']])
|
||||
line['thread'] = ' '.join([current_thread().name, line['xpcshell_process']])
|
||||
else:
|
||||
line['thread'] = current_thread().name
|
||||
self.log.log_raw(line)
|
||||
|
@ -579,7 +587,7 @@ class XPCShellTestThread(Thread):
|
|||
self.report_message(line_object)
|
||||
|
||||
if action == 'log' and line_object['message'] == 'CHILD-TEST-STARTED':
|
||||
self.saw_proc_start = True
|
||||
self.saw_proc_start = True
|
||||
elif action == 'log' and line_object['message'] == 'CHILD-TEST-COMPLETED':
|
||||
self.saw_proc_end = True
|
||||
|
||||
|
@ -668,7 +676,7 @@ class XPCShellTestThread(Thread):
|
|||
|
||||
if self.test_object.get('headless', False):
|
||||
self.env["MOZ_HEADLESS"] = '1'
|
||||
self.env["DISPLAY"] = '77' # Set a fake display.
|
||||
self.env["DISPLAY"] = '77' # Set a fake display.
|
||||
|
||||
testTimeoutInterval = self.harness_timeout
|
||||
# Allow a test to request a multiple of the timeout if it is expected to take long
|
||||
|
@ -689,7 +697,9 @@ class XPCShellTestThread(Thread):
|
|||
self.logCommand(name, self.complete_command, test_dir)
|
||||
|
||||
proc = self.launchProcess(self.complete_command,
|
||||
stdout=self.pStdout, stderr=self.pStderr, env=self.env, cwd=test_dir, timeout=testTimeoutInterval)
|
||||
stdout=self.pStdout, stderr=self.pStderr,
|
||||
env=self.env, cwd=test_dir,
|
||||
timeout=testTimeoutInterval)
|
||||
|
||||
if hasattr(proc, "pid"):
|
||||
self.proc_ident = proc.pid
|
||||
|
@ -806,6 +816,7 @@ class XPCShellTestThread(Thread):
|
|||
|
||||
self.keep_going = True
|
||||
|
||||
|
||||
class XPCShellTests(object):
|
||||
|
||||
def __init__(self, log=None):
|
||||
|
@ -836,7 +847,8 @@ class XPCShellTests(object):
|
|||
def normalizeTest(self, root, test_object):
|
||||
path = test_object.get('file_relpath', test_object['relpath'])
|
||||
if 'dupe-manifest' in test_object and 'ancestor-manifest' in test_object:
|
||||
test_object['id'] = '%s:%s' % (os.path.basename(test_object['ancestor-manifest']), path)
|
||||
test_object['id'] = '%s:%s' % (os.path.basename
|
||||
(test_object['ancestor-manifest']), path)
|
||||
else:
|
||||
test_object['id'] = path
|
||||
|
||||
|
@ -903,8 +915,8 @@ class XPCShellTests(object):
|
|||
|
||||
def setAbsPath(self):
|
||||
"""
|
||||
Set the absolute path for xpcshell, httpdjspath and xrepath.
|
||||
These 3 variables depend on input from the command line and we need to allow for absolute paths.
|
||||
Set the absolute path for xpcshell, httpdjspath and xrepath. These 3 variables
|
||||
depend on input from the command line and we need to allow for absolute paths.
|
||||
This function is overloaded for a remote solution as os.path* won't work remotely.
|
||||
"""
|
||||
self.testharnessdir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
@ -916,7 +928,8 @@ class XPCShellTests(object):
|
|||
if mozinfo.isMac:
|
||||
# Check if we're run from an OSX app bundle and override
|
||||
# self.xrePath if we are.
|
||||
appBundlePath = os.path.join(os.path.dirname(os.path.dirname(self.xpcshell)), 'Resources')
|
||||
appBundlePath = os.path.join(os.path.dirname(os.path.dirname(self.xpcshell)),
|
||||
'Resources')
|
||||
if os.path.exists(os.path.join(appBundlePath, 'application.ini')):
|
||||
self.xrePath = appBundlePath
|
||||
else:
|
||||
|
@ -934,7 +947,8 @@ class XPCShellTests(object):
|
|||
|
||||
def buildCoreEnvironment(self):
|
||||
"""
|
||||
Add environment variables likely to be used across all platforms, including remote systems.
|
||||
Add environment variables likely to be used across all platforms, including
|
||||
remote systems.
|
||||
"""
|
||||
# Make assertions fatal
|
||||
self.env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
|
||||
|
@ -960,8 +974,9 @@ class XPCShellTests(object):
|
|||
|
||||
def buildEnvironment(self):
|
||||
"""
|
||||
Create and returns a dictionary of self.env to include all the appropriate env variables and values.
|
||||
On a remote system, we overload this to set different values and are missing things like os.environ and PATH.
|
||||
Create and returns a dictionary of self.env to include all the appropriate env
|
||||
variables and values. On a remote system, we overload this to set different
|
||||
values and are missing things like os.environ and PATH.
|
||||
"""
|
||||
self.env = dict(os.environ)
|
||||
self.buildCoreEnvironment()
|
||||
|
@ -972,8 +987,8 @@ class XPCShellTests(object):
|
|||
os.environ["LIBPATHSTRICT"] = "T"
|
||||
elif sys.platform == 'osx' or sys.platform == "darwin":
|
||||
self.env["DYLD_LIBRARY_PATH"] = os.path.join(os.path.dirname(self.xrePath), 'MacOS')
|
||||
else: # unix or linux?
|
||||
if not "LD_LIBRARY_PATH" in self.env or self.env["LD_LIBRARY_PATH"] is None:
|
||||
else: # unix or linux?
|
||||
if "LD_LIBRARY_PATH" not in self.env or self.env["LD_LIBRARY_PATH"] is None:
|
||||
self.env["LD_LIBRARY_PATH"] = self.xrePath
|
||||
else:
|
||||
self.env["LD_LIBRARY_PATH"] = ":".join([self.xrePath, self.env["LD_LIBRARY_PATH"]])
|
||||
|
@ -990,10 +1005,12 @@ class XPCShellTests(object):
|
|||
self.env["ASAN_SYMBOLIZER_PATH"] = llvmsym
|
||||
else:
|
||||
oldTSanOptions = self.env.get("TSAN_OPTIONS", "")
|
||||
self.env["TSAN_OPTIONS"] = "external_symbolizer_path={} {}".format(llvmsym, oldTSanOptions)
|
||||
self.env["TSAN_OPTIONS"] = ("external_symbolizer_path={} {}".format(llvmsym,
|
||||
oldTSanOptions))
|
||||
self.log.info("runxpcshelltests.py | using symbolizer at %s" % llvmsym)
|
||||
else:
|
||||
self.log.error("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | Failed to find symbolizer at %s" % llvmsym)
|
||||
self.log.error("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | "
|
||||
"Failed to find symbolizer at %s" % llvmsym)
|
||||
|
||||
return self.env
|
||||
|
||||
|
@ -1031,14 +1048,16 @@ class XPCShellTests(object):
|
|||
if os.getenv('MOZ_ASSUME_NODE_RUNNING', None):
|
||||
self.log.info('Assuming required node servers are already running')
|
||||
if not os.getenv('MOZHTTP2_PORT', None):
|
||||
self.log.warning('MOZHTTP2_PORT environment variable not set. Tests requiring http/2 will fail.')
|
||||
self.log.warning('MOZHTTP2_PORT environment variable not set. '
|
||||
'Tests requiring http/2 will fail.')
|
||||
return
|
||||
|
||||
# We try to find the node executable in the path given to us by the user in
|
||||
# the MOZ_NODE_PATH environment variable
|
||||
nodeBin = os.getenv('MOZ_NODE_PATH', None)
|
||||
if not nodeBin:
|
||||
self.log.warning('MOZ_NODE_PATH environment variable not set. Tests requiring http/2 will fail.')
|
||||
self.log.warning('MOZ_NODE_PATH environment variable not set. '
|
||||
'Tests requiring http/2 will fail.')
|
||||
return
|
||||
|
||||
if not os.path.exists(nodeBin) or not os.path.isfile(nodeBin):
|
||||
|
@ -1060,16 +1079,16 @@ class XPCShellTests(object):
|
|||
# We pipe stdin to node because the server will exit when its
|
||||
# stdin reaches EOF
|
||||
process = Popen([nodeBin, serverJs], stdin=PIPE, stdout=PIPE,
|
||||
stderr=PIPE, env=self.env, cwd=os.getcwd())
|
||||
stderr=PIPE, env=self.env, cwd=os.getcwd())
|
||||
self.nodeProc[name] = process
|
||||
|
||||
# Check to make sure the server starts properly by waiting for it to
|
||||
# tell us it's started
|
||||
msg = process.stdout.readline()
|
||||
if 'server listening' in msg:
|
||||
searchObj = re.search( r'HTTP2 server listening on port (.*)', msg, 0)
|
||||
searchObj = re.search(r'HTTP2 server listening on port (.*)', msg, 0)
|
||||
if searchObj:
|
||||
self.env["MOZHTTP2_PORT"] = searchObj.group(1)
|
||||
self.env["MOZHTTP2_PORT"] = searchObj.group(1)
|
||||
except OSError as e:
|
||||
# This occurs if the subprocess couldn't be started
|
||||
self.log.error('Could not run %s server: %s' % (name, str(e)))
|
||||
|
@ -1088,11 +1107,12 @@ class XPCShellTests(object):
|
|||
self.log.info('Node server %s already dead %s' % (name, proc.poll()))
|
||||
else:
|
||||
proc.terminate()
|
||||
|
||||
def dumpOutput(fd, label):
|
||||
firstTime = True
|
||||
for msg in fd:
|
||||
if firstTime:
|
||||
firstTime = False;
|
||||
firstTime = False
|
||||
self.log.info('Process %s' % label)
|
||||
self.log.info(msg)
|
||||
dumpOutput(proc.stdout, "stdout")
|
||||
|
@ -1104,8 +1124,9 @@ class XPCShellTests(object):
|
|||
"""
|
||||
if self.interactive:
|
||||
self.xpcsRunArgs = [
|
||||
'-e', 'print("To start the test, type |_execute_test();|.");',
|
||||
'-i']
|
||||
'-e', 'print("To start the test, type |_execute_test();|.");',
|
||||
'-i'
|
||||
]
|
||||
else:
|
||||
self.xpcsRunArgs = ['-e', '_execute_test(); quit(0);']
|
||||
|
||||
|
@ -1119,7 +1140,8 @@ class XPCShellTests(object):
|
|||
if not isinstance(self.mozInfo, dict):
|
||||
mozInfoFile = self.mozInfo
|
||||
if not os.path.isfile(mozInfoFile):
|
||||
self.log.error("Error: couldn't find mozinfo.json at '%s'. Perhaps you need to use --build-info-json?" % mozInfoFile)
|
||||
self.log.error("Error: couldn't find mozinfo.json at '%s'. Perhaps you "
|
||||
"need to use --build-info-json?" % mozInfoFile)
|
||||
return False
|
||||
self.mozInfo = json.load(open(mozInfoFile))
|
||||
|
||||
|
@ -1167,10 +1189,10 @@ class XPCShellTests(object):
|
|||
|
||||
if options.get('rerun_failures'):
|
||||
if os.path.exists(options.get('failure_manifest')):
|
||||
rerun_manifest = os.path.join(os.path.dirname(options['failure_manifest']), "rerun.ini")
|
||||
rerun_manifest = os.path.join(os.path.dirname
|
||||
(options['failure_manifest']), "rerun.ini")
|
||||
shutil.copyfile(options['failure_manifest'], rerun_manifest)
|
||||
os.remove(options['failure_manifest'])
|
||||
manifest = rerun_manifest
|
||||
else:
|
||||
print >> sys.stderr, "No failures were found to re-run."
|
||||
sys.exit(1)
|
||||
|
@ -1191,7 +1213,8 @@ class XPCShellTests(object):
|
|||
|
||||
if options.get('debugger'):
|
||||
self.debuggerInfo = mozdebug.get_debugger_info(options.get('debugger'),
|
||||
options.get('debuggerArgs'), options.get('debuggerInteractive'))
|
||||
options.get('debuggerArgs'),
|
||||
options.get('debuggerInteractive'))
|
||||
|
||||
self.jsDebuggerInfo = None
|
||||
if options.get('jsDebugger'):
|
||||
|
@ -1237,7 +1260,8 @@ class XPCShellTests(object):
|
|||
|
||||
self.stack_fixer_function = None
|
||||
if self.utility_path and os.path.exists(self.utility_path):
|
||||
self.stack_fixer_function = get_stack_fixer_function(self.utility_path, self.symbolsPath)
|
||||
self.stack_fixer_function = get_stack_fixer_function(self.utility_path,
|
||||
self.symbolsPath)
|
||||
|
||||
# buildEnvironment() needs mozInfo, so we call it after mozInfo is initialized.
|
||||
self.buildEnvironment()
|
||||
|
@ -1256,7 +1280,8 @@ class XPCShellTests(object):
|
|||
|
||||
pStdout, pStderr = self.getPipes()
|
||||
|
||||
self.buildTestList(options.get('test_tags'), options.get('testPaths'), options.get('verify'))
|
||||
self.buildTestList(options.get('test_tags'), options.get('testPaths'),
|
||||
options.get('verify'))
|
||||
if self.singleFile:
|
||||
self.sequential = True
|
||||
|
||||
|
@ -1280,7 +1305,7 @@ class XPCShellTests(object):
|
|||
'testharnessdir': self.testharnessdir,
|
||||
'profileName': self.profileName,
|
||||
'singleFile': self.singleFile,
|
||||
'env': self.env, # making a copy of this in the testthreads
|
||||
'env': self.env, # making a copy of this in the testthreads
|
||||
'symbolsPath': self.symbolsPath,
|
||||
'logfiles': self.logfiles,
|
||||
'xpcshell': self.xpcshell,
|
||||
|
@ -1315,7 +1340,8 @@ class XPCShellTests(object):
|
|||
if "lldb" in self.debuggerInfo.path:
|
||||
# Ask people to start debugging using 'process launch', see bug 952211.
|
||||
self.log.info("It appears that you're using LLDB to debug this test. " +
|
||||
"Please use the 'process launch' command instead of the 'run' command to start xpcshell.")
|
||||
"Please use the 'process launch' command instead of "
|
||||
"the 'run' command to start xpcshell.")
|
||||
|
||||
if self.jsDebuggerInfo:
|
||||
# The js debugger magic needs more work to do the right thing
|
||||
|
@ -1346,17 +1372,17 @@ class XPCShellTests(object):
|
|||
|
||||
self.testCount += 1
|
||||
|
||||
test = testClass(test_object,
|
||||
verbose=self.verbose or test_object.get("verbose") == "true",
|
||||
usingTSan=usingTSan,
|
||||
mobileArgs=mobileArgs, **kwargs)
|
||||
test = testClass(
|
||||
test_object,
|
||||
verbose=self.verbose or test_object.get("verbose") == "true",
|
||||
usingTSan=usingTSan, mobileArgs=mobileArgs, **kwargs)
|
||||
if 'run-sequentially' in test_object or self.sequential:
|
||||
sequential_tests.append(test)
|
||||
else:
|
||||
tests_queue.append(test)
|
||||
|
||||
status = self.runTestList(tests_queue, sequential_tests, testClass,
|
||||
mobileArgs, **kwargs)
|
||||
mobileArgs, **kwargs)
|
||||
else:
|
||||
#
|
||||
# Test verification: Run each test many times, in various configurations,
|
||||
|
@ -1371,10 +1397,10 @@ class XPCShellTests(object):
|
|||
for i in xrange(VERIFY_REPEAT):
|
||||
self.testCount += 1
|
||||
test = testClass(test_object, retry=False,
|
||||
mobileArgs=mobileArgs, **kwargs)
|
||||
mobileArgs=mobileArgs, **kwargs)
|
||||
sequential_tests.append(test)
|
||||
status = self.runTestList(tests_queue, sequential_tests,
|
||||
testClass, mobileArgs, **kwargs)
|
||||
testClass, mobileArgs, **kwargs)
|
||||
return status
|
||||
|
||||
steps = [
|
||||
|
@ -1391,13 +1417,14 @@ class XPCShellTests(object):
|
|||
for (descr, step) in steps:
|
||||
if (datetime.now() - startTime) > maxTime:
|
||||
self.log.info("::: Test verification is taking too long: Giving up!")
|
||||
self.log.info("::: So far, all checks passed, but not all checks were run.")
|
||||
self.log.info("::: So far, all checks passed, but not "
|
||||
"all checks were run.")
|
||||
break
|
||||
self.log.info(':::')
|
||||
self.log.info('::: Running test verification step "%s"...' % descr)
|
||||
self.log.info(':::')
|
||||
status = step()
|
||||
if status != True:
|
||||
if status is not True:
|
||||
stepResults[descr] = "FAIL"
|
||||
finalResult = "FAILED!"
|
||||
break
|
||||
|
@ -1414,7 +1441,7 @@ class XPCShellTests(object):
|
|||
return status
|
||||
|
||||
def runTestList(self, tests_queue, sequential_tests, testClass,
|
||||
mobileArgs, **kwargs):
|
||||
mobileArgs, **kwargs):
|
||||
|
||||
if self.sequential:
|
||||
self.log.info("Running tests sequentially.")
|
||||
|
@ -1458,7 +1485,7 @@ class XPCShellTests(object):
|
|||
for test in running_tests:
|
||||
if test.done:
|
||||
done_tests.add(test)
|
||||
test.join(1) # join with timeout so we don't hang on blocked threads
|
||||
test.join(1) # join with timeout so we don't hang on blocked threads
|
||||
# if the test had trouble, we will try running it again
|
||||
# at the end of the run
|
||||
if test.retry or test.is_alive():
|
||||
|
@ -1482,8 +1509,9 @@ class XPCShellTests(object):
|
|||
# run the other tests sequentially
|
||||
for test in sequential_tests:
|
||||
if not keep_going:
|
||||
self.log.error("TEST-UNEXPECTED-FAIL | Received SIGINT (control-C), so stopped run. " \
|
||||
"(Use --keep-going to keep running tests after killing one with SIGINT)")
|
||||
self.log.error("TEST-UNEXPECTED-FAIL | Received SIGINT (control-C), so "
|
||||
"stopped run. (Use --keep-going to keep running tests "
|
||||
"after killing one with SIGINT)")
|
||||
break
|
||||
# we don't want to retry these tests
|
||||
test.retry = False
|
||||
|
@ -1502,10 +1530,10 @@ class XPCShellTests(object):
|
|||
self.log.info("Retrying tests that failed when run in parallel.")
|
||||
for test_object in self.try_again_list:
|
||||
test = testClass(test_object,
|
||||
retry=False,
|
||||
verbose=self.verbose,
|
||||
mobileArgs=mobileArgs,
|
||||
**kwargs)
|
||||
retry=False,
|
||||
verbose=self.verbose,
|
||||
mobileArgs=mobileArgs,
|
||||
**kwargs)
|
||||
test.start()
|
||||
test.join()
|
||||
self.addTestResults(test)
|
||||
|
@ -1546,9 +1574,10 @@ class XPCShellTests(object):
|
|||
self.log.info("INFO | Todo: %d" % self.todoCount)
|
||||
self.log.info("INFO | Retried: %d" % len(self.try_again_list))
|
||||
|
||||
if gotSIGINT and not keepGoing:
|
||||
self.log.error("TEST-UNEXPECTED-FAIL | Received SIGINT (control-C), so stopped run. " \
|
||||
"(Use --keep-going to keep running tests after killing one with SIGINT)")
|
||||
if gotSIGINT and not keep_going:
|
||||
self.log.error("TEST-UNEXPECTED-FAIL | Received SIGINT (control-C), so stopped run. "
|
||||
"(Use --keep-going to keep running tests after "
|
||||
"killing one with SIGINT)")
|
||||
return False
|
||||
|
||||
self.log.suite_end()
|
||||
|
@ -1573,5 +1602,6 @@ def main():
|
|||
if not xpcsh.runTests(options):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -30,11 +30,12 @@ mozinfo.find_and_update_from_json()
|
|||
objdir = build_obj.topobjdir.encode("utf-8")
|
||||
|
||||
if mozinfo.isMac:
|
||||
xpcshellBin = os.path.join(objdir, "dist", substs['MOZ_MACBUNDLE_NAME'], "Contents", "MacOS", "xpcshell")
|
||||
xpcshellBin = os.path.join(objdir, "dist", substs['MOZ_MACBUNDLE_NAME'],
|
||||
"Contents", "MacOS", "xpcshell")
|
||||
else:
|
||||
xpcshellBin = os.path.join(objdir, "dist", "bin", "xpcshell")
|
||||
if sys.platform == "win32":
|
||||
xpcshellBin += ".exe"
|
||||
xpcshellBin = os.path.join(objdir, "dist", "bin", "xpcshell")
|
||||
if sys.platform == "win32":
|
||||
xpcshellBin += ".exe"
|
||||
|
||||
TEST_PASS_STRING = "TEST-PASS"
|
||||
TEST_FAIL_STRING = "TEST-UNEXPECTED-FAIL"
|
||||
|
@ -448,6 +449,8 @@ add_test(function test_child_mozinfo () {
|
|||
run_next_test();
|
||||
});
|
||||
'''
|
||||
|
||||
|
||||
class XPCShellTestsTests(unittest.TestCase):
|
||||
"""
|
||||
Yes, these are unit tests for a unit test harness.
|
||||
|
@ -464,7 +467,7 @@ class XPCShellTestsTests(unittest.TestCase):
|
|||
self.symbols_path = None
|
||||
candidate_path = os.path.join(build_obj.distdir, 'crashreporter-symbols')
|
||||
if (os.path.isdir(candidate_path)):
|
||||
self.symbols_path = candidate_path
|
||||
self.symbols_path = candidate_path
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tempdir)
|
||||
|
@ -596,9 +599,11 @@ tail =
|
|||
line_pat = "#\d\d:"
|
||||
unknown_pat = "#\d\d\: \?\?\?\[.* \+0x[a-f0-9]+\]"
|
||||
self.assertFalse(any(re.search(unknown_pat, line) for line in log_lines),
|
||||
"An stack frame without symbols was found in\n%s" % pprint.pformat(log_lines))
|
||||
"An stack frame without symbols was found in\n%s" %
|
||||
pprint.pformat(log_lines))
|
||||
self.assertTrue(any(re.search(line_pat, line) for line in log_lines),
|
||||
"No line resembling a stack frame was found in\n%s" % pprint.pformat(log_lines))
|
||||
"No line resembling a stack frame was found in\n%s" %
|
||||
pprint.pformat(log_lines))
|
||||
|
||||
def testChildPass(self):
|
||||
"""
|
||||
|
@ -894,8 +899,8 @@ add_test({
|
|||
self.assertTestResult(False)
|
||||
self.assertInLog(TEST_FAIL_STRING)
|
||||
if not substs.get('RELEASE_OR_BETA'):
|
||||
# async stacks are currently not enabled in release builds.
|
||||
self.assertInLog("test_simple_uncaught_rejection.js:3:3")
|
||||
# async stacks are currently not enabled in release builds.
|
||||
self.assertInLog("test_simple_uncaught_rejection.js:3:3")
|
||||
self.assertInLog("Test rejection.")
|
||||
self.assertEquals(1, self.x.testCount)
|
||||
self.assertEquals(0, self.x.passCount)
|
||||
|
@ -994,7 +999,7 @@ add_test({
|
|||
Ensure multiple calls to add_test_task() work as expected.
|
||||
"""
|
||||
self.writeFile("test_add_task_multiple.js",
|
||||
ADD_TASK_MULTIPLE)
|
||||
ADD_TASK_MULTIPLE)
|
||||
self.writeManifest(["test_add_task_multiple.js"])
|
||||
|
||||
self.assertTestResult(True)
|
||||
|
@ -1007,7 +1012,7 @@ add_test({
|
|||
Ensure rejected task reports as failure.
|
||||
"""
|
||||
self.writeFile("test_add_task_rejected.js",
|
||||
ADD_TASK_REJECTED)
|
||||
ADD_TASK_REJECTED)
|
||||
self.writeManifest(["test_add_task_rejected.js"])
|
||||
|
||||
self.assertTestResult(False)
|
||||
|
@ -1020,7 +1025,7 @@ add_test({
|
|||
Ensure tests inside task are reported as failures.
|
||||
"""
|
||||
self.writeFile("test_add_task_failure_inside.js",
|
||||
ADD_TASK_FAILURE_INSIDE)
|
||||
ADD_TASK_FAILURE_INSIDE)
|
||||
self.writeManifest(["test_add_task_failure_inside.js"])
|
||||
|
||||
self.assertTestResult(False)
|
||||
|
@ -1033,7 +1038,7 @@ add_test({
|
|||
Calling run_next_test() from inside add_task() results in failure.
|
||||
"""
|
||||
self.writeFile("test_add_task_run_next_test.js",
|
||||
ADD_TASK_RUN_NEXT_TEST)
|
||||
ADD_TASK_RUN_NEXT_TEST)
|
||||
self.writeManifest(["test_add_task_run_next_test.js"])
|
||||
|
||||
self.assertTestResult(False)
|
||||
|
@ -1047,7 +1052,7 @@ add_test({
|
|||
results in a human-readable stack trace.
|
||||
"""
|
||||
self.writeFile("test_add_task_stack_trace.js",
|
||||
ADD_TASK_STACK_TRACE)
|
||||
ADD_TASK_STACK_TRACE)
|
||||
self.writeManifest(["test_add_task_stack_trace.js"])
|
||||
|
||||
self.assertTestResult(False)
|
||||
|
@ -1367,5 +1372,6 @@ add_test({
|
|||
self.assertInLog(TEST_PASS_STRING)
|
||||
self.assertNotInLog(TEST_FAIL_STRING)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mozunit.main()
|
||||
|
|
|
@ -40,8 +40,10 @@ def add_common_arguments(parser):
|
|||
help="Directory where testing modules are located.")
|
||||
parser.add_argument("--test-plugin-path",
|
||||
type=str, dest="pluginsPath", default=None,
|
||||
help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. "
|
||||
"By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory "
|
||||
help="Path to the location of a plugins directory containing the "
|
||||
"test plugin or plugins required for tests. "
|
||||
"By default xpcshell's dir svc provider returns gre/plugins. "
|
||||
"Use test-plugin-path to add a directory "
|
||||
"to return for NS_APP_PLUGINS_DIR_LIST when queried.")
|
||||
parser.add_argument("--total-chunks",
|
||||
type=int, dest="totalChunks", default=1,
|
||||
|
@ -54,7 +56,9 @@ def add_common_arguments(parser):
|
|||
help="name of application profile being tested")
|
||||
parser.add_argument("--build-info-json",
|
||||
type=str, dest="mozInfo", default=None,
|
||||
help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.")
|
||||
help="path to a mozinfo.json including information about the build "
|
||||
"configuration. defaults to looking for mozinfo.json next to "
|
||||
"the script.")
|
||||
parser.add_argument("--shuffle",
|
||||
action="store_true", dest="shuffle", default=False,
|
||||
help="Execute tests in random order")
|
||||
|
@ -66,7 +70,8 @@ def add_common_arguments(parser):
|
|||
parser.add_argument("--symbols-path",
|
||||
action="store", type=str, dest="symbolsPath",
|
||||
default=None,
|
||||
help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols")
|
||||
help="absolute path to directory containing breakpad symbols, "
|
||||
"or the URL of a zip file containing symbols")
|
||||
parser.add_argument("--jscov-dir-prefix",
|
||||
action="store", type=str, dest="jscovdir",
|
||||
default=argparse.SUPPRESS,
|
||||
|
@ -116,9 +121,9 @@ def add_common_arguments(parser):
|
|||
"(with --rerun-failure) or in which to record failed tests")
|
||||
parser.add_argument("--threads",
|
||||
type=int, dest="threadCount", default=0,
|
||||
help="override the number of jobs (threads) when running tests in parallel, "
|
||||
"the default is CPU x 1.5 when running via mach and CPU x 4 when running "
|
||||
"in automation")
|
||||
help="override the number of jobs (threads) when running tests "
|
||||
"in parallel, the default is CPU x 1.5 when running via mach "
|
||||
"and CPU x 4 when running in automation")
|
||||
parser.add_argument("testPaths", nargs="*", default=None,
|
||||
help="Paths of tests to run.")
|
||||
parser.add_argument("--verify",
|
||||
|
@ -129,6 +134,7 @@ def add_common_arguments(parser):
|
|||
type=int, default=3600,
|
||||
help="Maximum time, in seconds, to run in --verify mode.")
|
||||
|
||||
|
||||
def add_remote_arguments(parser):
|
||||
parser.add_argument("--deviceIP", action="store", type=str, dest="deviceIP",
|
||||
help="ip address of remote device to test")
|
||||
|
@ -139,13 +145,12 @@ def add_remote_arguments(parser):
|
|||
parser.add_argument("--objdir", action="store", type=str, dest="objdir",
|
||||
help="local objdir, containing xpcshell binaries")
|
||||
|
||||
|
||||
parser.add_argument("--apk", action="store", type=str, dest="localAPK",
|
||||
help="local path to Fennec APK")
|
||||
|
||||
|
||||
parser.add_argument("--noSetup", action="store_false", dest="setup", default=True,
|
||||
help="do not copy any files to device (to be used only if device is already setup)")
|
||||
help="do not copy any files to device (to be used only if "
|
||||
"device is already setup)")
|
||||
|
||||
parser.add_argument("--local-lib-dir", action="store", type=str, dest="localLib",
|
||||
help="local path to library directory")
|
||||
|
@ -154,7 +159,8 @@ def add_remote_arguments(parser):
|
|||
help="local path to bin directory")
|
||||
|
||||
parser.add_argument("--remoteTestRoot", action="store", type=str, dest="remoteTestRoot",
|
||||
help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)")
|
||||
help="remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests)")
|
||||
|
||||
|
||||
def parser_desktop():
|
||||
|
|
|
@ -16,6 +16,7 @@ flake8:
|
|||
- testing/mozbase
|
||||
- testing/mochitest
|
||||
- testing/talos/
|
||||
- testing/xpcshell
|
||||
- tools/git
|
||||
- tools/lint
|
||||
- tools/mercurial
|
||||
|
|
Загрузка…
Ссылка в новой задаче