blob: ef1c95a0ba08d193d112f78558e623ae627cbf47 [file] [log] [blame]
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------
# Khronos OpenGL CTS
# ------------------
#
# Copyright (c) 2016 The Khronos Group Inc.
#
# 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 xml.dom.minidom
import re
import subprocess
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))
sys.path.append(os.path.join(ROOT_DIR, "scripts", "verify"))
sys.path.append(os.path.join(ROOT_DIR, "scripts", "build"))
sys.path.append(os.path.join(ROOT_DIR, "scripts", "log"))
from package import getPackageDescription
from verify import *
from message import *
from common import *
from log_parser import *
from summary import *
def getConfigCaseName (type):
configs = { "es32" : ["CTS-Configs.es32", "CTS-Configs.es31", "CTS-Configs.es3", "CTS-Configs.es2"],
"es31" : ["CTS-Configs.es31", "CTS-Configs.es3", "CTS-Configs.es2"],
"es3" : ["CTS-Configs.es3", "CTS-Configs.es2"],
"es2" : ["CTS-Configs.es2"]}
return configs[type]
def retrieveReportedConfigs(caseName, log):
doc = xml.dom.minidom.parseString(log)
sectionItems = doc.getElementsByTagName('Section')
sectionName = None
configs = []
for sectionItem in sectionItems:
sectionName = sectionItem.getAttributeNode('Name').nodeValue
if sectionName == "Configs":
assert len(configs) == 0
textItems = sectionItem.getElementsByTagName('Text')
for textItem in textItems:
configs.append(getNodeText(textItem))
res = {caseName : configs}
return res
def compareConfigs(filename, baseConfigs, cmpConfigs):
messages = []
assert len(list(baseConfigs.keys())) == 1
assert len(list(cmpConfigs.keys())) == 1
baseKey = list(baseConfigs.keys())[0]
cmpKey = list(cmpConfigs.keys())[0]
if cmp(baseConfigs[baseKey], cmpConfigs[cmpKey]) != 0:
messages.append(error(filename, "Confomant configs reported for %s and %s do not match" % (baseKey,cmpKey)))
return messages
def verifyConfigFile (filename, type):
messages = []
caseNames = getConfigCaseName(type)
parser = BatchResultParser()
results = parser.parseFile(filename)
baseConfigs = None
for caseName in caseNames:
caseResult = None
print "Verifying %s in %s" % (caseName, filename)
for result in results:
if result.name == caseName:
caseResult = result
break;
if caseResult == None:
messages.append(error(filename, "Missing %s" % caseName))
else:
configs = retrieveReportedConfigs(caseName, result.log)
if baseConfigs == None:
baseConfigs = configs
else:
messages += compareConfigs(filename, baseConfigs, configs)
if not caseResult.statusCode in ALLOWED_STATUS_CODES:
messages.append(error(filename, "%s failed" % caseResult))
return messages
def verifyMustpassCases(package, mustpassCases, type):
messages = []
apiToTest = { "es32" : ["gles32", "gles31", "gles3", "gles2", "egl"],
"es31" : ["gles31", "gles3", "gles2", "egl"],
"es3" : ["gles3", "gles2", "egl"],
"es2" : ["gles2", "egl"]}
for mustpass in mustpassCases:
mustpassXML = os.path.join(mustpass, "mustpass.xml")
doc = xml.dom.minidom.parse(mustpassXML)
testConfigs = doc.getElementsByTagName("Configuration")
# check that all configs that must be tested are present
for testConfig in testConfigs:
caseListFile = testConfig.getAttributeNode("caseListFile").nodeValue
# identify APIs that must be tested for the given type
apis = apiToTest[type]
# identify API tested by the current config
configAPI = caseListFile.split('-')[0]
if configAPI in apis:
# the API in this config is expected to be tested
mustTest = True
else:
mustTest = False
pattern = "config-" + os.path.splitext(caseListFile)[0] + "-cfg-[0-9]*"+"-run-[0-9]*"
cmdLine = testConfig.getAttributeNode("commandLine").nodeValue
cfgItems = {'height':None, 'width':None, 'seed':None, 'rotation':None}
for arg in cmdLine.split():
val = arg.split('=')[1]
if "deqp-surface-height" in arg:
cfgItems['height'] = val
elif "deqp-surface-width" in arg:
cfgItems['width'] = val
elif "deqp-base-seed" in arg:
cfgItems['seed'] = val
elif "deqp-screen-rotation" in arg:
cfgItems['rotation'] = val
pattern += "-width-" + cfgItems['width'] + "-height-" + cfgItems['height']
if cfgItems['seed'] != None:
pattern += "-seed-" + cfgItems['seed']
pattern += ".qpa"
p = re.compile(pattern)
matches = [m for l in mustpassCases[mustpass] for m in (p.match(l),) if m]
if len(matches) == 0 and mustTest == True:
conformOs = testConfig.getAttributeNode("os").nodeValue
txt = "Configuration %s %s was not executed" % (caseListFile, cmdLine)
if conformOs == "any" or (package.conformOs != None and conformOs in package.conformOs.lower()):
msg = error(mustpassXML, txt)
else:
msg = warning(mustpassXML, txt)
messages.append(msg)
elif len(matches) != 0 and mustTest == False:
messages.append(error(mustpassXML, "Configuration %s %s was not expected to be tested but present in cts-run-summary.xml" % (caseListFile, cmdLine)))
return messages
def verifyTestLogs (package):
messages = []
try:
execute(['git', 'checkout', '--quiet', package.conformVersion])
except Exception, e:
print str(e)
print "Failed to checkout release tag %s." % package.conformVersion
return messages
messages = []
summary = parseRunSummary(os.path.join(package.basePath, package.summary))
mustpassDirs = []
# Check Conformant attribute
if not summary.isConformant:
messages.append(error(package.summary, "Runner reported conformance failure (Conformant=\"False\" in <Summary>)"))
# Verify config list
messages += verifyConfigFile(os.path.join(package.basePath, summary.configLogFilename), summary.type)
mustpassCases = {}
# Verify that all run files passed
for runLog in summary.runLogAndCaselist:
sys.stdout.write("Verifying %s -" % runLog)
sys.stdout.flush()
mustpassFile = os.path.join(ROOT_DIR, "external", "openglcts", summary.runLogAndCaselist[runLog])
key = os.path.dirname(mustpassFile)
if key in mustpassCases:
mpCase = mustpassCases[key]
else:
mpCase = []
mpCase.append(runLog)
mustpassCases[os.path.dirname(mustpassFile)] = mpCase
mustpass = readMustpass(mustpassFile)
messages_log = verifyTestLog(os.path.join(package.basePath, runLog), mustpass)
errors = [m for m in messages_log if m.type == ValidationMessage.TYPE_ERROR]
warnings = [m for m in messages_log if m.type == ValidationMessage.TYPE_WARNING]
if len(errors) > 0:
sys.stdout.write(" finished with ERRRORS")
if len(warnings) > 0:
sys.stdout.write(" finished with WARNINGS")
if len(errors) == 0 and len(warnings) == 0:
sys.stdout.write(" OK")
sys.stdout.write("\n")
sys.stdout.flush()
messages += messages_log
messages += verifyMustpassCases(package, mustpassCases, summary.type)
return messages
def verifyGitStatusFiles (package):
messages = []
if len(package.gitStatus) != 2:
messages.append(error(package.basePath, "Exactly two git status files must be present, found %s" % len(package.gitStatus)))
messages += verifyGitStatus(package)
return messages
def isGitLogFileEmpty (package, modulePath, gitLog):
logPath = os.path.join(package.basePath, gitLog)
log = readFile(logPath)
args = ['git', 'log', '-1', package.conformVersion]
process = subprocess.Popen(args, cwd=modulePath, stdout=subprocess.PIPE)
output = process.communicate()[0]
if process.returncode != 0:
raise Exception("Failed to execute '%s', got %d" % (str(args), process.returncode))
return log == output
def verifyGitLogFile (package):
messages = []
if len(package.gitLog) > 0:
for log, path in package.gitLog:
try:
isEmpty = isGitLogFileEmpty(package, path, log)
except Exception, e:
print str(e)
isEmpty = False
if not isEmpty:
messages.append(warning(os.path.join(package.basePath, log), "Log is not empty"))
else:
messages.append(error(package.basePath, "Missing git log files"))
return messages
def verifyPatchFiles (package):
messages = []
hasPatches = len(package.patches)
logEmpty = True
for log, path in package.gitLog:
logEmpty &= isGitLogFileEmpty(package, path, log)
if hasPatches and logEmpty:
messages.append(error(package.basePath, "Package includes patches but log is empty"))
elif not hasPatches and not logEmpty:
messages.append(error(package.basePath, "Test log is not empty but package doesn't contain patches"))
return messages
def verifyGitLogFiles (package):
messages = []
if len(package.gitLog) != 2:
messages.append(error(package.basePath, "Exactly two git log file must be present, found %s" % len(package.gitLog)))
for i, gitLog in enumerate(package.gitLog):
if "kc-cts" in gitLog[0]:
package.gitLog[i] = gitLog[:1] + ("external/kc-cts/src",) + gitLog[2:]
messages += verifyGitLogFile(package)
return messages
def verifyPackage (package):
messages = []
messages += verifyStatement(package)
messages += verifyGitStatusFiles(package)
messages += verifyGitLogFiles(package)
messages += verifyPatchFiles(package)
for item in package.otherItems:
messages.append(warning(os.path.join(package.basePath, item), "Unknown file"))
return messages
def verifyESSubmission(argv):
if len(argv) != 2:
print "%s: [extracted submission package directory]" % sys.argv[0]
sys.exit(-1)
try:
execute(['git', 'ls-remote', 'origin', '--quiet'])
except Exception, e:
print str(e)
print "This script must be executed inside VK-GL-CTS directory."
sys.exit(-1)
packagePath = os.path.normpath(sys.argv[1])
package = getPackageDescription(packagePath)
messages = verifyPackage(package)
messages += verifyTestLogs(package)
errors = [m for m in messages if m.type == ValidationMessage.TYPE_ERROR]
warnings = [m for m in messages if m.type == ValidationMessage.TYPE_WARNING]
for message in messages:
print str(message)
print ""
if len(errors) > 0:
print "Found %d validation errors and %d warnings!" % (len(errors), len(warnings))
sys.exit(-2)
elif len(warnings) > 0:
print "Found %d warnings, manual review required" % len(warnings)
sys.exit(-1)
else:
print "All validation checks passed"
if __name__ == "__main__":
verifyESSubmission(sys.argv)