mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 480279 - 'Allow mochitests to launch under a debugger or valgrind'. r=waldo.
This commit is contained in:
parent
c5833538ac
commit
b603641c69
@ -407,7 +407,7 @@ def environment(env = None, xrePath = DIST_BIN):
|
|||||||
# RUN THE APP #
|
# RUN THE APP #
|
||||||
###############
|
###############
|
||||||
|
|
||||||
def runApp(testURL, env, app, profileDir, extraArgs, runSSLTunnel = False, utilityPath = DIST_BIN, xrePath = DIST_BIN, certPath = CERTS_SRC_DIR):
|
def runApp(testURL, env, app, profileDir, extraArgs, runSSLTunnel = False, utilityPath = DIST_BIN, xrePath = DIST_BIN, certPath = CERTS_SRC_DIR, debuggerInfo = None):
|
||||||
"Run the app, log the duration it took to execute, return the status code."
|
"Run the app, log the duration it took to execute, return the status code."
|
||||||
|
|
||||||
if IS_TEST_BUILD and runSSLTunnel:
|
if IS_TEST_BUILD and runSSLTunnel:
|
||||||
@ -429,6 +429,12 @@ def runApp(testURL, env, app, profileDir, extraArgs, runSSLTunnel = False, utili
|
|||||||
cmd = os.path.abspath(cmd)
|
cmd = os.path.abspath(cmd)
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
|
if debuggerInfo:
|
||||||
|
args.extend(debuggerInfo["args"])
|
||||||
|
args.append(cmd)
|
||||||
|
cmd = os.path.abspath(debuggerInfo["path"])
|
||||||
|
|
||||||
if IS_MAC:
|
if IS_MAC:
|
||||||
args.append("-foreground")
|
args.append("-foreground")
|
||||||
|
|
||||||
@ -446,12 +452,24 @@ def runApp(testURL, env, app, profileDir, extraArgs, runSSLTunnel = False, utili
|
|||||||
args.extend(extraArgs)
|
args.extend(extraArgs)
|
||||||
|
|
||||||
startTime = datetime.now()
|
startTime = datetime.now()
|
||||||
proc = Process([cmd] + args, env = environment(env), stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
|
||||||
|
# Don't redirect stdout and stderr if an interactive debugger is attached
|
||||||
|
if debuggerInfo and debuggerInfo["interactive"]:
|
||||||
|
outputPipe = None
|
||||||
|
else:
|
||||||
|
outputPipe = subprocess.PIPE
|
||||||
|
|
||||||
|
proc = Process([cmd] + args, env = environment(env), stdout = outputPipe, stderr = subprocess.STDOUT)
|
||||||
log.info("INFO | (automation.py) | Application pid: %d", proc.pid)
|
log.info("INFO | (automation.py) | Application pid: %d", proc.pid)
|
||||||
line = proc.stdout.readline()
|
|
||||||
while line != "":
|
if outputPipe is None:
|
||||||
log.info(line.rstrip())
|
log.info("TEST-INFO: Not logging stdout or stderr due to debugger connection")
|
||||||
|
else:
|
||||||
line = proc.stdout.readline()
|
line = proc.stdout.readline()
|
||||||
|
while line != "":
|
||||||
|
log.info(line.rstrip())
|
||||||
|
line = proc.stdout.readline()
|
||||||
|
|
||||||
status = proc.wait()
|
status = proc.wait()
|
||||||
if status != 0:
|
if status != 0:
|
||||||
log.info("TEST-UNEXPECTED-FAIL | (automation.py) | Exited with code %d during test run", status)
|
log.info("TEST-UNEXPECTED-FAIL | (automation.py) | Exited with code %d during test run", status)
|
||||||
|
@ -88,6 +88,23 @@ LEAK_REPORT_FILE = PROFILE_DIRECTORY + "/" + "leaks-report.log"
|
|||||||
|
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
# Map of debugging programs to information about them, like default arguments
|
||||||
|
# and whether or not they are interactive.
|
||||||
|
DEBUGGER_INFO = {
|
||||||
|
# gdb requires that you supply the '--args' flag in order to pass arguments
|
||||||
|
# after the executable name to the executable.
|
||||||
|
"gdb": {
|
||||||
|
"interactive": True,
|
||||||
|
"args": "-q --args"
|
||||||
|
},
|
||||||
|
|
||||||
|
# valgrind doesn't explain much about leaks unless you set the
|
||||||
|
# '--leak-check=full' flag.
|
||||||
|
"valgrind": {
|
||||||
|
"interactive": False,
|
||||||
|
"args": "--leak-check=full"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
# COMMANDLINE OPTIONS #
|
# COMMANDLINE OPTIONS #
|
||||||
@ -206,6 +223,20 @@ class MochitestOptions(optparse.OptionParser):
|
|||||||
help = "copy specified files/dirs to testing profile")
|
help = "copy specified files/dirs to testing profile")
|
||||||
defaults["extraProfileFiles"] = []
|
defaults["extraProfileFiles"] = []
|
||||||
|
|
||||||
|
self.add_option("--debugger",
|
||||||
|
action = "store", dest = "debugger",
|
||||||
|
help = "use the given debugger to launch the application")
|
||||||
|
|
||||||
|
self.add_option("--debugger-args",
|
||||||
|
action = "store", dest = "debuggerArgs",
|
||||||
|
help = "pass the given args to the debugger _before_ "
|
||||||
|
"the application on the command line")
|
||||||
|
|
||||||
|
self.add_option("--debugger-interactive",
|
||||||
|
action = "store_true", dest = "debuggerInteractive",
|
||||||
|
help = "prevents the test harness from redirecting stdout "
|
||||||
|
"and stderr for interactive debuggers")
|
||||||
|
|
||||||
# -h, --help are automatically handled by OptionParser
|
# -h, --help are automatically handled by OptionParser
|
||||||
|
|
||||||
self.set_defaults(**defaults)
|
self.set_defaults(**defaults)
|
||||||
@ -288,6 +319,22 @@ def getFullPath(path):
|
|||||||
"Get an absolute path relative to oldcwd."
|
"Get an absolute path relative to oldcwd."
|
||||||
return os.path.normpath(os.path.join(oldcwd, os.path.expanduser(path)))
|
return os.path.normpath(os.path.join(oldcwd, os.path.expanduser(path)))
|
||||||
|
|
||||||
|
def searchPath(path):
|
||||||
|
"Go one step beyond getFullPath and try the various folders in PATH"
|
||||||
|
# Try looking in the current working directory first.
|
||||||
|
newpath = getFullPath(path)
|
||||||
|
if os.path.exists(newpath):
|
||||||
|
return newpath
|
||||||
|
|
||||||
|
# At this point we have to fail if a directory was given (to prevent cases
|
||||||
|
# like './gdb' from matching '/usr/bin/./gdb').
|
||||||
|
if not os.path.dirname(path):
|
||||||
|
for dir in os.environ['PATH'].split(os.pathsep):
|
||||||
|
newpath = os.path.join(dir, path)
|
||||||
|
if os.path.exists(newpath):
|
||||||
|
return newpath
|
||||||
|
return None
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# MAIN FUNCTION #
|
# MAIN FUNCTION #
|
||||||
#################
|
#################
|
||||||
@ -314,6 +361,32 @@ Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
|
|||||||
options.utilityPath = getFullPath(options.utilityPath)
|
options.utilityPath = getFullPath(options.utilityPath)
|
||||||
options.certPath = getFullPath(options.certPath)
|
options.certPath = getFullPath(options.certPath)
|
||||||
|
|
||||||
|
debuggerInfo = None
|
||||||
|
|
||||||
|
if options.debugger:
|
||||||
|
debuggerPath = searchPath(options.debugger)
|
||||||
|
if not debuggerPath:
|
||||||
|
print "Error: Path %s doesn't exist." % options.debugger
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
debuggerName = os.path.basename(debuggerPath).lower()
|
||||||
|
|
||||||
|
def getDebuggerInfo(type, default):
|
||||||
|
if debuggerName in DEBUGGER_INFO and type in DEBUGGER_INFO[debuggerName]:
|
||||||
|
return DEBUGGER_INFO[debuggerName][type]
|
||||||
|
return default
|
||||||
|
|
||||||
|
debuggerInfo = {
|
||||||
|
"path": debuggerPath,
|
||||||
|
"interactive" : getDebuggerInfo("interactive", False),
|
||||||
|
"args": getDebuggerInfo("args", "").split()
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.debuggerArgs:
|
||||||
|
debuggerInfo["args"] = options.debuggerArgs.split()
|
||||||
|
if options.debuggerInteractive:
|
||||||
|
debuggerInfo["interactive"] = options.debuggerInteractive
|
||||||
|
|
||||||
# browser environment
|
# browser environment
|
||||||
browserEnv = dict(os.environ)
|
browserEnv = dict(os.environ)
|
||||||
|
|
||||||
@ -399,7 +472,8 @@ Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
|
|||||||
runSSLTunnel = True,
|
runSSLTunnel = True,
|
||||||
utilityPath = options.utilityPath,
|
utilityPath = options.utilityPath,
|
||||||
xrePath = options.xrePath,
|
xrePath = options.xrePath,
|
||||||
certPath = options.certPath)
|
certPath=options.certPath,
|
||||||
|
debuggerInfo=debuggerInfo)
|
||||||
|
|
||||||
# Server's no longer needed, and perhaps more importantly, anything it might
|
# Server's no longer needed, and perhaps more importantly, anything it might
|
||||||
# spew to console shouldn't disrupt the leak information table we print next.
|
# spew to console shouldn't disrupt the leak information table we print next.
|
||||||
|
Loading…
Reference in New Issue
Block a user