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