Bug 480279 - 'Allow mochitests to launch under a debugger or valgrind'. r=waldo.

This commit is contained in:
Ben Turner 2009-03-06 15:28:20 -08:00
parent c5833538ac
commit b603641c69
2 changed files with 98 additions and 6 deletions

View File

@ -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)

View File

@ -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.