Back to home page

OSCL-LXR

 
 

    


0001 '''
0002 run the command under test, under valgrind and collect memory leak info
0003 as a separate test.
0004 '''
0005 
0006 
0007 import os
0008 import re
0009 import signal
0010 from string import Template
0011 import subprocess
0012 import time
0013 from TdcPlugin import TdcPlugin
0014 from TdcResults import *
0015 
0016 from tdc_config import *
0017 
0018 def vp_extract_num_from_string(num_as_string_maybe_with_commas):
0019     return int(num_as_string_maybe_with_commas.replace(',',''))
0020 
0021 class SubPlugin(TdcPlugin):
0022     def __init__(self):
0023         self.sub_class = 'valgrind/SubPlugin'
0024         self.tap = ''
0025         self._tsr = TestSuiteReport()
0026         super().__init__()
0027 
0028     def pre_suite(self, testcount, testidlist):
0029         '''run commands before test_runner goes into a test loop'''
0030         super().pre_suite(testcount, testidlist)
0031         if self.args.verbose > 1:
0032             print('{}.pre_suite'.format(self.sub_class))
0033         if self.args.valgrind:
0034             self._add_to_tap('1..{}\n'.format(self.testcount))
0035 
0036     def post_suite(self, index):
0037         '''run commands after test_runner goes into a test loop'''
0038         super().post_suite(index)
0039         if self.args.verbose > 1:
0040             print('{}.post_suite'.format(self.sub_class))
0041         #print('{}'.format(self.tap))
0042         for xx in range(index - 1, self.testcount):
0043             res = TestResult('{}-mem'.format(self.testidlist[xx]), 'Test skipped')
0044             res.set_result(ResultState.skip)
0045             res.set_errormsg('Skipped because of prior setup/teardown failure')
0046             self._add_results(res)
0047         if self.args.verbose < 4:
0048             subprocess.check_output('rm -f vgnd-*.log', shell=True)
0049 
0050     def add_args(self, parser):
0051         super().add_args(parser)
0052         self.argparser_group = self.argparser.add_argument_group(
0053             'valgrind',
0054             'options for valgrindPlugin (run command under test under Valgrind)')
0055 
0056         self.argparser_group.add_argument(
0057             '-V', '--valgrind', action='store_true',
0058             help='Run commands under valgrind')
0059 
0060         return self.argparser
0061 
0062     def adjust_command(self, stage, command):
0063         super().adjust_command(stage, command)
0064         cmdform = 'list'
0065         cmdlist = list()
0066 
0067         if not self.args.valgrind:
0068             return command
0069 
0070         if self.args.verbose > 1:
0071             print('{}.adjust_command'.format(self.sub_class))
0072 
0073         if not isinstance(command, list):
0074             cmdform = 'str'
0075             cmdlist = command.split()
0076         else:
0077             cmdlist = command
0078 
0079         if stage == 'execute':
0080             if self.args.verbose > 1:
0081                 print('adjust_command:  stage is {}; inserting valgrind stuff in command [{}] list [{}]'.
0082                       format(stage, command, cmdlist))
0083             cmdlist.insert(0, '--track-origins=yes')
0084             cmdlist.insert(0, '--show-leak-kinds=definite,indirect')
0085             cmdlist.insert(0, '--leak-check=full')
0086             cmdlist.insert(0, '--log-file=vgnd-{}.log'.format(self.args.testid))
0087             cmdlist.insert(0, '-v')  # ask for summary of non-leak errors
0088             cmdlist.insert(0, ENVIR['VALGRIND_BIN'])
0089         else:
0090             pass
0091 
0092         if cmdform == 'str':
0093             command = ' '.join(cmdlist)
0094         else:
0095             command = cmdlist
0096 
0097         if self.args.verbose > 1:
0098             print('adjust_command:  return command [{}]'.format(command))
0099         return command
0100 
0101     def post_execute(self):
0102         if not self.args.valgrind:
0103             return
0104 
0105         res = TestResult('{}-mem'.format(self.args.testid),
0106               '{} memory leak check'.format(self.args.test_name))
0107         if self.args.test_skip:
0108             res.set_result(ResultState.skip)
0109             res.set_errormsg('Test case designated as skipped.')
0110             self._add_results(res)
0111             return
0112 
0113         self.definitely_lost_re = re.compile(
0114             r'definitely lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\sblocks', re.MULTILINE | re.DOTALL)
0115         self.indirectly_lost_re = re.compile(
0116             r'indirectly lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL)
0117         self.possibly_lost_re = re.compile(
0118             r'possibly lost:\s+([,0-9]+)bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL)
0119         self.non_leak_error_re = re.compile(
0120             r'ERROR SUMMARY:\s+([,0-9]+) errors from\s+([,0-9]+)\s+contexts', re.MULTILINE | re.DOTALL)
0121 
0122         def_num = 0
0123         ind_num = 0
0124         pos_num = 0
0125         nle_num = 0
0126 
0127         # what about concurrent test runs?  Maybe force them to be in different directories?
0128         with open('vgnd-{}.log'.format(self.args.testid)) as vfd:
0129             content = vfd.read()
0130             def_mo = self.definitely_lost_re.search(content)
0131             ind_mo = self.indirectly_lost_re.search(content)
0132             pos_mo = self.possibly_lost_re.search(content)
0133             nle_mo = self.non_leak_error_re.search(content)
0134 
0135             if def_mo:
0136                 def_num = int(def_mo.group(2))
0137             if ind_mo:
0138                 ind_num = int(ind_mo.group(2))
0139             if pos_mo:
0140                 pos_num = int(pos_mo.group(2))
0141             if nle_mo:
0142                 nle_num = int(nle_mo.group(1))
0143 
0144         mem_results = ''
0145         if (def_num > 0) or (ind_num > 0) or (pos_num > 0) or (nle_num > 0):
0146             mem_results += 'not '
0147             res.set_result(ResultState.fail)
0148             res.set_failmsg('Memory leak detected')
0149             res.append_failmsg(content)
0150         else:
0151             res.set_result(ResultState.success)
0152 
0153         self._add_results(res)
0154 
0155 
0156     def _add_results(self, res):
0157         self._tsr.add_resultdata(res)
0158 
0159     def _add_to_tap(self, more_tap_output):
0160         self.tap += more_tap_output