18296aa0fSIan Rogers# SPDX-License-Identifier: GPL-2.0 28296aa0fSIan Rogers 3*21944462SIan Rogersimport configparser 48296aa0fSIan Rogersimport os 58296aa0fSIan Rogersimport sys 68296aa0fSIan Rogersimport glob 78296aa0fSIan Rogersimport optparse 88296aa0fSIan Rogersimport platform 98296aa0fSIan Rogersimport tempfile 108296aa0fSIan Rogersimport logging 118296aa0fSIan Rogersimport re 128296aa0fSIan Rogersimport shutil 138296aa0fSIan Rogersimport subprocess 148296aa0fSIan Rogers 158296aa0fSIan Rogersdef data_equal(a, b): 168296aa0fSIan Rogers # Allow multiple values in assignment separated by '|' 178296aa0fSIan Rogers a_list = a.split('|') 188296aa0fSIan Rogers b_list = b.split('|') 198296aa0fSIan Rogers 208296aa0fSIan Rogers for a_item in a_list: 218296aa0fSIan Rogers for b_item in b_list: 228296aa0fSIan Rogers if (a_item == b_item): 238296aa0fSIan Rogers return True 248296aa0fSIan Rogers elif (a_item == '*') or (b_item == '*'): 258296aa0fSIan Rogers return True 268296aa0fSIan Rogers 278296aa0fSIan Rogers return False 288296aa0fSIan Rogers 298296aa0fSIan Rogersclass Fail(Exception): 308296aa0fSIan Rogers def __init__(self, test, msg): 318296aa0fSIan Rogers self.msg = msg 328296aa0fSIan Rogers self.test = test 338296aa0fSIan Rogers def getMsg(self): 348296aa0fSIan Rogers return '\'%s\' - %s' % (self.test.path, self.msg) 358296aa0fSIan Rogers 368296aa0fSIan Rogersclass Notest(Exception): 378296aa0fSIan Rogers def __init__(self, test, arch): 388296aa0fSIan Rogers self.arch = arch 398296aa0fSIan Rogers self.test = test 408296aa0fSIan Rogers def getMsg(self): 418296aa0fSIan Rogers return '[%s] \'%s\'' % (self.arch, self.test.path) 428296aa0fSIan Rogers 438296aa0fSIan Rogersclass Unsup(Exception): 448296aa0fSIan Rogers def __init__(self, test): 458296aa0fSIan Rogers self.test = test 468296aa0fSIan Rogers def getMsg(self): 478296aa0fSIan Rogers return '\'%s\'' % self.test.path 488296aa0fSIan Rogers 498296aa0fSIan Rogersclass Event(dict): 508296aa0fSIan Rogers terms = [ 518296aa0fSIan Rogers 'cpu', 528296aa0fSIan Rogers 'flags', 538296aa0fSIan Rogers 'type', 548296aa0fSIan Rogers 'size', 558296aa0fSIan Rogers 'config', 568296aa0fSIan Rogers 'sample_period', 578296aa0fSIan Rogers 'sample_type', 588296aa0fSIan Rogers 'read_format', 598296aa0fSIan Rogers 'disabled', 608296aa0fSIan Rogers 'inherit', 618296aa0fSIan Rogers 'pinned', 628296aa0fSIan Rogers 'exclusive', 638296aa0fSIan Rogers 'exclude_user', 648296aa0fSIan Rogers 'exclude_kernel', 658296aa0fSIan Rogers 'exclude_hv', 668296aa0fSIan Rogers 'exclude_idle', 678296aa0fSIan Rogers 'mmap', 688296aa0fSIan Rogers 'comm', 698296aa0fSIan Rogers 'freq', 708296aa0fSIan Rogers 'inherit_stat', 718296aa0fSIan Rogers 'enable_on_exec', 728296aa0fSIan Rogers 'task', 738296aa0fSIan Rogers 'watermark', 748296aa0fSIan Rogers 'precise_ip', 758296aa0fSIan Rogers 'mmap_data', 768296aa0fSIan Rogers 'sample_id_all', 778296aa0fSIan Rogers 'exclude_host', 788296aa0fSIan Rogers 'exclude_guest', 798296aa0fSIan Rogers 'exclude_callchain_kernel', 808296aa0fSIan Rogers 'exclude_callchain_user', 818296aa0fSIan Rogers 'wakeup_events', 828296aa0fSIan Rogers 'bp_type', 838296aa0fSIan Rogers 'config1', 848296aa0fSIan Rogers 'config2', 858296aa0fSIan Rogers 'branch_sample_type', 868296aa0fSIan Rogers 'sample_regs_user', 878296aa0fSIan Rogers 'sample_stack_user', 888296aa0fSIan Rogers ] 898296aa0fSIan Rogers 908296aa0fSIan Rogers def add(self, data): 918296aa0fSIan Rogers for key, val in data: 928296aa0fSIan Rogers log.debug(" %s = %s" % (key, val)) 938296aa0fSIan Rogers self[key] = val 948296aa0fSIan Rogers 958296aa0fSIan Rogers def __init__(self, name, data, base): 968296aa0fSIan Rogers log.debug(" Event %s" % name); 978296aa0fSIan Rogers self.name = name; 988296aa0fSIan Rogers self.group = '' 998296aa0fSIan Rogers self.add(base) 1008296aa0fSIan Rogers self.add(data) 1018296aa0fSIan Rogers 1028296aa0fSIan Rogers def equal(self, other): 1038296aa0fSIan Rogers for t in Event.terms: 1048296aa0fSIan Rogers log.debug(" [%s] %s %s" % (t, self[t], other[t])); 1058296aa0fSIan Rogers if t not in self or t not in other: 1068296aa0fSIan Rogers return False 1078296aa0fSIan Rogers if not data_equal(self[t], other[t]): 1088296aa0fSIan Rogers return False 1098296aa0fSIan Rogers return True 1108296aa0fSIan Rogers 1118296aa0fSIan Rogers def optional(self): 1128296aa0fSIan Rogers if 'optional' in self and self['optional'] == '1': 1138296aa0fSIan Rogers return True 1148296aa0fSIan Rogers return False 1158296aa0fSIan Rogers 1168296aa0fSIan Rogers def diff(self, other): 1178296aa0fSIan Rogers for t in Event.terms: 1188296aa0fSIan Rogers if t not in self or t not in other: 1198296aa0fSIan Rogers continue 1208296aa0fSIan Rogers if not data_equal(self[t], other[t]): 1218296aa0fSIan Rogers log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) 1228296aa0fSIan Rogers 1238296aa0fSIan Rogersdef parse_version(version): 1248296aa0fSIan Rogers if not version: 1258296aa0fSIan Rogers return None 1268296aa0fSIan Rogers return [int(v) for v in version.split(".")[0:2]] 1278296aa0fSIan Rogers 1288296aa0fSIan Rogers# Test file description needs to have following sections: 1298296aa0fSIan Rogers# [config] 1308296aa0fSIan Rogers# - just single instance in file 1318296aa0fSIan Rogers# - needs to specify: 1328296aa0fSIan Rogers# 'command' - perf command name 1338296aa0fSIan Rogers# 'args' - special command arguments 1348296aa0fSIan Rogers# 'ret' - Skip test if Perf doesn't exit with this value (0 by default) 1358296aa0fSIan Rogers# 'test_ret'- If set to 'true', fail test instead of skipping for 'ret' argument 1368296aa0fSIan Rogers# 'arch' - architecture specific test (optional) 1378296aa0fSIan Rogers# comma separated list, ! at the beginning 1388296aa0fSIan Rogers# negates it. 1398296aa0fSIan Rogers# 'auxv' - Truthy statement that is evaled in the scope of the auxv map. When false, 1408296aa0fSIan Rogers# the test is skipped. For example 'auxv["AT_HWCAP"] == 10'. (optional) 1418296aa0fSIan Rogers# 'kernel_since' - Inclusive kernel version from which the test will start running. Only the 1428296aa0fSIan Rogers# first two values are supported, for example "6.1" (optional) 1438296aa0fSIan Rogers# 'kernel_until' - Exclusive kernel version from which the test will stop running. (optional) 1448296aa0fSIan Rogers# [eventX:base] 1458296aa0fSIan Rogers# - one or multiple instances in file 1468296aa0fSIan Rogers# - expected values assignments 1478296aa0fSIan Rogersclass Test(object): 1488296aa0fSIan Rogers def __init__(self, path, options): 1498296aa0fSIan Rogers parser = configparser.ConfigParser() 1508296aa0fSIan Rogers parser.read(path) 1518296aa0fSIan Rogers 1528296aa0fSIan Rogers log.warning("running '%s'" % path) 1538296aa0fSIan Rogers 1548296aa0fSIan Rogers self.path = path 1558296aa0fSIan Rogers self.test_dir = options.test_dir 1568296aa0fSIan Rogers self.perf = options.perf 1578296aa0fSIan Rogers self.command = parser.get('config', 'command') 1588296aa0fSIan Rogers self.args = parser.get('config', 'args') 1598296aa0fSIan Rogers 1608296aa0fSIan Rogers try: 1618296aa0fSIan Rogers self.ret = parser.get('config', 'ret') 1628296aa0fSIan Rogers except: 1638296aa0fSIan Rogers self.ret = 0 1648296aa0fSIan Rogers 1658296aa0fSIan Rogers self.test_ret = parser.getboolean('config', 'test_ret', fallback=False) 1668296aa0fSIan Rogers 1678296aa0fSIan Rogers try: 1688296aa0fSIan Rogers self.arch = parser.get('config', 'arch') 1698296aa0fSIan Rogers log.warning("test limitation '%s'" % self.arch) 1708296aa0fSIan Rogers except: 1718296aa0fSIan Rogers self.arch = '' 1728296aa0fSIan Rogers 1738296aa0fSIan Rogers self.auxv = parser.get('config', 'auxv', fallback=None) 1748296aa0fSIan Rogers self.kernel_since = parse_version(parser.get('config', 'kernel_since', fallback=None)) 1758296aa0fSIan Rogers self.kernel_until = parse_version(parser.get('config', 'kernel_until', fallback=None)) 1768296aa0fSIan Rogers self.expect = {} 1778296aa0fSIan Rogers self.result = {} 1788296aa0fSIan Rogers log.debug(" loading expected events"); 1798296aa0fSIan Rogers self.load_events(path, self.expect) 1808296aa0fSIan Rogers 1818296aa0fSIan Rogers def is_event(self, name): 1828296aa0fSIan Rogers if name.find("event") == -1: 1838296aa0fSIan Rogers return False 1848296aa0fSIan Rogers else: 1858296aa0fSIan Rogers return True 1868296aa0fSIan Rogers 1878296aa0fSIan Rogers def skip_test_kernel_since(self): 1888296aa0fSIan Rogers if not self.kernel_since: 1898296aa0fSIan Rogers return False 1908296aa0fSIan Rogers return not self.kernel_since <= parse_version(platform.release()) 1918296aa0fSIan Rogers 1928296aa0fSIan Rogers def skip_test_kernel_until(self): 1938296aa0fSIan Rogers if not self.kernel_until: 1948296aa0fSIan Rogers return False 1958296aa0fSIan Rogers return not parse_version(platform.release()) < self.kernel_until 1968296aa0fSIan Rogers 1978296aa0fSIan Rogers def skip_test_auxv(self): 1988296aa0fSIan Rogers def new_auxv(a, pattern): 1998296aa0fSIan Rogers items = list(filter(None, pattern.split(a))) 2008296aa0fSIan Rogers # AT_HWCAP is hex but doesn't have a prefix, so special case it 2018296aa0fSIan Rogers if items[0] == "AT_HWCAP": 2028296aa0fSIan Rogers value = int(items[-1], 16) 2038296aa0fSIan Rogers else: 2048296aa0fSIan Rogers try: 2058296aa0fSIan Rogers value = int(items[-1], 0) 2068296aa0fSIan Rogers except: 2078296aa0fSIan Rogers value = items[-1] 2088296aa0fSIan Rogers return (items[0], value) 2098296aa0fSIan Rogers 2108296aa0fSIan Rogers if not self.auxv: 2118296aa0fSIan Rogers return False 2128296aa0fSIan Rogers auxv = subprocess.check_output("LD_SHOW_AUXV=1 sleep 0", shell=True) \ 2138296aa0fSIan Rogers .decode(sys.stdout.encoding) 2148296aa0fSIan Rogers pattern = re.compile(r"[: ]+") 2158296aa0fSIan Rogers auxv = dict([new_auxv(a, pattern) for a in auxv.splitlines()]) 2168296aa0fSIan Rogers return not eval(self.auxv) 2178296aa0fSIan Rogers 2188296aa0fSIan Rogers def skip_test_arch(self, myarch): 2198296aa0fSIan Rogers # If architecture not set always run test 2208296aa0fSIan Rogers if self.arch == '': 2218296aa0fSIan Rogers # log.warning("test for arch %s is ok" % myarch) 2228296aa0fSIan Rogers return False 2238296aa0fSIan Rogers 2248296aa0fSIan Rogers # Allow multiple values in assignment separated by ',' 2258296aa0fSIan Rogers arch_list = self.arch.split(',') 2268296aa0fSIan Rogers 2278296aa0fSIan Rogers # Handle negated list such as !s390x,ppc 2288296aa0fSIan Rogers if arch_list[0][0] == '!': 2298296aa0fSIan Rogers arch_list[0] = arch_list[0][1:] 2308296aa0fSIan Rogers log.warning("excluded architecture list %s" % arch_list) 2318296aa0fSIan Rogers for arch_item in arch_list: 2328296aa0fSIan Rogers # log.warning("test for %s arch is %s" % (arch_item, myarch)) 2338296aa0fSIan Rogers if arch_item == myarch: 2348296aa0fSIan Rogers return True 2358296aa0fSIan Rogers return False 2368296aa0fSIan Rogers 2378296aa0fSIan Rogers for arch_item in arch_list: 2388296aa0fSIan Rogers # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch)) 2398296aa0fSIan Rogers if arch_item == myarch: 2408296aa0fSIan Rogers return False 2418296aa0fSIan Rogers return True 2428296aa0fSIan Rogers 2438296aa0fSIan Rogers def restore_sample_rate(self, value=10000): 2448296aa0fSIan Rogers try: 2458296aa0fSIan Rogers # Check value of sample_rate 2468296aa0fSIan Rogers with open("/proc/sys/kernel/perf_event_max_sample_rate", "r") as fIn: 2478296aa0fSIan Rogers curr_value = fIn.readline() 2488296aa0fSIan Rogers # If too low restore to reasonable value 2498296aa0fSIan Rogers if not curr_value or int(curr_value) < int(value): 2508296aa0fSIan Rogers with open("/proc/sys/kernel/perf_event_max_sample_rate", "w") as fOut: 2518296aa0fSIan Rogers fOut.write(str(value)) 2528296aa0fSIan Rogers 2538296aa0fSIan Rogers except IOError as e: 2548296aa0fSIan Rogers log.warning("couldn't restore sample_rate value: I/O error %s" % e) 2558296aa0fSIan Rogers except ValueError as e: 2568296aa0fSIan Rogers log.warning("couldn't restore sample_rate value: Value error %s" % e) 2578296aa0fSIan Rogers except TypeError as e: 2588296aa0fSIan Rogers log.warning("couldn't restore sample_rate value: Type error %s" % e) 2598296aa0fSIan Rogers 2608296aa0fSIan Rogers def load_events(self, path, events): 2618296aa0fSIan Rogers parser_event = configparser.ConfigParser() 2628296aa0fSIan Rogers parser_event.read(path) 2638296aa0fSIan Rogers 2648296aa0fSIan Rogers # The event record section header contains 'event' word, 2658296aa0fSIan Rogers # optionaly followed by ':' allowing to load 'parent 2668296aa0fSIan Rogers # event' first as a base 2678296aa0fSIan Rogers for section in filter(self.is_event, parser_event.sections()): 2688296aa0fSIan Rogers 2698296aa0fSIan Rogers parser_items = parser_event.items(section); 2708296aa0fSIan Rogers base_items = {} 2718296aa0fSIan Rogers 2728296aa0fSIan Rogers # Read parent event if there's any 2738296aa0fSIan Rogers if (':' in section): 2748296aa0fSIan Rogers base = section[section.index(':') + 1:] 2758296aa0fSIan Rogers parser_base = configparser.ConfigParser() 2768296aa0fSIan Rogers parser_base.read(self.test_dir + '/' + base) 2778296aa0fSIan Rogers base_items = parser_base.items('event') 2788296aa0fSIan Rogers 2798296aa0fSIan Rogers e = Event(section, parser_items, base_items) 2808296aa0fSIan Rogers events[section] = e 2818296aa0fSIan Rogers 2828296aa0fSIan Rogers def run_cmd(self, tempdir): 2838296aa0fSIan Rogers junk1, junk2, junk3, junk4, myarch = (os.uname()) 2848296aa0fSIan Rogers 2858296aa0fSIan Rogers if self.skip_test_arch(myarch): 2868296aa0fSIan Rogers raise Notest(self, myarch) 2878296aa0fSIan Rogers 2888296aa0fSIan Rogers if self.skip_test_auxv(): 2898296aa0fSIan Rogers raise Notest(self, "auxv skip") 2908296aa0fSIan Rogers 2918296aa0fSIan Rogers if self.skip_test_kernel_since(): 2928296aa0fSIan Rogers raise Notest(self, "old kernel skip") 2938296aa0fSIan Rogers 2948296aa0fSIan Rogers if self.skip_test_kernel_until(): 2958296aa0fSIan Rogers raise Notest(self, "new kernel skip") 2968296aa0fSIan Rogers 2978296aa0fSIan Rogers self.restore_sample_rate() 2988296aa0fSIan Rogers cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, 2998296aa0fSIan Rogers self.perf, self.command, tempdir, self.args) 3008296aa0fSIan Rogers ret = os.WEXITSTATUS(os.system(cmd)) 3018296aa0fSIan Rogers 3028296aa0fSIan Rogers log.info(" '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret))) 3038296aa0fSIan Rogers 3048296aa0fSIan Rogers if not data_equal(str(ret), str(self.ret)): 3058296aa0fSIan Rogers if self.test_ret: 3068296aa0fSIan Rogers raise Fail(self, "Perf exit code failure") 3078296aa0fSIan Rogers else: 3088296aa0fSIan Rogers raise Unsup(self) 3098296aa0fSIan Rogers 3108296aa0fSIan Rogers def compare(self, expect, result): 3118296aa0fSIan Rogers match = {} 3128296aa0fSIan Rogers 3138296aa0fSIan Rogers log.debug(" compare"); 3148296aa0fSIan Rogers 3158296aa0fSIan Rogers # For each expected event find all matching 3168296aa0fSIan Rogers # events in result. Fail if there's not any. 3178296aa0fSIan Rogers for exp_name, exp_event in expect.items(): 3188296aa0fSIan Rogers exp_list = [] 3198296aa0fSIan Rogers res_event = {} 3208296aa0fSIan Rogers log.debug(" matching [%s]" % exp_name) 3218296aa0fSIan Rogers for res_name, res_event in result.items(): 3228296aa0fSIan Rogers log.debug(" to [%s]" % res_name) 3238296aa0fSIan Rogers if (exp_event.equal(res_event)): 3248296aa0fSIan Rogers exp_list.append(res_name) 3258296aa0fSIan Rogers log.debug(" ->OK") 3268296aa0fSIan Rogers else: 3278296aa0fSIan Rogers log.debug(" ->FAIL"); 3288296aa0fSIan Rogers 3298296aa0fSIan Rogers log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list))) 3308296aa0fSIan Rogers 3318296aa0fSIan Rogers # we did not any matching event - fail 3328296aa0fSIan Rogers if not exp_list: 3338296aa0fSIan Rogers if exp_event.optional(): 3348296aa0fSIan Rogers log.debug(" %s does not match, but is optional" % exp_name) 3358296aa0fSIan Rogers else: 3368296aa0fSIan Rogers if not res_event: 3378296aa0fSIan Rogers log.debug(" res_event is empty"); 3388296aa0fSIan Rogers else: 3398296aa0fSIan Rogers exp_event.diff(res_event) 3408296aa0fSIan Rogers raise Fail(self, 'match failure'); 3418296aa0fSIan Rogers 3428296aa0fSIan Rogers match[exp_name] = exp_list 3438296aa0fSIan Rogers 3448296aa0fSIan Rogers # For each defined group in the expected events 3458296aa0fSIan Rogers # check we match the same group in the result. 3468296aa0fSIan Rogers for exp_name, exp_event in expect.items(): 3478296aa0fSIan Rogers group = exp_event.group 3488296aa0fSIan Rogers 3498296aa0fSIan Rogers if (group == ''): 3508296aa0fSIan Rogers continue 3518296aa0fSIan Rogers 3528296aa0fSIan Rogers for res_name in match[exp_name]: 3538296aa0fSIan Rogers res_group = result[res_name].group 3548296aa0fSIan Rogers if res_group not in match[group]: 3558296aa0fSIan Rogers raise Fail(self, 'group failure') 3568296aa0fSIan Rogers 3578296aa0fSIan Rogers log.debug(" group: [%s] matches group leader %s" % 3588296aa0fSIan Rogers (exp_name, str(match[group]))) 3598296aa0fSIan Rogers 3608296aa0fSIan Rogers log.debug(" matched") 3618296aa0fSIan Rogers 3628296aa0fSIan Rogers def resolve_groups(self, events): 3638296aa0fSIan Rogers for name, event in events.items(): 3648296aa0fSIan Rogers group_fd = event['group_fd']; 3658296aa0fSIan Rogers if group_fd == '-1': 3668296aa0fSIan Rogers continue; 3678296aa0fSIan Rogers 3688296aa0fSIan Rogers for iname, ievent in events.items(): 3698296aa0fSIan Rogers if (ievent['fd'] == group_fd): 3708296aa0fSIan Rogers event.group = iname 3718296aa0fSIan Rogers log.debug('[%s] has group leader [%s]' % (name, iname)) 3728296aa0fSIan Rogers break; 3738296aa0fSIan Rogers 3748296aa0fSIan Rogers def run(self): 3758296aa0fSIan Rogers tempdir = tempfile.mkdtemp(); 3768296aa0fSIan Rogers 3778296aa0fSIan Rogers try: 3788296aa0fSIan Rogers # run the test script 3798296aa0fSIan Rogers self.run_cmd(tempdir); 3808296aa0fSIan Rogers 3818296aa0fSIan Rogers # load events expectation for the test 3828296aa0fSIan Rogers log.debug(" loading result events"); 3838296aa0fSIan Rogers for f in glob.glob(tempdir + '/event*'): 3848296aa0fSIan Rogers self.load_events(f, self.result); 3858296aa0fSIan Rogers 3868296aa0fSIan Rogers # resolve group_fd to event names 3878296aa0fSIan Rogers self.resolve_groups(self.expect); 3888296aa0fSIan Rogers self.resolve_groups(self.result); 3898296aa0fSIan Rogers 3908296aa0fSIan Rogers # do the expectation - results matching - both ways 3918296aa0fSIan Rogers self.compare(self.expect, self.result) 3928296aa0fSIan Rogers self.compare(self.result, self.expect) 3938296aa0fSIan Rogers 3948296aa0fSIan Rogers finally: 3958296aa0fSIan Rogers # cleanup 3968296aa0fSIan Rogers shutil.rmtree(tempdir) 3978296aa0fSIan Rogers 3988296aa0fSIan Rogers 3998296aa0fSIan Rogersdef run_tests(options): 4008296aa0fSIan Rogers for f in glob.glob(options.test_dir + '/' + options.test): 4018296aa0fSIan Rogers try: 4028296aa0fSIan Rogers Test(f, options).run() 4038296aa0fSIan Rogers except Unsup as obj: 4048296aa0fSIan Rogers log.warning("unsupp %s" % obj.getMsg()) 4058296aa0fSIan Rogers except Notest as obj: 4068296aa0fSIan Rogers log.warning("skipped %s" % obj.getMsg()) 4078296aa0fSIan Rogers 4088296aa0fSIan Rogersdef setup_log(verbose): 4098296aa0fSIan Rogers global log 4108296aa0fSIan Rogers level = logging.CRITICAL 4118296aa0fSIan Rogers 4128296aa0fSIan Rogers if verbose == 1: 4138296aa0fSIan Rogers level = logging.WARNING 4148296aa0fSIan Rogers if verbose == 2: 4158296aa0fSIan Rogers level = logging.INFO 4168296aa0fSIan Rogers if verbose >= 3: 4178296aa0fSIan Rogers level = logging.DEBUG 4188296aa0fSIan Rogers 4198296aa0fSIan Rogers log = logging.getLogger('test') 4208296aa0fSIan Rogers log.setLevel(level) 4218296aa0fSIan Rogers ch = logging.StreamHandler() 4228296aa0fSIan Rogers ch.setLevel(level) 4238296aa0fSIan Rogers formatter = logging.Formatter('%(message)s') 4248296aa0fSIan Rogers ch.setFormatter(formatter) 4258296aa0fSIan Rogers log.addHandler(ch) 4268296aa0fSIan Rogers 4278296aa0fSIan RogersUSAGE = '''%s [OPTIONS] 4288296aa0fSIan Rogers -d dir # tests dir 4298296aa0fSIan Rogers -p path # perf binary 4308296aa0fSIan Rogers -t test # single test 4318296aa0fSIan Rogers -v # verbose level 4328296aa0fSIan Rogers''' % sys.argv[0] 4338296aa0fSIan Rogers 4348296aa0fSIan Rogersdef main(): 4358296aa0fSIan Rogers parser = optparse.OptionParser(usage=USAGE) 4368296aa0fSIan Rogers 4378296aa0fSIan Rogers parser.add_option("-t", "--test", 4388296aa0fSIan Rogers action="store", type="string", dest="test") 4398296aa0fSIan Rogers parser.add_option("-d", "--test-dir", 4408296aa0fSIan Rogers action="store", type="string", dest="test_dir") 4418296aa0fSIan Rogers parser.add_option("-p", "--perf", 4428296aa0fSIan Rogers action="store", type="string", dest="perf") 4438296aa0fSIan Rogers parser.add_option("-v", "--verbose", 4448296aa0fSIan Rogers default=0, action="count", dest="verbose") 4458296aa0fSIan Rogers 4468296aa0fSIan Rogers options, args = parser.parse_args() 4478296aa0fSIan Rogers if args: 4488296aa0fSIan Rogers parser.error('FAILED wrong arguments %s' % ' '.join(args)) 4498296aa0fSIan Rogers return -1 4508296aa0fSIan Rogers 4518296aa0fSIan Rogers setup_log(options.verbose) 4528296aa0fSIan Rogers 4538296aa0fSIan Rogers if not options.test_dir: 4548296aa0fSIan Rogers print('FAILED no -d option specified') 4558296aa0fSIan Rogers sys.exit(-1) 4568296aa0fSIan Rogers 4578296aa0fSIan Rogers if not options.test: 4588296aa0fSIan Rogers options.test = 'test*' 4598296aa0fSIan Rogers 4608296aa0fSIan Rogers try: 4618296aa0fSIan Rogers run_tests(options) 4628296aa0fSIan Rogers 4638296aa0fSIan Rogers except Fail as obj: 4648296aa0fSIan Rogers print("FAILED %s" % obj.getMsg()) 4658296aa0fSIan Rogers sys.exit(-1) 4668296aa0fSIan Rogers 4678296aa0fSIan Rogers sys.exit(0) 4688296aa0fSIan Rogers 4698296aa0fSIan Rogersif __name__ == '__main__': 4708296aa0fSIan Rogers main() 471