You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
7.6 KiB
285 lines
7.6 KiB
# -*- 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 sys
|
|
import random
|
|
import string
|
|
import subprocess
|
|
from optparse import OptionParser
|
|
|
|
def all (results, predicate):
|
|
for result in results:
|
|
if not predicate(result):
|
|
return False
|
|
return True
|
|
|
|
def any (results, predicate):
|
|
for result in results:
|
|
if predicate(result):
|
|
return True
|
|
return False
|
|
|
|
class FilterRule:
|
|
def __init__ (self, name, description, filters):
|
|
self.name = name
|
|
self.description = description
|
|
self.filters = filters
|
|
|
|
class TestCaseResult:
|
|
def __init__ (self, name, results):
|
|
self.name = name
|
|
self.results = results
|
|
|
|
class Group:
|
|
def __init__ (self, name):
|
|
self.name = name
|
|
self.cases = []
|
|
|
|
def readCaseList (filename):
|
|
f = open(filename, 'rb')
|
|
cases = []
|
|
for line in f:
|
|
if line[:6] == "TEST: ":
|
|
case = line[6:].strip()
|
|
if len(case) > 0:
|
|
cases.append(case)
|
|
return cases
|
|
|
|
def toResultList (caselist):
|
|
results = []
|
|
for case in caselist:
|
|
results.append(TestCaseResult(case, []))
|
|
return results
|
|
|
|
def addResultsToCaseList (caselist, results):
|
|
resultMap = {}
|
|
caseListRes = toResultList(caselist)
|
|
|
|
for res in caseListRes:
|
|
resultMap[res.name] = res
|
|
|
|
for result in results:
|
|
if result.name in resultMap:
|
|
resultMap[result.name].results += result.results
|
|
|
|
return caseListRes
|
|
|
|
def readTestResults (filename):
|
|
f = open(filename, 'rb')
|
|
csvData = f.read()
|
|
csvLines = csvData.splitlines()
|
|
results = []
|
|
|
|
f.close()
|
|
|
|
for line in csvLines[1:]:
|
|
args = line.split(',')
|
|
if len(args) == 1:
|
|
continue # Ignore
|
|
|
|
results.append(TestCaseResult(args[0], args[1:]))
|
|
|
|
if len(results) == 0:
|
|
raise Exception("Empty result list")
|
|
|
|
# Sanity check for results
|
|
numResultItems = len(results[0].results)
|
|
seenResults = set()
|
|
for result in results:
|
|
if result.name in seenResults:
|
|
raise Exception("Duplicate result row for test case '%s'" % result.name)
|
|
if len(result.results) != numResultItems:
|
|
raise Exception("Found %d results for test case '%s', expected %d" % (len(result.results), result.name, numResultItems))
|
|
seenResults.add(result.name)
|
|
|
|
return results
|
|
|
|
def readGroupList (filename):
|
|
f = open(filename, 'rb')
|
|
groups = []
|
|
for line in f:
|
|
group = line.strip()
|
|
if group != "":
|
|
groups.append(group)
|
|
return groups
|
|
|
|
def createGroups (results, groupNames):
|
|
groups = []
|
|
matched = set()
|
|
|
|
for groupName in groupNames:
|
|
group = Group(groupName)
|
|
groups.append(group)
|
|
|
|
prefix = groupName + "."
|
|
prefixLen = len(prefix)
|
|
for case in results:
|
|
if case.name[:prefixLen] == prefix:
|
|
if case in matched:
|
|
die("Case '%s' matched by multiple groups (when processing '%s')" % (case.name, group.name))
|
|
group.cases.append(case)
|
|
matched.add(case)
|
|
|
|
return groups
|
|
|
|
def createLeafGroups (results):
|
|
groups = []
|
|
groupMap = {}
|
|
|
|
for case in results:
|
|
parts = case.name.split('.')
|
|
groupName = string.join(parts[:-1], ".")
|
|
|
|
if not groupName in groupMap:
|
|
group = Group(groupName)
|
|
groups.append(group)
|
|
groupMap[groupName] = group
|
|
else:
|
|
group = groupMap[groupName]
|
|
|
|
group.cases.append(case)
|
|
|
|
return groups
|
|
|
|
def filterList (results, condition):
|
|
filtered = []
|
|
for case in results:
|
|
if condition(case.results):
|
|
filtered.append(case)
|
|
return filtered
|
|
|
|
def getFilter (list, name):
|
|
for filter in list:
|
|
if filter.name == name:
|
|
return filter
|
|
return None
|
|
|
|
def getNumCasesInGroups (groups):
|
|
numCases = 0
|
|
for group in groups:
|
|
numCases += len(group.cases)
|
|
return numCases
|
|
|
|
def getCasesInSet (results, caseSet):
|
|
filtered = []
|
|
for case in results:
|
|
if case in caseSet:
|
|
filtered.append(case)
|
|
return filtered
|
|
|
|
def selectCasesInGroups (results, groups):
|
|
casesInGroups = set()
|
|
for group in groups:
|
|
for case in group.cases:
|
|
casesInGroups.add(case)
|
|
return getCasesInSet(results, casesInGroups)
|
|
|
|
def selectRandomSubset (results, groups, limit, seed):
|
|
selectedCases = set()
|
|
numSelect = min(limit, getNumCasesInGroups(groups))
|
|
|
|
random.seed(seed)
|
|
random.shuffle(groups)
|
|
|
|
groupNdx = 0
|
|
while len(selectedCases) < numSelect:
|
|
group = groups[groupNdx]
|
|
if len(group.cases) == 0:
|
|
del groups[groupNdx]
|
|
if groupNdx == len(groups):
|
|
groupNdx -= 1
|
|
continue # Try next
|
|
|
|
selected = random.choice(group.cases)
|
|
selectedCases.add(selected)
|
|
group.cases.remove(selected)
|
|
|
|
groupNdx = (groupNdx + 1) % len(groups)
|
|
|
|
return getCasesInSet(results, selectedCases)
|
|
|
|
def die (msg):
|
|
print(msg)
|
|
sys.exit(-1)
|
|
|
|
# Named filter lists
|
|
FILTER_RULES = [
|
|
FilterRule("all", "No filtering", []),
|
|
FilterRule("all-pass", "All results must be 'Pass'", [lambda l: all(l, lambda r: r == 'Pass')]),
|
|
FilterRule("any-pass", "Any of results is 'Pass'", [lambda l: any(l, lambda r: r == 'Pass')]),
|
|
FilterRule("any-fail", "Any of results is not 'Pass' or 'NotSupported'", [lambda l: not all(l, lambda r: r == 'Pass' or r == 'NotSupported')]),
|
|
FilterRule("prev-failing", "Any except last result is failure", [lambda l: l[-1] == 'Pass' and not all(l[:-1], lambda r: r == 'Pass')]),
|
|
FilterRule("prev-passing", "Any except last result is 'Pass'", [lambda l: l[-1] != 'Pass' and any(l[:-1], lambda r: r == 'Pass')])
|
|
]
|
|
|
|
if __name__ == "__main__":
|
|
parser = OptionParser(usage = "usage: %prog [options] [caselist] [result csv file]")
|
|
parser.add_option("-f", "--filter", dest="filter", default="all", help="filter rule name")
|
|
parser.add_option("-l", "--list", action="store_true", dest="list", default=False, help="list available rules")
|
|
parser.add_option("-n", "--num", dest="limit", default=0, help="limit number of cases")
|
|
parser.add_option("-s", "--seed", dest="seed", default=0, help="use selected seed for random selection")
|
|
parser.add_option("-g", "--groups", dest="groups_file", default=None, help="select cases based on group list file")
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
if options.list:
|
|
print("Available filter rules:")
|
|
for filter in FILTER_RULES:
|
|
print(" %s: %s" % (filter.name, filter.description))
|
|
sys.exit(0)
|
|
|
|
if len(args) == 0:
|
|
die("No input files specified")
|
|
elif len(args) > 2:
|
|
die("Too many arguments")
|
|
|
|
# Fetch filter
|
|
filter = getFilter(FILTER_RULES, options.filter)
|
|
if filter == None:
|
|
die("Unknown filter '%s'" % options.filter)
|
|
|
|
# Read case list
|
|
caselist = readCaseList(args[0])
|
|
if len(args) > 1:
|
|
results = readTestResults(args[1])
|
|
results = addResultsToCaseList(caselist, results)
|
|
else:
|
|
results = toResultList(caselist)
|
|
|
|
# Execute filters for results
|
|
for rule in filter.filters:
|
|
results = filterList(results, rule)
|
|
|
|
if options.limit != 0:
|
|
if options.groups_file != None:
|
|
groups = createGroups(results, readGroupList(options.groups_file))
|
|
else:
|
|
groups = createLeafGroups(results)
|
|
results = selectRandomSubset(results, groups, int(options.limit), int(options.seed))
|
|
elif options.groups_file != None:
|
|
groups = createGroups(results, readGroupList(options.groups_file))
|
|
results = selectCasesInGroups(results, groups)
|
|
|
|
# Print test set
|
|
for result in results:
|
|
print(result.name)
|