1c25e4736SBrenda J. Butler''' 2c25e4736SBrenda J. Butlerrun the command under test, under valgrind and collect memory leak info 3c25e4736SBrenda J. Butleras a separate test. 4c25e4736SBrenda J. Butler''' 5c25e4736SBrenda J. Butler 6c25e4736SBrenda J. Butler 7c25e4736SBrenda J. Butlerimport os 8c25e4736SBrenda J. Butlerimport re 9c25e4736SBrenda J. Butlerimport signal 10c25e4736SBrenda J. Butlerfrom string import Template 11c25e4736SBrenda J. Butlerimport subprocess 12c25e4736SBrenda J. Butlerimport time 13c25e4736SBrenda J. Butlerfrom TdcPlugin import TdcPlugin 14915c158dSLucas Batesfrom TdcResults import * 15c25e4736SBrenda J. Butler 16c25e4736SBrenda J. Butlerfrom tdc_config import * 17c25e4736SBrenda J. Butler 18c25e4736SBrenda J. Butlerdef vp_extract_num_from_string(num_as_string_maybe_with_commas): 19c25e4736SBrenda J. Butler return int(num_as_string_maybe_with_commas.replace(',','')) 20c25e4736SBrenda J. Butler 21c25e4736SBrenda J. Butlerclass SubPlugin(TdcPlugin): 22c25e4736SBrenda J. Butler def __init__(self): 23c25e4736SBrenda J. Butler self.sub_class = 'valgrind/SubPlugin' 24c25e4736SBrenda J. Butler self.tap = '' 25915c158dSLucas Bates self._tsr = TestSuiteReport() 26c25e4736SBrenda J. Butler super().__init__() 27c25e4736SBrenda J. Butler 28*98cfbe42SPedro Tammela def pre_suite(self, testcount, testist): 29c25e4736SBrenda J. Butler '''run commands before test_runner goes into a test loop''' 30*98cfbe42SPedro Tammela self.testidlist = [tidx['id'] for tidx in testlist] 31*98cfbe42SPedro Tammela super().pre_suite(testcount, testlist) 32c25e4736SBrenda J. Butler if self.args.verbose > 1: 33c25e4736SBrenda J. Butler print('{}.pre_suite'.format(self.sub_class)) 34c25e4736SBrenda J. Butler if self.args.valgrind: 35c25e4736SBrenda J. Butler self._add_to_tap('1..{}\n'.format(self.testcount)) 36c25e4736SBrenda J. Butler 37c25e4736SBrenda J. Butler def post_suite(self, index): 38c25e4736SBrenda J. Butler '''run commands after test_runner goes into a test loop''' 39c25e4736SBrenda J. Butler super().post_suite(index) 40c25e4736SBrenda J. Butler if self.args.verbose > 1: 41c25e4736SBrenda J. Butler print('{}.post_suite'.format(self.sub_class)) 42915c158dSLucas Bates #print('{}'.format(self.tap)) 43915c158dSLucas Bates for xx in range(index - 1, self.testcount): 44915c158dSLucas Bates res = TestResult('{}-mem'.format(self.testidlist[xx]), 'Test skipped') 45915c158dSLucas Bates res.set_result(ResultState.skip) 46915c158dSLucas Bates res.set_errormsg('Skipped because of prior setup/teardown failure') 47915c158dSLucas Bates self._add_results(res) 48c25e4736SBrenda J. Butler if self.args.verbose < 4: 49c25e4736SBrenda J. Butler subprocess.check_output('rm -f vgnd-*.log', shell=True) 50c25e4736SBrenda J. Butler 51c25e4736SBrenda J. Butler def add_args(self, parser): 52c25e4736SBrenda J. Butler super().add_args(parser) 53c25e4736SBrenda J. Butler self.argparser_group = self.argparser.add_argument_group( 54c25e4736SBrenda J. Butler 'valgrind', 55c25e4736SBrenda J. Butler 'options for valgrindPlugin (run command under test under Valgrind)') 56c25e4736SBrenda J. Butler 57c25e4736SBrenda J. Butler self.argparser_group.add_argument( 58c25e4736SBrenda J. Butler '-V', '--valgrind', action='store_true', 59c25e4736SBrenda J. Butler help='Run commands under valgrind') 60c25e4736SBrenda J. Butler 61c25e4736SBrenda J. Butler return self.argparser 62c25e4736SBrenda J. Butler 63c25e4736SBrenda J. Butler def adjust_command(self, stage, command): 64c25e4736SBrenda J. Butler super().adjust_command(stage, command) 65c25e4736SBrenda J. Butler cmdform = 'list' 66c25e4736SBrenda J. Butler cmdlist = list() 67c25e4736SBrenda J. Butler 68c25e4736SBrenda J. Butler if not self.args.valgrind: 69c25e4736SBrenda J. Butler return command 70c25e4736SBrenda J. Butler 71c25e4736SBrenda J. Butler if self.args.verbose > 1: 72c25e4736SBrenda J. Butler print('{}.adjust_command'.format(self.sub_class)) 73c25e4736SBrenda J. Butler 74c25e4736SBrenda J. Butler if not isinstance(command, list): 75c25e4736SBrenda J. Butler cmdform = 'str' 76c25e4736SBrenda J. Butler cmdlist = command.split() 77c25e4736SBrenda J. Butler else: 78c25e4736SBrenda J. Butler cmdlist = command 79c25e4736SBrenda J. Butler 80c25e4736SBrenda J. Butler if stage == 'execute': 81c25e4736SBrenda J. Butler if self.args.verbose > 1: 82c25e4736SBrenda J. Butler print('adjust_command: stage is {}; inserting valgrind stuff in command [{}] list [{}]'. 83c25e4736SBrenda J. Butler format(stage, command, cmdlist)) 84c25e4736SBrenda J. Butler cmdlist.insert(0, '--track-origins=yes') 85c25e4736SBrenda J. Butler cmdlist.insert(0, '--show-leak-kinds=definite,indirect') 86c25e4736SBrenda J. Butler cmdlist.insert(0, '--leak-check=full') 87c25e4736SBrenda J. Butler cmdlist.insert(0, '--log-file=vgnd-{}.log'.format(self.args.testid)) 88c25e4736SBrenda J. Butler cmdlist.insert(0, '-v') # ask for summary of non-leak errors 89c25e4736SBrenda J. Butler cmdlist.insert(0, ENVIR['VALGRIND_BIN']) 90c25e4736SBrenda J. Butler else: 91c25e4736SBrenda J. Butler pass 92c25e4736SBrenda J. Butler 93c25e4736SBrenda J. Butler if cmdform == 'str': 94c25e4736SBrenda J. Butler command = ' '.join(cmdlist) 95c25e4736SBrenda J. Butler else: 96c25e4736SBrenda J. Butler command = cmdlist 97c25e4736SBrenda J. Butler 98c25e4736SBrenda J. Butler if self.args.verbose > 1: 99c25e4736SBrenda J. Butler print('adjust_command: return command [{}]'.format(command)) 100c25e4736SBrenda J. Butler return command 101c25e4736SBrenda J. Butler 102c25e4736SBrenda J. Butler def post_execute(self): 103c25e4736SBrenda J. Butler if not self.args.valgrind: 104c25e4736SBrenda J. Butler return 105c25e4736SBrenda J. Butler 106255c1c72SLucas Bates res = TestResult('{}-mem'.format(self.args.testid), 107255c1c72SLucas Bates '{} memory leak check'.format(self.args.test_name)) 108255c1c72SLucas Bates if self.args.test_skip: 109255c1c72SLucas Bates res.set_result(ResultState.skip) 110255c1c72SLucas Bates res.set_errormsg('Test case designated as skipped.') 111255c1c72SLucas Bates self._add_results(res) 112255c1c72SLucas Bates return 113255c1c72SLucas Bates 114c25e4736SBrenda J. Butler self.definitely_lost_re = re.compile( 115c25e4736SBrenda J. Butler r'definitely lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\sblocks', re.MULTILINE | re.DOTALL) 116c25e4736SBrenda J. Butler self.indirectly_lost_re = re.compile( 117c25e4736SBrenda J. Butler r'indirectly lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL) 118c25e4736SBrenda J. Butler self.possibly_lost_re = re.compile( 119c25e4736SBrenda J. Butler r'possibly lost:\s+([,0-9]+)bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL) 120c25e4736SBrenda J. Butler self.non_leak_error_re = re.compile( 121c25e4736SBrenda J. Butler r'ERROR SUMMARY:\s+([,0-9]+) errors from\s+([,0-9]+)\s+contexts', re.MULTILINE | re.DOTALL) 122c25e4736SBrenda J. Butler 123c25e4736SBrenda J. Butler def_num = 0 124c25e4736SBrenda J. Butler ind_num = 0 125c25e4736SBrenda J. Butler pos_num = 0 126c25e4736SBrenda J. Butler nle_num = 0 127c25e4736SBrenda J. Butler 128c25e4736SBrenda J. Butler # what about concurrent test runs? Maybe force them to be in different directories? 129c25e4736SBrenda J. Butler with open('vgnd-{}.log'.format(self.args.testid)) as vfd: 130c25e4736SBrenda J. Butler content = vfd.read() 131c25e4736SBrenda J. Butler def_mo = self.definitely_lost_re.search(content) 132c25e4736SBrenda J. Butler ind_mo = self.indirectly_lost_re.search(content) 133c25e4736SBrenda J. Butler pos_mo = self.possibly_lost_re.search(content) 134c25e4736SBrenda J. Butler nle_mo = self.non_leak_error_re.search(content) 135c25e4736SBrenda J. Butler 136c25e4736SBrenda J. Butler if def_mo: 137c25e4736SBrenda J. Butler def_num = int(def_mo.group(2)) 138c25e4736SBrenda J. Butler if ind_mo: 139c25e4736SBrenda J. Butler ind_num = int(ind_mo.group(2)) 140c25e4736SBrenda J. Butler if pos_mo: 141c25e4736SBrenda J. Butler pos_num = int(pos_mo.group(2)) 142c25e4736SBrenda J. Butler if nle_mo: 143c25e4736SBrenda J. Butler nle_num = int(nle_mo.group(1)) 144c25e4736SBrenda J. Butler 145c25e4736SBrenda J. Butler mem_results = '' 146c25e4736SBrenda J. Butler if (def_num > 0) or (ind_num > 0) or (pos_num > 0) or (nle_num > 0): 147c25e4736SBrenda J. Butler mem_results += 'not ' 148915c158dSLucas Bates res.set_result(ResultState.fail) 149915c158dSLucas Bates res.set_failmsg('Memory leak detected') 150915c158dSLucas Bates res.append_failmsg(content) 151915c158dSLucas Bates else: 152915c158dSLucas Bates res.set_result(ResultState.success) 153915c158dSLucas Bates 154915c158dSLucas Bates self._add_results(res) 155c25e4736SBrenda J. Butler 156c25e4736SBrenda J. Butler 157915c158dSLucas Bates def _add_results(self, res): 158915c158dSLucas Bates self._tsr.add_resultdata(res) 159915c158dSLucas Bates 160c25e4736SBrenda J. Butler def _add_to_tap(self, more_tap_output): 161c25e4736SBrenda J. Butler self.tap += more_tap_output 162