Changes

Jump to: navigation, search

Mozilla BuildBot Trending/Snippets

12,099 bytes added, 00:09, 23 February 2009
no edit summary
==Log File Parser==
<pre>
#!/usr/bin/env python
"""This is a log parser for Mozilla Testing Logs
Written by John Ford in 2009 and made available under MPL/GPL/LGPL"""
 
import re
from sys import argv
 
class Log:
"""I represent a Log. Currently, I only understand how to
parse lines of test output. I do not yet know about myself"""
lines = [] #All LogLine objects
def __init__(self, filename):
"""Create a Log object based on the file at a location"""
print "Log file: %s" % filename
try:
f = open(filename)
self.parseFile(f)
except IOError:
print "Log: encountered error while reading file"
finally:
f.close()
def parseFile(self, file):
"""I take a file object and parse all of its lines. Currently,
I understand most standard XPCShell tests, feed tests, and Reftests"""
rawlines = file.readlines()
for line in rawlines:
###############################
# Special case for feed tests #
###############################
if(re.match(r"PASS \| xml", line) or re.match(r"FAIL \| xml", line)):
try:
self.lines.append(FeedTestLogLine(line))
except InvalidLogLineError:
print "This line is not a feed test but shows up as such:\n%s" % line
#############################
# Special case for reftests #
#############################
elif(re.search(r"REFTEST", line)):
try:
self.lines.append(ReftestLogLine(line))
except InvalidLogLineError:
print "This line is not a reftest but shows up as such:\n%s" % line
###############################
# Standard test output format #
###############################
elif(re.search(r"PASS", line) or re.search(r"FAIL", line) or re.search(r"EXPECTED RANDOM", line)):
try:
self.lines.append(TestLogLine(line))
except InvalidLogLineError:
# TODO: figure out why this line isn't being executed ever
print "This line is not a standard test but shows up as such:\n%s" % line
################################################################
# Make sure that the start time is captured for the feed tests #
################################################################
# This is a bad way of doing this but is there until timestamps
# are added
elif(re.match(r"Start: ", line)):
time = line.replace("Start: ", "").strip()
for x in self.lines:
if(isinstance(x, FeedTestLogLine)):
x.startTime = time
 
def buildNumber(self):
"""I tell you which Build Number I am"""
return 1
def startTime(self):
"""I tell you when I started"""
return 1
def endTime(self):
"""I tell you when I finished"""
return 10
def factory(self):
"""I tell you which buildbot Factory I came from"""
return "f1"
def builder(self):
"""I tell you which buildbot Builder I came from"""
return "mozilla-buildbot"
def slave(self):
"""I tell you which buildbot BuildSlave I came from"""
return "local-osx"
def testCount(self):
"""I tell you how many test's output I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
count = count + 1
return count
def passCount(self):
"""I tell you how many test passes I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.passed()):
count = count + 1
return count
def failCount(self):
"""I tell you how many test fails I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.failed()):
count = count + 1
return count
def unexpectedCount(self):
"""I tell you how many unexpected test results I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.unexpected()):
count = count + 1
return count
def unexpectedPassCount(self):
"""I tell you how many unexpected passes I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.unexpectedPass()):
count = count + 1
return count
def unexpectedFailCount(self):
"""I tell you how many unexpected passes I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.unexpectedFail()):
count = count + 1
return count
def knownFailCount(self):
"""I tell you how many known fails I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.knownFail()):
count = count + 1
return count
def randomCount(self):
"""I tell you how many known fails I found"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.random()):
count = count + 1
return count
def badThingsCount(self):
"""I tell you how many BadThings happend"""
count = 0
for line in self.lines:
if isinstance(line, TestLogLine):
if(line.unexpected() or line.fail()):
count = count + 1
return count
def logURL(self):
"""I tell you where you can find me"""
return "http://www.example.com/waterfall"
def logLines(self):
"""If you want my LogLines, ask me here"""
return self.lines
 
