working on build file
This commit is contained in:
218
scripts/log_parser.py
git.filemode.normal_file
218
scripts/log_parser.py
git.filemode.normal_file
@@ -0,0 +1,218 @@
|
||||
# -*- 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 shlex
|
||||
import sys
|
||||
import xml.dom.minidom
|
||||
|
||||
class StatusCode:
|
||||
PASS = 'Pass'
|
||||
FAIL = 'Fail'
|
||||
QUALITY_WARNING = 'QualityWarning'
|
||||
COMPATIBILITY_WARNING = 'CompatibilityWarning'
|
||||
PENDING = 'Pending'
|
||||
NOT_SUPPORTED = 'NotSupported'
|
||||
RESOURCE_ERROR = 'ResourceError'
|
||||
INTERNAL_ERROR = 'InternalError'
|
||||
CRASH = 'Crash'
|
||||
TIMEOUT = 'Timeout'
|
||||
|
||||
STATUS_CODES = [
|
||||
PASS,
|
||||
FAIL,
|
||||
QUALITY_WARNING,
|
||||
COMPATIBILITY_WARNING,
|
||||
PENDING,
|
||||
NOT_SUPPORTED,
|
||||
RESOURCE_ERROR,
|
||||
INTERNAL_ERROR,
|
||||
CRASH,
|
||||
TIMEOUT
|
||||
]
|
||||
STATUS_CODE_SET = set(STATUS_CODES)
|
||||
|
||||
@staticmethod
|
||||
def isValid (code):
|
||||
return code in StatusCode.STATUS_CODE_SET
|
||||
|
||||
class TestCaseResult:
|
||||
def __init__ (self, name, statusCode, statusDetails, log):
|
||||
self.name = name
|
||||
self.statusCode = statusCode
|
||||
self.statusDetails = statusDetails
|
||||
self.log = log
|
||||
|
||||
def __str__ (self):
|
||||
return "%s: %s (%s)" % (self.name, self.statusCode, self.statusDetails)
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__ (self, filename, line, message):
|
||||
self.filename = filename
|
||||
self.line = line
|
||||
self.message = message
|
||||
|
||||
def __str__ (self):
|
||||
return "%s:%d: %s" % (self.filename, self.line, self.message)
|
||||
|
||||
def splitContainerLine (line):
|
||||
if sys.version_info > (3, 0):
|
||||
# In Python 3, shlex works better with unicode.
|
||||
return shlex.split(line)
|
||||
else:
|
||||
# In Python 2, shlex works better with bytes, so encode and decode again upon return.
|
||||
return [w.decode('utf-8') for w in shlex.split(line.encode('utf-8'))]
|
||||
|
||||
def getNodeText (node):
|
||||
rc = []
|
||||
for node in node.childNodes:
|
||||
if node.nodeType == node.TEXT_NODE:
|
||||
rc.append(node.data)
|
||||
return ''.join(rc)
|
||||
|
||||
class BatchResultParser:
|
||||
def __init__ (self):
|
||||
pass
|
||||
|
||||
def parseFile (self, filename):
|
||||
self.init(filename)
|
||||
|
||||
f = open(filename, 'rb')
|
||||
for line in f:
|
||||
self.parseLine(line)
|
||||
self.curLine += 1
|
||||
f.close()
|
||||
|
||||
return self.testCaseResults
|
||||
|
||||
def getNextTestCaseResult (self, file):
|
||||
try:
|
||||
del self.testCaseResults[:]
|
||||
self.curResultText = None
|
||||
|
||||
isNextResult = self.parseLine(next(file))
|
||||
while not isNextResult:
|
||||
isNextResult = self.parseLine(next(file))
|
||||
|
||||
# Return the next TestCaseResult
|
||||
return self.testCaseResults.pop()
|
||||
|
||||
except StopIteration:
|
||||
# If end of file was reached and there is no log left, the parsing finished successful (return None).
|
||||
# Otherwise, if there is still log to be parsed, it means that there was a crash.
|
||||
if self.curResultText:
|
||||
return TestCaseResult(self.curCaseName, StatusCode.CRASH, StatusCode.CRASH, self.curResultText)
|
||||
else:
|
||||
return None
|
||||
|
||||
def init (self, filename):
|
||||
# Results
|
||||
self.sessionInfo = []
|
||||
self.testCaseResults = []
|
||||
|
||||
# State
|
||||
self.curResultText = None
|
||||
self.curCaseName = None
|
||||
|
||||
# Error context
|
||||
self.curLine = 1
|
||||
self.filename = filename
|
||||
|
||||
def parseLine (self, line):
|
||||
# Some test shaders contain invalid characters.
|
||||
text = line.decode('utf-8', 'ignore')
|
||||
if len(text) > 0 and text[0] == '#':
|
||||
return self.parseContainerLine(line)
|
||||
elif self.curResultText != None:
|
||||
self.curResultText += line
|
||||
return None
|
||||
# else: just ignored
|
||||
|
||||
def parseContainerLine (self, line):
|
||||
isTestCaseResult = False
|
||||
# Some test shaders contain invalid characters.
|
||||
text = line.decode('utf-8', 'ignore')
|
||||
args = splitContainerLine(text)
|
||||
if args[0] == "#sessionInfo":
|
||||
if len(args) < 3:
|
||||
print(args)
|
||||
self.parseError("Invalid #sessionInfo")
|
||||
self.sessionInfo.append((args[1], ' '.join(args[2:])))
|
||||
elif args[0] == "#beginSession" or args[0] == "#endSession":
|
||||
pass # \todo [pyry] Validate
|
||||
elif args[0] == "#beginTestCaseResult":
|
||||
if len(args) != 2 or self.curCaseName != None:
|
||||
self.parseError("Invalid #beginTestCaseResult")
|
||||
self.curCaseName = args[1]
|
||||
self.curResultText = b""
|
||||
elif args[0] == "#endTestCaseResult":
|
||||
if len(args) != 1 or self.curCaseName == None:
|
||||
self.parseError("Invalid #endTestCaseResult")
|
||||
self.parseTestCaseResult(self.curCaseName, self.curResultText)
|
||||
self.curCaseName = None
|
||||
self.curResultText = None
|
||||
isTestCaseResult = True
|
||||
elif args[0] == "#terminateTestCaseResult":
|
||||
if len(args) < 2 or self.curCaseName == None:
|
||||
self.parseError("Invalid #terminateTestCaseResult")
|
||||
statusCode = ' '.join(args[1:])
|
||||
statusDetails = statusCode
|
||||
|
||||
if not StatusCode.isValid(statusCode):
|
||||
# Legacy format
|
||||
if statusCode == "Watchdog timeout occurred.":
|
||||
statusCode = StatusCode.TIMEOUT
|
||||
else:
|
||||
statusCode = StatusCode.CRASH
|
||||
|
||||
# Do not try to parse at all since XML is likely broken
|
||||
self.testCaseResults.append(TestCaseResult(self.curCaseName, statusCode, statusDetails, self.curResultText))
|
||||
|
||||
self.curCaseName = None
|
||||
self.curResultText = None
|
||||
isTestCaseResult = True
|
||||
else:
|
||||
# Assume this is result text
|
||||
if self.curResultText != None:
|
||||
self.curResultText += line
|
||||
|
||||
return isTestCaseResult
|
||||
|
||||
def parseTestCaseResult (self, name, log):
|
||||
try:
|
||||
# The XML parser has troubles with invalid characters deliberately included in the shaders.
|
||||
# This line removes such characters before calling the parser
|
||||
log = log.decode('utf-8','ignore').encode("utf-8")
|
||||
doc = xml.dom.minidom.parseString(log)
|
||||
resultItems = doc.getElementsByTagName('Result')
|
||||
if len(resultItems) != 1:
|
||||
self.parseError("Expected 1 <Result>, found %d" % len(resultItems))
|
||||
|
||||
statusCode = resultItems[0].getAttributeNode('StatusCode').nodeValue
|
||||
statusDetails = getNodeText(resultItems[0])
|
||||
except Exception as e:
|
||||
statusCode = StatusCode.INTERNAL_ERROR
|
||||
statusDetails = "XML parsing failed: %s" % str(e)
|
||||
|
||||
self.testCaseResults.append(TestCaseResult(name, statusCode, statusDetails, log))
|
||||
|
||||
def parseError (self, message):
|
||||
raise ParseError(self.filename, self.curLine, message)
|
||||
Reference in New Issue
Block a user