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 shlex
     24 import xml.dom.minidom
     25 
     26 class StatusCode:
     27 	PASS					= 'Pass'
     28 	FAIL					= 'Fail'
     29 	QUALITY_WARNING			= 'QualityWarning'
     30 	COMPATIBILITY_WARNING	= 'CompatibilityWarning'
     31 	PENDING					= 'Pending'
     32 	NOT_SUPPORTED			= 'NotSupported'
     33 	RESOURCE_ERROR			= 'ResourceError'
     34 	INTERNAL_ERROR			= 'InternalError'
     35 	CRASH					= 'Crash'
     36 	TIMEOUT					= 'Timeout'
     37 
     38 	STATUS_CODES			= [
     39 		PASS,
     40 		FAIL,
     41 		QUALITY_WARNING,
     42 		COMPATIBILITY_WARNING,
     43 		PENDING,
     44 		NOT_SUPPORTED,
     45 		RESOURCE_ERROR,
     46 		INTERNAL_ERROR,
     47 		CRASH,
     48 		TIMEOUT
     49 		]
     50 	STATUS_CODE_SET			= set(STATUS_CODES)
     51 
     52 	@staticmethod
     53 	def isValid (code):
     54 		return code in StatusCode.STATUS_CODE_SET
     55 
     56 class TestCaseResult:
     57 	def __init__ (self, name, statusCode, statusDetails, log):
     58 		self.name			= name
     59 		self.statusCode		= statusCode
     60 		self.statusDetails	= statusDetails
     61 		self.log			= log
     62 
     63 	def __str__ (self):
     64 		return "%s: %s (%s)" % (self.name, self.statusCode, self.statusDetails)
     65 
     66 class ParseError(Exception):
     67 	def __init__ (self, filename, line, message):
     68 		self.filename	= filename
     69 		self.line		= line
     70 		self.message	= message
     71 
     72 	def __str__ (self):
     73 		return "%s:%d: %s" % (self.filename, self.line, self.message)
     74 
     75 def splitContainerLine (line):
     76 	return shlex.split(line)
     77 
     78 def getNodeText (node):
     79 	rc = []
     80 	for node in node.childNodes:
     81 		if node.nodeType == node.TEXT_NODE:
     82 			rc.append(node.data)
     83 	return ''.join(rc)
     84 
     85 class BatchResultParser:
     86 	def __init__ (self):
     87 		pass
     88 
     89 	def parseFile (self, filename):
     90 		self.init(filename)
     91 
     92 		f = open(filename, 'rb')
     93 		for line in f:
     94 			self.parseLine(line)
     95 			self.curLine += 1
     96 		f.close()
     97 
     98 		return self.testCaseResults
     99 
    100 	def init (self, filename):
    101 		# Results
    102 		self.sessionInfo		= []
    103 		self.testCaseResults	= []
    104 
    105 		# State
    106 		self.curResultText		= None
    107 		self.curCaseName		= None
    108 
    109 		# Error context
    110 		self.curLine			= 1
    111 		self.filename			= filename
    112 
    113 	def parseLine (self, line):
    114 		if len(line) > 0 and line[0] == '#':
    115 			self.parseContainerLine(line)
    116 		elif self.curResultText != None:
    117 			self.curResultText += line
    118 		# else: just ignored
    119 
    120 	def parseContainerLine (self, line):
    121 		args = splitContainerLine(line)
    122 		if args[0] == "#sessionInfo":
    123 			if len(args) < 3:
    124 				print args
    125 				self.parseError("Invalid #sessionInfo")
    126 			self.sessionInfo.append((args[1], ' '.join(args[2:])))
    127 		elif args[0] == "#beginSession" or args[0] == "#endSession":
    128 			pass # \todo [pyry] Validate
    129 		elif args[0] == "#beginTestCaseResult":
    130 			if len(args) != 2 or self.curCaseName != None:
    131 				self.parseError("Invalid #beginTestCaseResult")
    132 			self.curCaseName	= args[1]
    133 			self.curResultText	= ""
    134 		elif args[0] == "#endTestCaseResult":
    135 			if len(args) != 1 or self.curCaseName == None:
    136 				self.parseError("Invalid #endTestCaseResult")
    137 			self.parseTestCaseResult(self.curCaseName, self.curResultText)
    138 			self.curCaseName	= None
    139 			self.curResultText	= None
    140 		elif args[0] == "#terminateTestCaseResult":
    141 			if len(args) < 2 or self.curCaseName == None:
    142 				self.parseError("Invalid #terminateTestCaseResult")
    143 			statusCode		= ' '.join(args[1:])
    144 			statusDetails	= statusCode
    145 
    146 			if not StatusCode.isValid(statusCode):
    147 				# Legacy format
    148 				if statusCode == "Watchdog timeout occurred.":
    149 					statusCode = StatusCode.TIMEOUT
    150 				else:
    151 					statusCode = StatusCode.CRASH
    152 
    153 			# Do not try to parse at all since XML is likely broken
    154 			self.testCaseResults.append(TestCaseResult(self.curCaseName, statusCode, statusDetails, self.curResultText))
    155 
    156 			self.curCaseName	= None
    157 			self.curResultText	= None
    158 		else:
    159 			# Assume this is result text
    160 			if self.curResultText != None:
    161 				self.curResultText += line
    162 
    163 	def parseTestCaseResult (self, name, log):
    164 		try:
    165 			doc = xml.dom.minidom.parseString(log)
    166 			resultItems = doc.getElementsByTagName('Result')
    167 			if len(resultItems) != 1:
    168 				self.parseError("Expected 1 <Result>, found %d" % len(resultItems))
    169 
    170 			statusCode		= resultItems[0].getAttributeNode('StatusCode').nodeValue
    171 			statusDetails	= getNodeText(resultItems[0])
    172 		except Exception as e:
    173 			statusCode		= TestStatusCode.INTERNAL_ERROR
    174 			statusDetails	= "XML parsing failed: %s" % str(e)
    175 
    176 		self.testCaseResults.append(TestCaseResult(name, statusCode, statusDetails, log))
    177 
    178 	def parseError (self, message):
    179 		raise ParseError(self.filename, self.curLine, message)
    180