class LogLine:
"""I represent a Log Line. I might be more than one
line of raw output from the log. I understand log output
in the format "X | msg" where X is a time and msg is
the rest of the output"""
startTime = None # Time command starts
msg = None # Message
def __init__(self, line):
chunks = line.split(" | ")
self.startTime = chunks[0].strip()
self.msg = chunks[1].strip()
def time(self):
"""I Tell you the time it took to make this line"""
return "%s minus %s" % startTime, endTime
#def startTime(self):
#"""I tell you the time this item was started"""
#return startTime
def endTime(self):
"""I tell you the time this line ended UNIMPLEMENTED"""
return None
class TestLogLine(LogLine):
"""I am a line of output specific to a Test run.
I understand logs in the format "X | Y | Z | Q"
Where X is a timestamp, Y is test status, Z is
a test name and Q is the test message"""
statusMsg = None # I store PASS, FAIL....
testName = None # I store the name of the test
def __init__(self, line):
"""Parse a line into a TestLogLine output"""
chunks = line.split(" | ")
try:
self.startTime = chunks[0].strip()
self.statusMsg = chunks[1].strip()
self.testName = chunks[2].strip()
self.msg = chunks[3].strip()
except IndexError:
raise InvalidLogLineError("This line does not use the standard log output format")
def passed(self):
"""I tell you if this line passed"""
return re.search("PASS", self.statusMsg) != None
def failed(self):
"""I tell you if this line failed"""
return re.search("FAIL", self.statusMsg) != None
def knownFail(self):
"""I tell you if this test was a known fail"""
return re.search("KNOWN-FAIL", self.statusMsg)
def unexpected(self):
"""I tell you if this was an unexpected result"""
return re.search("UNEXPECTED", self.statusMsg) != None
def unexpectedPass(self):
"""I tell you if this was an unexpected pass"""
return self.passed() and self.unexpected()
def unexpectedFail(self):
"""I tell you if this was an unexpected fail"""
return self.failed() and self.unexpected()
def random(self):
"""I tell you if this was expected random output"""
return re.search(r"\(EXPECTED RANDOM\)", self.statusMsg)
class FeedTestLogLine(TestLogLine):
"""I am a special case for the feed tests. I don't have
timestamps in my output yet, so the Log's parsefile method
adds the same timestamp to all of us. I understand log output
in the form: X | Y | Z | Q where X is test status,
Y and Z are the test name and Q is the test outcome"""
def __init__(self, line):
chunks = line.split(" | ")
try:
self.startTime = repr(0)
self.statusMsg = chunks[0].strip()
self.testName = "%s - %s" % (chunks[1].strip(), chunks[2].strip())
self.msg = chunks[3].strip()
except IndexError:
raise InvalidLogLineError("This line does not use the standard log output format")
class ReftestLogLine(TestLogLine):
"""I am a line of Reftest output. I do not yet have timing information
for each step and take a really long time to run so the suite's start time
is not valid for me. I understand things in the format X | Y | Z where
X is test status (with the word REFTEST removed), Y is the test's name and
Z is any special messages"""
def __init__(self, line):
chunks = line.split(" | ")
try:
self.startTime = repr(0)
self.statusMsg = chunks[0].replace("REFTEST ", "").strip()
self.testName = chunks[1].strip()
try:
self.msg = chunks[2].strip()
except IndexError:
self.msg = "No Message"
except IndexError:
raise InvalidLogLineError("This Reftest does not use the standard log output format")
class InvalidLogLineError(Exception):
"""I am an exception which is raised when someone makes an invalid LogLine"""
pass
if(__name__ == "__main__"):
log = Log(argv[1])
# This is desired output format from Bug443329
# BUILDID/BUILDTIME | TESTTIME | TESTNAME | MACHINE(from this we can map to OS) | STATUS | MSG | link to full log
for line in log.logLines():
if (isinstance(line, TestLogLine)):
print "%s/%s | %s | %s | %s | %s | %s | %s" % (
log.buildNumber(),
repr(log.startTime()),
line.startTime,
line.testName,
log.slave(),
line.statusMsg,
line.msg,
log.logURL())
print """Note:
Build ID, Build Time, Machine Name, Link to log are
all bogus fields"""
""" This code is what i tested with
for line in log.logLines():
if(isinstance(line, TestLogLine)):
print "=" * 100
print "Line start: %s" % line.startTime
print "Line status: %s" % line.statusMsg
print "Line name: %s" % line.testName
print "Line Msg: %s" % line.msg
print "Count: %d" % log.testCount()
print "Fails: %d" % log.failCount()
print "Known Fails: %d" % log.knownFailCount()
print "Passes: %d" % log.passCount()
print "Unexpected: %d" % log.unexpectedCount()
print "UnexpectedP: %d" % log.unexpectedPassCount()
print "UnexpectedF: %d" % log.unexpectedFailCount()
print "Random: %d" % log.randomCount()"""
</pre>
==Date Format Parser==
1
edit

Navigation menu