| # -*- coding: utf-8 -*- |
| |
| #------------------------------------------------------------------------- |
| # drawElements Quality Program utilities |
| # -------------------------------------- |
| # |
| # Copyright 2015 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| #------------------------------------------------------------------------- |
| |
| import os |
| import sys |
| import codecs |
| import xml.dom.minidom |
| import xml.sax |
| import xml.sax.handler |
| from log_parser import BatchResultParser, StatusCode |
| |
| STYLESHEET_FILENAME = "testlog.xsl" |
| LOG_VERSION = '0.3.2' |
| |
| class BuildXMLLogHandler(xml.sax.handler.ContentHandler): |
| def __init__ (self, doc): |
| self.doc = doc |
| self.elementStack = [] |
| self.rootElements = [] |
| |
| def getRootElements (self): |
| return self.rootElements |
| |
| def pushElement (self, elem): |
| if len(self.elementStack) == 0: |
| self.rootElements.append(elem) |
| else: |
| self.getCurElement().appendChild(elem) |
| self.elementStack.append(elem) |
| |
| def popElement (self): |
| self.elementStack.pop() |
| |
| def getCurElement (self): |
| if len(self.elementStack) > 0: |
| return self.elementStack[-1] |
| else: |
| return None |
| |
| def startDocument (self): |
| pass |
| |
| def endDocument (self): |
| pass |
| |
| def startElement (self, name, attrs): |
| elem = self.doc.createElement(name) |
| for name in attrs.getNames(): |
| value = attrs.getValue(name) |
| elem.setAttribute(name, value) |
| self.pushElement(elem) |
| |
| def endElement (self, name): |
| self.popElement() |
| |
| def characters (self, content): |
| # Discard completely empty content |
| if len(content.strip()) == 0: |
| return |
| |
| # Append as text node (not pushed to stack) |
| if self.getCurElement() != None: |
| txt = self.doc.createTextNode(content) |
| self.getCurElement().appendChild(txt) |
| |
| class LogErrorHandler(xml.sax.handler.ErrorHandler): |
| def __init__ (self): |
| pass |
| |
| def error (self, err): |
| #print "error(%s)" % str(err) |
| pass |
| |
| def fatalError (self, err): |
| #print "fatalError(%s)" % str(err) |
| pass |
| |
| def warning (self, warn): |
| #print "warning(%s)" % str(warn) |
| pass |
| |
| def findFirstElementByName (nodes, name): |
| for node in nodes: |
| if node.nodeName == name: |
| return node |
| chFound = findFirstElementByName(node.childNodes, name) |
| if chFound != None: |
| return chFound |
| return None |
| |
| # Normalizes potentially broken (due to crash for example) log data to XML element tree |
| def normalizeToXml (result, doc): |
| handler = BuildXMLLogHandler(doc) |
| errHandler = LogErrorHandler() |
| |
| xml.sax.parseString(result.log, handler, errHandler) |
| |
| rootNodes = handler.getRootElements() |
| |
| # Check if we have TestCaseResult |
| testCaseResult = findFirstElementByName(rootNodes, 'TestCaseResult') |
| if testCaseResult == None: |
| # Create TestCaseResult element |
| testCaseResult = doc.createElement('TestCaseResult') |
| testCaseResult.setAttribute('CasePath', result.name) |
| testCaseResult.setAttribute('CaseType', 'SelfValidate') # \todo [pyry] Not recoverable.. |
| testCaseResult.setAttribute('Version', LOG_VERSION) |
| rootNodes.append(testCaseResult) |
| |
| # Check if we have Result element |
| resultElem = findFirstElementByName(rootNodes, 'Result') |
| if resultElem == None: |
| # Create result element |
| resultElem = doc.createElement('Result') |
| resultElem.setAttribute('StatusCode', result.statusCode) |
| resultElem.appendChild(doc.createTextNode(result.statusDetails)) |
| testCaseResult.appendChild(resultElem) |
| |
| return rootNodes |
| |
| def logToXml (inFile, outFile): |
| parser = BatchResultParser() |
| results = parser.parseFile(inFile) |
| |
| dstDoc = xml.dom.minidom.Document() |
| batchResultNode = dstDoc.createElement('BatchResult') |
| batchResultNode.setAttribute("FileName", os.path.basename(inFile)) |
| |
| dstDoc.appendChild(batchResultNode) |
| |
| for result in results: |
| # Normalize log to valid XML |
| rootNodes = normalizeToXml(result, dstDoc) |
| for node in rootNodes: |
| batchResultNode.appendChild(node) |
| |
| # Summary |
| countByStatusCode = {} |
| for code in StatusCode.STATUS_CODES: |
| countByStatusCode[code] = 0 |
| |
| for result in results: |
| countByStatusCode[result.statusCode] += 1 |
| |
| summaryElem = dstDoc.createElement('ResultTotals') |
| for code in StatusCode.STATUS_CODES: |
| summaryElem.setAttribute(code, "%d" % countByStatusCode[code]) |
| summaryElem.setAttribute('All', "%d" % len(results)) |
| batchResultNode.appendChild(summaryElem) |
| |
| text = dstDoc.toprettyxml() |
| |
| out = codecs.open(outFile, "wb", encoding="utf-8") |
| |
| # Write custom headers |
| out.write("<?xml version=\"1.0\"?>\n") |
| out.write("<?xml-stylesheet href=\"%s\" type=\"text/xsl\"?>\n" % STYLESHEET_FILENAME) |
| |
| for line in text.splitlines()[1:]: |
| out.write(line) |
| out.write("\n") |
| |
| out.close() |
| |
| if __name__ == "__main__": |
| if len(sys.argv) != 3: |
| print "%s: [test log] [dst file]" % sys.argv[0] |
| sys.exit(-1) |
| |
| logToXml(sys.argv[1], sys.argv[2]) |