Bug 908945 - Fix automation.py's exit code handling; r=jmaher

This commit is contained in:
Vaibhav Agrawal 2014-03-26 06:14:51 -04:00
parent 505934e4c4
commit 710c031709
3 changed files with 67 additions and 13 deletions

View File

@ -449,6 +449,7 @@ class Automation(object):
pk12util = os.path.join(utilityPath, "pk12util" + self.BIN_SUFFIX)
status = self.Process([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env = env).wait()
automationutils.printstatus(status, "certutil")
if status != 0:
return status
@ -460,13 +461,15 @@ class Automation(object):
trustBits = "CT,,"
if root.endswith("-object"):
trustBits = "CT,,CT"
self.Process([certutil, "-A", "-i", os.path.join(certPath, item),
status = self.Process([certutil, "-A", "-i", os.path.join(certPath, item),
"-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
env = env).wait()
automationutils.printstatus(status, "certutil")
if ext == ".client":
self.Process([pk12util, "-i", os.path.join(certPath, item), "-w",
status = self.Process([pk12util, "-i", os.path.join(certPath, item), "-w",
pwfilePath, "-d", profileDir],
env = env).wait()
automationutils.printstatus(status, "pk12util")
os.unlink(pwfilePath)
return 0
@ -654,8 +657,11 @@ class Automation(object):
else:
# We should have a "crashinject" program in our utility path
crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(processPID)]).wait() == 0:
return
if os.path.exists(crashinject):
status = subprocess.Popen([crashinject, str(processPID)]).wait()
automationutils.printstatus(status, "crashinject")
if status == 0:
return
self.log.info("Can't trigger Breakpad, just killing process")
self.killPid(processPID)
@ -728,12 +734,14 @@ class Automation(object):
self.killAndGetStack(browserProcessId, utilityPath, debuggerInfo)
status = proc.wait()
automationutils.printstatus(status, "Main app process")
if status == 0:
self.lastTestSeen = "Main app process exited normally"
if status != 0 and not didTimeout and not hitMaxTime:
self.log.info("TEST-UNEXPECTED-FAIL | %s | Exited with code %d during test run", self.lastTestSeen, status)
if stackFixerProcess is not None:
fixerStatus = stackFixerProcess.wait()
automationutils.printstatus(status, "stackFixerProcess")
if fixerStatus != 0 and not didTimeout and not hitMaxTime:
self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", fixerStatus)
return status

View File

@ -7,8 +7,10 @@ from __future__ import with_statement
import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2, zipfile
import base64
import re
import os
from urlparse import urlparse
from operator import itemgetter
import signal
try:
import mozinfo
@ -155,6 +157,43 @@ def isURL(thing):
# We want to download URLs like http://... but not Windows paths like c:\...
return len(urlparse(thing).scheme) >= 2
# Python does not provide strsignal() even in the very latest 3.x.
# This is a reasonable fake.
def strsig(n):
# Signal numbers run 0 through NSIG-1; an array with NSIG members
# has exactly that many slots
_sigtbl = [None]*signal.NSIG
for k in dir(signal):
if k.startswith("SIG") and not k.startswith("SIG_") and k != "SIGCLD" and k != "SIGPOLL":
_sigtbl[getattr(signal, k)] = k
# Realtime signals mostly have no names
if hasattr(signal, "SIGRTMIN") and hasattr(signal, "SIGRTMAX"):
for r in range(signal.SIGRTMIN+1, signal.SIGRTMAX+1):
_sigtbl[r] = "SIGRTMIN+" + str(r - signal.SIGRTMIN)
# Fill in any remaining gaps
for i in range(signal.NSIG):
if _sigtbl[i] is None:
_sigtbl[i] = "unrecognized signal, number " + str(i)
if n < 0 or n >= signal.NSIG:
return "out-of-range signal, number "+str(n)
return _sigtbl[n]
def printstatus(status, name = ""):
# 'status' is the exit status
if os.name != 'posix':
# Windows error codes are easier to look up if printed in hexadecimal
if status < 0:
status += 2**32
print "TEST-INFO | %s: exit status %x\n" % (name, status)
elif os.WIFEXITED(status):
print "TEST-INFO | %s: exit %d\n" % (name, os.WEXITSTATUS(status))
elif os.WIFSIGNALED(status):
# The python stdlib doesn't appear to have strsignal(), alas
print "TEST-INFO | {}: killed by {}".format(name,strsig(os.WTERMSIG(status)))
else:
# This is probably a can't-happen condition on Unix, but let's be defensive
print "TEST-INFO | %s: undecodable exit status %04x\n" % (name, status)
def addCommonOptions(parser, defaults={}):
parser.add_option("--xre-path",
action = "store", type = "string", dest = "xrePath",
@ -499,10 +538,13 @@ def dumpScreen(utilityPath):
# Need to figure out which OS-dependent tool to use
if mozinfo.isUnix:
utility = [os.path.join(utilityPath, "screentopng")]
utilityname = "screentopng"
elif mozinfo.isMac:
utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png']
utilityname = "screencapture"
elif mozinfo.isWin:
utility = [os.path.join(utilityPath, "screenshot.exe")]
utilityname = "screenshot"
# Get dir where to write the screenshot file
parent_dir = os.environ.get('MOZ_UPLOAD_DIR', None)
@ -515,15 +557,12 @@ def dumpScreen(utilityPath):
tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail-screenshot_', suffix='.png', dir=parent_dir)
os.close(tmpfd)
returncode = subprocess.call(utility + [imgfilename])
printstatus(returncode, utilityname)
except OSError, err:
log.info("Failed to start %s for screenshot: %s",
utility[0], err.strerror)
return
# Check whether the capture utility ran successfully
if returncode != 0:
log.info("%s exited with code %d", utility, returncode)
class ShutdownLeaks(object):
"""
Parses the mochitest run log when running a debug build, assigns all leaked

View File

@ -29,7 +29,7 @@ import traceback
import urllib2
import zipfile
from automationutils import environment, getDebuggerInfo, isURL, KeyValueParseError, parseKeyValue, processLeakLog, systemMemory, dumpScreen, ShutdownLeaks
from automationutils import environment, getDebuggerInfo, isURL, KeyValueParseError, parseKeyValue, processLeakLog, systemMemory, dumpScreen, ShutdownLeaks, printstatus
from datetime import datetime
from manifestparser import TestManifest
from mochitest_options import MochitestOptions
@ -790,8 +790,11 @@ class Mochitest(MochitestUtilsMixin):
if mozinfo.isWin:
# We should have a "crashinject" program in our utility path
crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(processPID)]).wait() == 0:
return
if os.path.exists(crashinject):
status = subprocess.Popen([crashinject, str(processPID)]).wait()
printstatus(status, "crashinject")
if status == 0:
return
else:
try:
os.kill(processPID, signal.SIGABRT)
@ -1019,6 +1022,7 @@ class Mochitest(MochitestUtilsMixin):
# until bug 913970 is fixed regarding mozrunner `wait` not returning status
# see https://bugzilla.mozilla.org/show_bug.cgi?id=913970
status = proc.wait()
printstatus(status, "Main app process")
runner.process_handler = None
if timeout is None:
@ -1497,6 +1501,7 @@ class Mochitest(MochitestUtilsMixin):
pk12util = os.path.join(utilityPath, "pk12util" + bin_suffix)
status = call([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env=env)
printstatus(status, "certutil")
if status:
return status
@ -1508,13 +1513,15 @@ class Mochitest(MochitestUtilsMixin):
trustBits = "CT,,"
if root.endswith("-object"):
trustBits = "CT,,CT"
call([certutil, "-A", "-i", os.path.join(certPath, item),
status = call([certutil, "-A", "-i", os.path.join(certPath, item),
"-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
env=env)
printstatus(status, "certutil")
elif ext == ".client":
call([pk12util, "-i", os.path.join(certPath, item), "-w",
status = call([pk12util, "-i", os.path.join(certPath, item), "-w",
pwfilePath, "-d", profileDir],
env=env)
printstatus(status, "pk2util")
os.unlink(pwfilePath)
return 0