mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-05 01:54:09 +08:00
255c1c7279
By adding a check for an optional key/value pair to the test case data, individual test cases may be skipped to prevent tdc from aborting a test run due to setup or teardown failure. If a test case is skipped, it will still appear in the results output to allow for a consistent number of executed tests in each run. However, the test will be marked as skipped. This support for skipping extends to any plugins that may generate additional results for each executed test. Signed-off-by: Lucas Bates <lucasb@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
'''
|
|
run the command under test, under valgrind and collect memory leak info
|
|
as a separate test.
|
|
'''
|
|
|
|
|
|
import os
|
|
import re
|
|
import signal
|
|
from string import Template
|
|
import subprocess
|
|
import time
|
|
from TdcPlugin import TdcPlugin
|
|
from TdcResults import *
|
|
|
|
from tdc_config import *
|
|
|
|
def vp_extract_num_from_string(num_as_string_maybe_with_commas):
|
|
return int(num_as_string_maybe_with_commas.replace(',',''))
|
|
|
|
class SubPlugin(TdcPlugin):
|
|
def __init__(self):
|
|
self.sub_class = 'valgrind/SubPlugin'
|
|
self.tap = ''
|
|
self._tsr = TestSuiteReport()
|
|
super().__init__()
|
|
|
|
def pre_suite(self, testcount, testidlist):
|
|
'''run commands before test_runner goes into a test loop'''
|
|
super().pre_suite(testcount, testidlist)
|
|
if self.args.verbose > 1:
|
|
print('{}.pre_suite'.format(self.sub_class))
|
|
if self.args.valgrind:
|
|
self._add_to_tap('1..{}\n'.format(self.testcount))
|
|
|
|
def post_suite(self, index):
|
|
'''run commands after test_runner goes into a test loop'''
|
|
super().post_suite(index)
|
|
if self.args.verbose > 1:
|
|
print('{}.post_suite'.format(self.sub_class))
|
|
#print('{}'.format(self.tap))
|
|
for xx in range(index - 1, self.testcount):
|
|
res = TestResult('{}-mem'.format(self.testidlist[xx]), 'Test skipped')
|
|
res.set_result(ResultState.skip)
|
|
res.set_errormsg('Skipped because of prior setup/teardown failure')
|
|
self._add_results(res)
|
|
if self.args.verbose < 4:
|
|
subprocess.check_output('rm -f vgnd-*.log', shell=True)
|
|
|
|
def add_args(self, parser):
|
|
super().add_args(parser)
|
|
self.argparser_group = self.argparser.add_argument_group(
|
|
'valgrind',
|
|
'options for valgrindPlugin (run command under test under Valgrind)')
|
|
|
|
self.argparser_group.add_argument(
|
|
'-V', '--valgrind', action='store_true',
|
|
help='Run commands under valgrind')
|
|
|
|
return self.argparser
|
|
|
|
def adjust_command(self, stage, command):
|
|
super().adjust_command(stage, command)
|
|
cmdform = 'list'
|
|
cmdlist = list()
|
|
|
|
if not self.args.valgrind:
|
|
return command
|
|
|
|
if self.args.verbose > 1:
|
|
print('{}.adjust_command'.format(self.sub_class))
|
|
|
|
if not isinstance(command, list):
|
|
cmdform = 'str'
|
|
cmdlist = command.split()
|
|
else:
|
|
cmdlist = command
|
|
|
|
if stage == 'execute':
|
|
if self.args.verbose > 1:
|
|
print('adjust_command: stage is {}; inserting valgrind stuff in command [{}] list [{}]'.
|
|
format(stage, command, cmdlist))
|
|
cmdlist.insert(0, '--track-origins=yes')
|
|
cmdlist.insert(0, '--show-leak-kinds=definite,indirect')
|
|
cmdlist.insert(0, '--leak-check=full')
|
|
cmdlist.insert(0, '--log-file=vgnd-{}.log'.format(self.args.testid))
|
|
cmdlist.insert(0, '-v') # ask for summary of non-leak errors
|
|
cmdlist.insert(0, ENVIR['VALGRIND_BIN'])
|
|
else:
|
|
pass
|
|
|
|
if cmdform == 'str':
|
|
command = ' '.join(cmdlist)
|
|
else:
|
|
command = cmdlist
|
|
|
|
if self.args.verbose > 1:
|
|
print('adjust_command: return command [{}]'.format(command))
|
|
return command
|
|
|
|
def post_execute(self):
|
|
if not self.args.valgrind:
|
|
return
|
|
|
|
res = TestResult('{}-mem'.format(self.args.testid),
|
|
'{} memory leak check'.format(self.args.test_name))
|
|
if self.args.test_skip:
|
|
res.set_result(ResultState.skip)
|
|
res.set_errormsg('Test case designated as skipped.')
|
|
self._add_results(res)
|
|
return
|
|
|
|
self.definitely_lost_re = re.compile(
|
|
r'definitely lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\sblocks', re.MULTILINE | re.DOTALL)
|
|
self.indirectly_lost_re = re.compile(
|
|
r'indirectly lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL)
|
|
self.possibly_lost_re = re.compile(
|
|
r'possibly lost:\s+([,0-9]+)bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL)
|
|
self.non_leak_error_re = re.compile(
|
|
r'ERROR SUMMARY:\s+([,0-9]+) errors from\s+([,0-9]+)\s+contexts', re.MULTILINE | re.DOTALL)
|
|
|
|
def_num = 0
|
|
ind_num = 0
|
|
pos_num = 0
|
|
nle_num = 0
|
|
|
|
# what about concurrent test runs? Maybe force them to be in different directories?
|
|
with open('vgnd-{}.log'.format(self.args.testid)) as vfd:
|
|
content = vfd.read()
|
|
def_mo = self.definitely_lost_re.search(content)
|
|
ind_mo = self.indirectly_lost_re.search(content)
|
|
pos_mo = self.possibly_lost_re.search(content)
|
|
nle_mo = self.non_leak_error_re.search(content)
|
|
|
|
if def_mo:
|
|
def_num = int(def_mo.group(2))
|
|
if ind_mo:
|
|
ind_num = int(ind_mo.group(2))
|
|
if pos_mo:
|
|
pos_num = int(pos_mo.group(2))
|
|
if nle_mo:
|
|
nle_num = int(nle_mo.group(1))
|
|
|
|
mem_results = ''
|
|
if (def_num > 0) or (ind_num > 0) or (pos_num > 0) or (nle_num > 0):
|
|
mem_results += 'not '
|
|
res.set_result(ResultState.fail)
|
|
res.set_failmsg('Memory leak detected')
|
|
res.append_failmsg(content)
|
|
else:
|
|
res.set_result(ResultState.success)
|
|
|
|
self._add_results(res)
|
|
|
|
|
|
def _add_results(self, res):
|
|
self._tsr.add_resultdata(res)
|
|
|
|
def _add_to_tap(self, more_tap_output):
|
|
self.tap += more_tap_output
|