# -*- 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