1b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# -*- coding: utf-8 -*-
2b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
3b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#-------------------------------------------------------------------------
4b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# Khronos OpenGL CTS
5b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# ------------------
6b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#
7b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# Copyright (c) 2016 The Khronos Group Inc.
8b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#
9b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# Licensed under the Apache License, Version 2.0 (the "License");
10b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# you may not use this file except in compliance with the License.
11b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# You may obtain a copy of the License at
12b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#
13b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#      http://www.apache.org/licenses/LICENSE-2.0
14b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#
15b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# Unless required by applicable law or agreed to in writing, software
16b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# distributed under the License is distributed on an "AS IS" BASIS,
17b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# See the License for the specific language governing permissions and
19b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin# limitations under the License.
20b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#
21b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin#-------------------------------------------------------------------------
22b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
23b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinimport os
24b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinimport sys
25b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinimport xml.dom.minidom
26b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinimport re
27244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazinimport subprocess
28b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
29b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander GalazinROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))
30b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinsys.path.append(os.path.join(ROOT_DIR, "scripts", "verify"))
31b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinsys.path.append(os.path.join(ROOT_DIR, "scripts", "build"))
32b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinsys.path.append(os.path.join(ROOT_DIR, "scripts", "log"))
33b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
34b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinfrom package import getPackageDescription
35b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinfrom verify import *
36b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinfrom message import *
37b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinfrom common import *
38b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinfrom log_parser import *
39b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinfrom summary import *
40b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
41b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef getConfigCaseName (type):
42b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	configs = { "es32" : ["CTS-Configs.es32", "CTS-Configs.es31", "CTS-Configs.es3", "CTS-Configs.es2"],
43b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				"es31" : ["CTS-Configs.es31", "CTS-Configs.es3", "CTS-Configs.es2"],
44b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				"es3"  : ["CTS-Configs.es3", "CTS-Configs.es2"],
45b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				"es2"  : ["CTS-Configs.es2"]}
46b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return configs[type]
47b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
48b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef retrieveReportedConfigs(caseName, log):
49b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	doc				= xml.dom.minidom.parseString(log)
50b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	sectionItems	= doc.getElementsByTagName('Section')
51b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	sectionName		= None
52b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
53b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	configs = []
54b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	for sectionItem in sectionItems:
55b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sectionName	= sectionItem.getAttributeNode('Name').nodeValue
56b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		if sectionName == "Configs":
57b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			assert len(configs) == 0
58b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			textItems = sectionItem.getElementsByTagName('Text')
59b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			for textItem in textItems:
60b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				configs.append(getNodeText(textItem))
61b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	res = {caseName : configs}
62b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return res
63b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
64b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef compareConfigs(filename, baseConfigs, cmpConfigs):
65b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
66b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	assert len(list(baseConfigs.keys())) == 1
67b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	assert len(list(cmpConfigs.keys())) == 1
68b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	baseKey = list(baseConfigs.keys())[0]
69b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	cmpKey = list(cmpConfigs.keys())[0]
70b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
71b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	if cmp(baseConfigs[baseKey], cmpConfigs[cmpKey]) != 0:
72b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages.append(error(filename, "Confomant configs reported for %s and %s do not match" % (baseKey,cmpKey)))
73b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
74b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
75b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
76b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef verifyConfigFile (filename, type):
77b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages  = []
78b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	caseNames = getConfigCaseName(type)
79b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
80b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	parser		= BatchResultParser()
81b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	results		= parser.parseFile(filename)
82b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	baseConfigs	= None
83b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
84b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	for caseName in caseNames:
85b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		caseResult	= None
86b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "Verifying %s in %s" % (caseName, filename)
87b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		for result in results:
88b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			if result.name == caseName:
89b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				caseResult = result
90b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				break;
91b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		if caseResult == None:
92b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			messages.append(error(filename, "Missing %s" % caseName))
93b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		else:
94b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			configs = retrieveReportedConfigs(caseName, result.log)
95b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			if baseConfigs == None:
96b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				baseConfigs = configs
97b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			else:
98b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				messages += compareConfigs(filename, baseConfigs, configs)
99b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			if not caseResult.statusCode in ALLOWED_STATUS_CODES:
100b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				messages.append(error(filename, "%s failed" % caseResult))
101b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
102b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
103b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
104462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazindef verifyMustpassCases(package, mustpassCases, type):
105b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
1067125a982e2232fc61e64d1d56ff8ca73bb75becfAlexander Galazin	apiToTest = { "es32" : ["gles32", "gles31", "gles3", "gles2", "egl"],
1077125a982e2232fc61e64d1d56ff8ca73bb75becfAlexander Galazin				"es31" : ["gles31", "gles3", "gles2", "egl"],
1087125a982e2232fc61e64d1d56ff8ca73bb75becfAlexander Galazin				"es3"  : ["gles3", "gles2", "egl"],
1097125a982e2232fc61e64d1d56ff8ca73bb75becfAlexander Galazin				"es2"  : ["gles2", "egl"]}
110462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin
111b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	for mustpass in mustpassCases:
112b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		mustpassXML = os.path.join(mustpass, "mustpass.xml")
113b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		doc = xml.dom.minidom.parse(mustpassXML)
114b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		testConfigs = doc.getElementsByTagName("Configuration")
115462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin		# check that all configs that must be tested are present
116b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		for testConfig in testConfigs:
117b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			caseListFile = testConfig.getAttributeNode("caseListFile").nodeValue
118462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			# identify APIs that must be tested for the given type
119462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			apis = apiToTest[type]
120462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			# identify API tested by the current config
121462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			configAPI = caseListFile.split('-')[0]
122462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			if configAPI in apis:
123462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin				# the API in this config is expected to be tested
124462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin				mustTest = True
125462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			else:
126462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin				mustTest = False
127b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			pattern = "config-" + os.path.splitext(caseListFile)[0] + "-cfg-[0-9]*"+"-run-[0-9]*"
128b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			cmdLine = testConfig.getAttributeNode("commandLine").nodeValue
129b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			cfgItems = {'height':None, 'width':None, 'seed':None, 'rotation':None}
130b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			for arg in cmdLine.split():
131b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				val = arg.split('=')[1]
132b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				if "deqp-surface-height" in arg:
133b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					cfgItems['height'] = val
134b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				elif "deqp-surface-width" in arg:
135b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					cfgItems['width'] = val
136b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				elif "deqp-base-seed" in arg:
137b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					cfgItems['seed'] = val
138b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				elif "deqp-screen-rotation" in arg:
139b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					cfgItems['rotation'] = val
140b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			pattern += "-width-" + cfgItems['width'] + "-height-" + cfgItems['height']
141b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			if cfgItems['seed'] != None:
142b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin				pattern += "-seed-" + cfgItems['seed']
143b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			pattern += ".qpa"
144b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			p = re.compile(pattern)
145b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			matches = [m for l in mustpassCases[mustpass] for m in (p.match(l),) if m]
146462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			if len(matches) == 0 and mustTest == True:
147b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					conformOs = testConfig.getAttributeNode("os").nodeValue
148b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					txt = "Configuration %s %s was not executed" % (caseListFile, cmdLine)
149b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					if conformOs == "any" or (package.conformOs != None and conformOs in package.conformOs.lower()):
150b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin						msg = error(mustpassXML, txt)
151b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					else:
152b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin						msg = warning(mustpassXML, txt)
153b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin					messages.append(msg)
154462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin			elif len(matches) != 0 and mustTest == False:
155462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin				messages.append(error(mustpassXML, "Configuration %s %s was not expected to be tested but present in cts-run-summary.xml" % (caseListFile, cmdLine)))
156b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
157b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
158b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
159b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef verifyTestLogs (package):
160b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
161b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
162b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	try:
163b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		execute(['git', 'checkout', '--quiet', package.conformVersion])
164b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	except Exception, e:
165b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print str(e)
166b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "Failed to checkout release tag %s." % package.conformVersion
167b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		return messages
168b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
169b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
170b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	summary	= parseRunSummary(os.path.join(package.basePath, package.summary))
171b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	mustpassDirs = []
172b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
173b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	# Check Conformant attribute
174b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	if not summary.isConformant:
175b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages.append(error(package.summary, "Runner reported conformance failure (Conformant=\"False\" in <Summary>)"))
176b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
177b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	# Verify config list
178b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages += verifyConfigFile(os.path.join(package.basePath, summary.configLogFilename), summary.type)
179b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
180b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	mustpassCases = {}
181b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	# Verify that all run files passed
182b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	for runLog in summary.runLogAndCaselist:
183b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.stdout.write("Verifying %s -" % runLog)
184b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.stdout.flush()
185b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
186b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		mustpassFile = os.path.join(ROOT_DIR, "external", "openglcts", summary.runLogAndCaselist[runLog])
187b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		key = os.path.dirname(mustpassFile)
188b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		if key in mustpassCases:
189b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			mpCase = mustpassCases[key]
190b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		else:
191b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			mpCase = []
192b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		mpCase.append(runLog)
193b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		mustpassCases[os.path.dirname(mustpassFile)] = mpCase
194b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		mustpass = readMustpass(mustpassFile)
195b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages_log = verifyTestLog(os.path.join(package.basePath, runLog), mustpass)
196b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
197b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		errors	= [m for m in messages_log if m.type == ValidationMessage.TYPE_ERROR]
198b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		warnings	= [m for m in messages_log if m.type == ValidationMessage.TYPE_WARNING]
199b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		if len(errors) > 0:
200b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			sys.stdout.write(" finished with ERRRORS")
201b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		if len(warnings) > 0:
202b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			sys.stdout.write(" finished with WARNINGS")
203b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		if len(errors) == 0 and len(warnings) == 0:
204b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin			sys.stdout.write(" OK")
205b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.stdout.write("\n")
206b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.stdout.flush()
207b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
208b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages += messages_log
209b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
210462cbbf2c4671c684dd70dc82b350ca6ebc9d02cAlexander Galazin	messages += verifyMustpassCases(package, mustpassCases, summary.type)
211b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
212b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
213b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
214b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef verifyGitStatusFiles (package):
215b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
216b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
217b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	if len(package.gitStatus) != 2:
218b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages.append(error(package.basePath, "Exactly two git status files must be present, found %s" % len(package.gitStatus)))
219b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
220b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages += verifyGitStatus(package)
221b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
222b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
223b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
224244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazindef isGitLogFileEmpty (package, modulePath, gitLog):
225244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	logPath	= os.path.join(package.basePath, gitLog)
226244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	log		= readFile(logPath)
227244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
228244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	args = ['git', 'log', '-1', package.conformVersion]
229244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	process = subprocess.Popen(args, cwd=modulePath, stdout=subprocess.PIPE)
230244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	output = process.communicate()[0]
231244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	if process.returncode != 0:
232244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		raise Exception("Failed to execute '%s', got %d" % (str(args), process.returncode))
233244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
234244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	return log == output
235244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
236244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazindef verifyGitLogFile (package):
237244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	messages = []
238244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
239244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	if len(package.gitLog) > 0:
240244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		for log, path in package.gitLog:
241244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin			try:
242244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin				isEmpty = isGitLogFileEmpty(package, path, log)
243244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin			except Exception, e:
244244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin				print str(e)
245244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin				isEmpty = False
246244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
247244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin			if not isEmpty:
248244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin				messages.append(warning(os.path.join(package.basePath, log), "Log is not empty"))
249244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	else:
250244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		messages.append(error(package.basePath, "Missing git log files"))
251244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
252244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	return messages
253244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
254244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazindef verifyPatchFiles (package):
255244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	messages	= []
256244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	hasPatches	= len(package.patches)
257244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	logEmpty	= True
258244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	for log, path in package.gitLog:
259244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		logEmpty &= isGitLogFileEmpty(package, path, log)
260244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
261244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	if hasPatches and logEmpty:
262244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		messages.append(error(package.basePath, "Package includes patches but log is empty"))
263244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	elif not hasPatches and not logEmpty:
264244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		messages.append(error(package.basePath, "Test log is not empty but package doesn't contain patches"))
265244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
266244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	return messages
267244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
268b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef verifyGitLogFiles (package):
269b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
270b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
271b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	if len(package.gitLog) != 2:
272b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages.append(error(package.basePath, "Exactly two git log file must be present, found %s" % len(package.gitLog)))
273b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
274244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	for i, gitLog in enumerate(package.gitLog):
275244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin		if "kc-cts" in gitLog[0]:
276244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin			package.gitLog[i] = gitLog[:1] + ("external/kc-cts/src",) + gitLog[2:]
277244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin
278244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	messages += verifyGitLogFile(package)
279b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
280b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
281b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
282b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef verifyPackage (package):
283b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages = []
284b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
285b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages += verifyStatement(package)
286b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages += verifyGitStatusFiles(package)
287b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages += verifyGitLogFiles(package)
288244a26241b3887ccdca2eccbd45b914d3b5e6883Alexander Galazin	messages += verifyPatchFiles(package)
289b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
290b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	for item in package.otherItems:
291b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		messages.append(warning(os.path.join(package.basePath, item), "Unknown file"))
292b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
293b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	return messages
294b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
295b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazindef verifyESSubmission(argv):
296b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	if len(argv) != 2:
297b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "%s: [extracted submission package directory]" % sys.argv[0]
298b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.exit(-1)
299b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	try:
300b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		execute(['git', 'ls-remote', 'origin', '--quiet'])
301b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	except Exception, e:
302b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print str(e)
303b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "This script must be executed inside VK-GL-CTS directory."
304b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.exit(-1)
305b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
306b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	packagePath		=  os.path.normpath(sys.argv[1])
307b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	package			=  getPackageDescription(packagePath)
308b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages		=  verifyPackage(package)
309b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	messages		+= verifyTestLogs(package)
310b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
311b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	errors			= [m for m in messages if m.type == ValidationMessage.TYPE_ERROR]
312b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	warnings		= [m for m in messages if m.type == ValidationMessage.TYPE_WARNING]
313b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
314b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	for message in messages:
315b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print str(message)
316b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
317b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	print ""
318b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
319b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	if len(errors) > 0:
320b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "Found %d validation errors and %d warnings!" % (len(errors), len(warnings))
321b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.exit(-2)
322b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	elif len(warnings) > 0:
323b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "Found %d warnings, manual review required" % len(warnings)
324b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		sys.exit(-1)
325b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	else:
326b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin		print "All validation checks passed"
327b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin
328b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazinif __name__ == "__main__":
329b90ed7c95140b4518dc17e32f6f12bb744ce71dcAlexander Galazin	verifyESSubmission(sys.argv)
330