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