Bug 958897 - ssltunnel lives if mochitest killed. r=jmaher

[PATCH] Made Mochitest.runApp() clean up after itself in case of exception
This commit is contained in:
Kevin Cox 2014-03-23 10:20:32 -04:00
Родитель b253190ddb
Коммит a844a7ae48
1 изменённых файлов: 124 добавлений и 121 удалений

Просмотреть файл

@ -907,149 +907,152 @@ class Mochitest(MochitestUtilsMixin):
# copy env so we don't munge the caller's environment # copy env so we don't munge the caller's environment
env = env.copy() env = env.copy()
# set process log environment variable # make sure we clean up after ourselves.
tmpfd, processLog = tempfile.mkstemp(suffix='pidlog') try:
os.close(tmpfd) # set process log environment variable
env["MOZ_PROCESS_LOG"] = processLog tmpfd, processLog = tempfile.mkstemp(suffix='pidlog')
os.close(tmpfd)
env["MOZ_PROCESS_LOG"] = processLog
if self.runSSLTunnel: if self.runSSLTunnel:
# create certificate database for the profile # create certificate database for the profile
# TODO: this should really be upstreamed somewhere, maybe mozprofile # TODO: this should really be upstreamed somewhere, maybe mozprofile
certificateStatus = self.fillCertificateDB(self.profile.profile, certificateStatus = self.fillCertificateDB(self.profile.profile,
certPath, certPath,
utilityPath, utilityPath,
xrePath) xrePath)
if certificateStatus: if certificateStatus:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Certificate integration failed") log.info("TEST-UNEXPECTED-FAIL | runtests.py | Certificate integration failed")
return certificateStatus return certificateStatus
# start ssltunnel to provide https:// URLs capability # start ssltunnel to provide https:// URLs capability
ssltunnel = os.path.join(utilityPath, "ssltunnel" + bin_suffix) ssltunnel = os.path.join(utilityPath, "ssltunnel" + bin_suffix)
ssltunnel_cfg = os.path.join(self.profile.profile, "ssltunnel.cfg") ssltunnel_cfg = os.path.join(self.profile.profile, "ssltunnel.cfg")
ssltunnelProcess = mozprocess.ProcessHandler([ssltunnel, ssltunnel_cfg], ssltunnelProcess = mozprocess.ProcessHandler([ssltunnel, ssltunnel_cfg],
env=environment(xrePath=xrePath)) env=environment(xrePath=xrePath))
ssltunnelProcess.run() ssltunnelProcess.run()
log.info("INFO | runtests.py | SSL tunnel pid: %d", ssltunnelProcess.pid) log.info("INFO | runtests.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
else: else:
ssltunnelProcess = None ssltunnelProcess = None
if interactive: if interactive:
# If an interactive debugger is attached, # If an interactive debugger is attached,
# don't use timeouts, and don't capture ctrl-c. # don't use timeouts, and don't capture ctrl-c.
timeout = None timeout = None
signal.signal(signal.SIGINT, lambda sigid, frame: None) signal.signal(signal.SIGINT, lambda sigid, frame: None)
# build command line # build command line
cmd = os.path.abspath(app) cmd = os.path.abspath(app)
args = list(extraArgs) args = list(extraArgs)
# TODO: mozrunner should use -foreground at least for mac # TODO: mozrunner should use -foreground at least for mac
# https://bugzilla.mozilla.org/show_bug.cgi?id=916512 # https://bugzilla.mozilla.org/show_bug.cgi?id=916512
args.append('-foreground') args.append('-foreground')
if testUrl: if testUrl:
if debuggerInfo and debuggerInfo['requiresEscapedArgs']: if debuggerInfo and debuggerInfo['requiresEscapedArgs']:
testUrl = testUrl.replace("&", "\\&") testUrl = testUrl.replace("&", "\\&")
args.append(testUrl) args.append(testUrl)
if mozinfo.info["debug"] and not webapprtChrome: if mozinfo.info["debug"] and not webapprtChrome:
shutdownLeaks = ShutdownLeaks(log.info) shutdownLeaks = ShutdownLeaks(log.info)
else: else:
shutdownLeaks = None shutdownLeaks = None
# create an instance to process the output # create an instance to process the output
outputHandler = self.OutputHandler(harness=self, outputHandler = self.OutputHandler(harness=self,
utilityPath=utilityPath, utilityPath=utilityPath,
symbolsPath=symbolsPath, symbolsPath=symbolsPath,
dump_screen_on_timeout=not debuggerInfo, dump_screen_on_timeout=not debuggerInfo,
hide_subtests=hide_subtests, hide_subtests=hide_subtests,
shutdownLeaks=shutdownLeaks, shutdownLeaks=shutdownLeaks,
) )
def timeoutHandler(): def timeoutHandler():
outputHandler.log_output_buffer() outputHandler.log_output_buffer()
browserProcessId = outputHandler.browserProcessId browserProcessId = outputHandler.browserProcessId
self.handleTimeout(timeout, proc, utilityPath, debuggerInfo, browserProcessId) self.handleTimeout(timeout, proc, utilityPath, debuggerInfo, browserProcessId)
kp_kwargs = {'kill_on_timeout': False, kp_kwargs = {'kill_on_timeout': False,
'onTimeout': [timeoutHandler]} 'onTimeout': [timeoutHandler]}
kp_kwargs['processOutputLine'] = [outputHandler] kp_kwargs['processOutputLine'] = [outputHandler]
# create mozrunner instance and start the system under test process # create mozrunner instance and start the system under test process
self.lastTestSeen = self.test_name self.lastTestSeen = self.test_name
startTime = datetime.now() startTime = datetime.now()
# b2g desktop requires FirefoxRunner even though appname is b2g # b2g desktop requires FirefoxRunner even though appname is b2g
if mozinfo.info.get('appname') == 'b2g' and mozinfo.info.get('toolkit') != 'gonk': if mozinfo.info.get('appname') == 'b2g' and mozinfo.info.get('toolkit') != 'gonk':
runner_cls = mozrunner.FirefoxRunner runner_cls = mozrunner.FirefoxRunner
else: else:
runner_cls = mozrunner.runners.get(mozinfo.info.get('appname', 'firefox'), runner_cls = mozrunner.runners.get(mozinfo.info.get('appname', 'firefox'),
mozrunner.Runner) mozrunner.Runner)
runner = runner_cls(profile=self.profile, runner = runner_cls(profile=self.profile,
binary=cmd, binary=cmd,
cmdargs=args, cmdargs=args,
env=env, env=env,
process_class=mozprocess.ProcessHandlerMixin, process_class=mozprocess.ProcessHandlerMixin,
kp_kwargs=kp_kwargs, kp_kwargs=kp_kwargs,
) )
# XXX work around bug 898379 until mozrunner is updated for m-c; see # XXX work around bug 898379 until mozrunner is updated for m-c; see
# https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c49 # https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c49
runner.kp_kwargs = kp_kwargs runner.kp_kwargs = kp_kwargs
# start the runner # start the runner
runner.start(debug_args=debug_args, runner.start(debug_args=debug_args,
interactive=interactive, interactive=interactive,
outputTimeout=timeout) outputTimeout=timeout)
proc = runner.process_handler proc = runner.process_handler
log.info("INFO | runtests.py | Application pid: %d", proc.pid) log.info("INFO | runtests.py | Application pid: %d", proc.pid)
if onLaunch is not None: if onLaunch is not None:
# Allow callers to specify an onLaunch callback to be fired after the # Allow callers to specify an onLaunch callback to be fired after the
# app is launched. # app is launched.
# We call onLaunch for b2g desktop mochitests so that we can # We call onLaunch for b2g desktop mochitests so that we can
# run a Marionette script after gecko has completed startup. # run a Marionette script after gecko has completed startup.
onLaunch() onLaunch()
# wait until app is finished # wait until app is finished
# XXX copy functionality from # XXX copy functionality from
# https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/runner.py#L61 # https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/runner.py#L61
# until bug 913970 is fixed regarding mozrunner `wait` not returning status # until bug 913970 is fixed regarding mozrunner `wait` not returning status
# see https://bugzilla.mozilla.org/show_bug.cgi?id=913970 # see https://bugzilla.mozilla.org/show_bug.cgi?id=913970
status = proc.wait() status = proc.wait()
runner.process_handler = None runner.process_handler = None
if timeout is None: if timeout is None:
didTimeout = False didTimeout = False
else: else:
didTimeout = proc.didTimeout didTimeout = proc.didTimeout
# finalize output handler # finalize output handler
outputHandler.finish(didTimeout) outputHandler.finish(didTimeout)
# record post-test information # record post-test information
if status: if status:
log.info("TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s", self.lastTestSeen, status) log.info("TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s", self.lastTestSeen, status)
else: else:
self.lastTestSeen = 'Main app process exited normally' self.lastTestSeen = 'Main app process exited normally'
log.info("INFO | runtests.py | Application ran for: %s", str(datetime.now() - startTime)) log.info("INFO | runtests.py | Application ran for: %s", str(datetime.now() - startTime))
# Do a final check for zombie child processes. # Do a final check for zombie child processes.
zombieProcesses = self.checkForZombies(processLog, utilityPath, debuggerInfo) zombieProcesses = self.checkForZombies(processLog, utilityPath, debuggerInfo)
# check for crashes # check for crashes
minidump_path = os.path.join(self.profile.profile, "minidumps") minidump_path = os.path.join(self.profile.profile, "minidumps")
crashed = mozcrash.check_for_crashes(minidump_path, crashed = mozcrash.check_for_crashes(minidump_path,
symbolsPath, symbolsPath,
test_name=self.lastTestSeen) test_name=self.lastTestSeen)
if crashed or zombieProcesses: if crashed or zombieProcesses:
status = 1 status = 1
# cleanup finally:
if os.path.exists(processLog): # cleanup
os.remove(processLog) if os.path.exists(processLog):
if ssltunnelProcess: os.remove(processLog)
ssltunnelProcess.kill() if ssltunnelProcess:
ssltunnelProcess.kill()
return status return status