Home | History | Annotate | Download | only in log
      1 # -*- coding: utf-8 -*-
      2 
      3 import os
      4 import sys
      5 import codecs
      6 import xml.dom.minidom
      7 import xml.sax
      8 import xml.sax.handler
      9 from log_parser import BatchResultParser, StatusCode
     10 
     11 STYLESHEET_FILENAME = "testlog.xsl"
     12 LOG_VERSION			= '0.3.2'
     13 
     14 class BuildXMLLogHandler(xml.sax.handler.ContentHandler):
     15 	def __init__ (self, doc):
     16 		self.doc			= doc
     17 		self.elementStack	= []
     18 		self.rootElements	= []
     19 
     20 	def getRootElements (self):
     21 		return self.rootElements
     22 
     23 	def pushElement (self, elem):
     24 		if len(self.elementStack) == 0:
     25 			self.rootElements.append(elem)
     26 		else:
     27 			self.getCurElement().appendChild(elem)
     28 		self.elementStack.append(elem)
     29 
     30 	def popElement (self):
     31 		self.elementStack.pop()
     32 
     33 	def getCurElement (self):
     34 		if len(self.elementStack) > 0:
     35 			return self.elementStack[-1]
     36 		else:
     37 			return None
     38 
     39 	def startDocument (self):
     40 		pass
     41 
     42 	def endDocument (self):
     43 		pass
     44 
     45 	def startElement (self, name, attrs):
     46 		elem = self.doc.createElement(name)
     47 		for name in attrs.getNames():
     48 			value = attrs.getValue(name)
     49 			elem.setAttribute(name, value)
     50 		self.pushElement(elem)
     51 
     52 	def endElement (self, name):
     53 		self.popElement()
     54 
     55 	def characters (self, content):
     56 		# Discard completely empty content
     57 		if len(content.strip()) == 0:
     58 			return
     59 
     60 		# Append as text node (not pushed to stack)
     61 		if self.getCurElement() != None:
     62 			txt = self.doc.createTextNode(content)
     63 			self.getCurElement().appendChild(txt)
     64 
     65 class LogErrorHandler(xml.sax.handler.ErrorHandler):
     66 	def __init__ (self):
     67 		pass
     68 
     69 	def error (self, err):
     70 		#print "error(%s)" % str(err)
     71 		pass
     72 
     73 	def fatalError (self, err):
     74 		#print "fatalError(%s)" % str(err)
     75 		pass
     76 
     77 	def warning (self, warn):
     78 		#print "warning(%s)" % str(warn)
     79 		pass
     80 
     81 def findFirstElementByName (nodes, name):
     82 	for node in nodes:
     83 		if node.nodeName == name:
     84 			return node
     85 		chFound = findFirstElementByName(node.childNodes, name)
     86 		if chFound != None:
     87 			return chFound
     88 	return None
     89 
     90 # Normalizes potentially broken (due to crash for example) log data to XML element tree
     91 def normalizeToXml (result, doc):
     92 	handler		= BuildXMLLogHandler(doc)
     93 	errHandler	= LogErrorHandler()
     94 
     95 	xml.sax.parseString(result.log, handler, errHandler)
     96 
     97 	rootNodes = handler.getRootElements()
     98 
     99 	# Check if we have TestCaseResult
    100 	testCaseResult = findFirstElementByName(rootNodes, 'TestCaseResult')
    101 	if testCaseResult == None:
    102 		# Create TestCaseResult element
    103 		testCaseResult = doc.createElement('TestCaseResult')
    104 		testCaseResult.setAttribute('CasePath', result.name)
    105 		testCaseResult.setAttribute('CaseType', 'SelfValidate') # \todo [pyry] Not recoverable..
    106 		testCaseResult.setAttribute('Version', LOG_VERSION)
    107 		rootNodes.append(testCaseResult)
    108 
    109 	# Check if we have Result element
    110 	resultElem = findFirstElementByName(rootNodes, 'Result')
    111 	if resultElem == None:
    112 		# Create result element
    113 		resultElem = doc.createElement('Result')
    114 		resultElem.setAttribute('StatusCode', result.statusCode)
    115 		resultElem.appendChild(doc.createTextNode(result.statusDetails))
    116 		testCaseResult.appendChild(resultElem)
    117 
    118 	return rootNodes
    119 
    120 def logToXml (inFile, outFile):
    121 	parser	= BatchResultParser()
    122 	results	= parser.parseFile(inFile)
    123 
    124 	dstDoc			= xml.dom.minidom.Document()
    125 	batchResultNode	= dstDoc.createElement('BatchResult')
    126 	batchResultNode.setAttribute("FileName", os.path.basename(inFile))
    127 
    128 	dstDoc.appendChild(batchResultNode)
    129 
    130 	for result in results:
    131 		# Normalize log to valid XML
    132 		rootNodes = normalizeToXml(result, dstDoc)
    133 		for node in rootNodes:
    134 			batchResultNode.appendChild(node)
    135 
    136 	# Summary
    137 	countByStatusCode = {}
    138 	for code in StatusCode.STATUS_CODES:
    139 		countByStatusCode[code] = 0
    140 
    141 	for result in results:
    142 		countByStatusCode[result.statusCode] += 1
    143 
    144 	summaryElem = dstDoc.createElement('ResultTotals')
    145 	for code in StatusCode.STATUS_CODES:
    146 		summaryElem.setAttribute(code, "%d" % countByStatusCode[code])
    147 	summaryElem.setAttribute('All', "%d" % len(results))
    148 	batchResultNode.appendChild(summaryElem)
    149 
    150 	text = dstDoc.toprettyxml()
    151 
    152 	out = codecs.open(outFile, "wb", encoding="utf-8")
    153 
    154 	# Write custom headers
    155 	out.write("<?xml version=\"1.0\"?>\n")
    156 	out.write("<?xml-stylesheet href=\"%s\" type=\"text/xsl\"?>\n" % STYLESHEET_FILENAME)
    157 
    158 	for line in text.splitlines()[1:]:
    159 		out.write(line)
    160 		out.write("\n")
    161 
    162 	out.close()
    163 
    164 if __name__ == "__main__":
    165 	if len(sys.argv) != 3:
    166 		print "%s: [test log] [dst file]" % sys.argv[0]
    167 		sys.exit(-1)
    168 
    169 	logToXml(sys.argv[1], sys.argv[2])
    170