Changeset cd8fa2f in rtems-tools


Ignore:
Timestamp:
Sep 7, 2020, 12:05:19 AM (3 weeks ago)
Author:
Chris Johns <chrisj@…>
Branches:
master
Children:
0ad4aaa
Parents:
b1c6a98
git-author:
Chris Johns <chrisj@…> (09/07/20 00:05:19)
git-committer:
Chris Johns <chrisj@…> (09/08/20 06:15:43)
Message:

tester: Add support for test-too-long

  • A test that loops generating output did not timeout. Monitor the the session time and set a maximum test period.
Location:
tester
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • tester/rt/config.py

    rb1c6a98 rcd8fa2f  
    11#
    22# RTEMS Tools Project (http://www.rtems.org/)
    3 # Copyright 2013-2017 Chris Johns (chrisj@rtems.org)
     3# Copyright 2013-2020 Chris Johns (chrisj@rtems.org)
    44# All rights reserved.
    55#
     
    5050
    5151import console
     52import exe
    5253import gdb
    5354import tftp
     
    7980        self.name = name
    8081        self.timedout = False
     82        self.test_too_long = False
    8183        self.test_started = False
    8284        self.kill_good = False
     
    102104        self._unlock()
    103105        self.capture('*** TIMEOUT TIMEOUT')
     106
     107    def _test_too_long(self):
     108        self._lock()
     109        self.test_too_long = True
     110        self._unlock()
     111        self.capture('*** TEST TOO LONG')
    104112
    105113    def _ok_kill(self):
     
    220228                raise error.general(self._name_line_msg('invalid console type'))
    221229
    222     def _dir_execute(self, data, total, index, exe, bsp_arch, bsp):
    223         self.process = execute.execute(output = self.capture)
    224         if self.console:
    225             self.console.open()
     230    def _dir_execute(self, data, total, index, rexe, bsp_arch, bsp):
     231        self.process = exe.exe(bsp_arch, bsp, trace = self.exe_trace('exe'))
    226232        if not self.in_error:
    227             self.capture_console('run: %s' % (' '.join(data)))
     233            if self.console:
     234                self.console.open()
    228235            if not self.opts.dry_run():
    229                 ec, proc = self.process.open(data,
    230                                              timeout = (int(self.expand('%{timeout}')),
    231                                                         self._timeout))
    232                 self._lock()
    233                 if not (self.kill_good or self.defined('exe_ignore_ret')) and ec > 0:
    234                     self._error('execute failed: %s: exit-code:%d' % (' '.join(data), ec))
    235                 elif self.timedout:
    236                     self.process.kill()
    237                 self._unlock()
     236                self.process.open(data,
     237                                  ignore_exit_code = self.defined('exe_ignore_ret'),
     238                                  output = self.capture,
     239                                  console = self.capture_console,
     240                                  timeout = (int(self.expand('%{timeout}')),
     241                                             int(self.expand('%{max_test_period}')),
     242                                             self._timeout,
     243                                             self._test_too_long))
    238244            if self.console:
    239245                self.console.close()
     
    256262                                  output = self.capture,
    257263                                  gdb_console = self.capture_console,
    258                                   timeout = int(self.expand('%{timeout}')))
     264                                  timeout = (int(self.expand('%{timeout}')),
     265                                             int(self.expand('%{max_test_period}')),
     266                                             self._timeout,
     267                                             self._test_too_long))
    259268            if self.console:
    260269                self.console.close()
     
    279288                                  console = self.capture_console,
    280289                                  timeout = (int(self.expand('%{timeout}')),
    281                                              self._timeout))
     290                                             int(self.expand('%{max_test_period}')),
     291                                             self._timeout,
     292                                             self._test_too_long))
    282293                if self.console:
    283294                    self.console.close()
  • tester/rt/gdb.py

    rb1c6a98 rcd8fa2f  
    4444import sys
    4545import threading
     46import time
    4647
    4748from rtemstoolkit import error
     
    6869        self.bsp_arch = bsp_arch
    6970        self.output = None
     71        self.output_length = 0
    7072        self.gdb_console = None
    7173        self.input = queue.Queue()
    7274        self.commands = queue.Queue()
    7375        self.process = None
     76        self.ecode = None
    7477        self.state = {}
    7578        self.running = False
     
    7780        self.output = None
    7881        self.output_buffer = ''
     82        self.timeout = None
     83        self.test_too_long = None
    7984        self.lc = 0
    8085
     
    154159
    155160    def _timeout(self):
    156         self._lock('_timeout')
    157         try:
    158             if self.output:
    159                 self.output('*** TIMEOUT TIMEOUT')
    160                 self._gdb_quit(backtrace = True)
    161         finally:
    162             self._unlock('_timeout')
     161        self._stop()
     162        if self.timeout is not None:
     163            self.timeout()
     164
     165    def _test_too_long(self):
     166        self._stop()
     167        if self.test_too_long is not None:
     168            self.test_too_long()
    163169
    164170    def _cleanup(self, proc):
     
    182188            self._unlock('_gdb_quit')
    183189
     190    def _stop(self):
     191        self._gdb_quit(backtrace=True)
     192        seconds = 5
     193        step = 0.1
     194        while self.process and seconds > 0:
     195            if seconds > step:
     196                seconds -= step
     197            else:
     198                seconds = 0
     199            self._unlock('_stop')
     200            time.sleep(step)
     201            self._lock('_stop')
     202        if self.process and seconds == 0:
     203            self._kill()
     204
     205    def _kill(self):
     206        if self.process:
     207            self.process.kill()
     208        self.process = None
     209
     210    def _execute_gdb(self, args):
     211        '''Thread to execute GDB and to wait for it to finish.'''
     212        cmds = args
     213        self.gdb_console('gdb: %s' % (' '.join(cmds)))
     214        ecode, proc = self.process.open(cmds)
     215        if self.trace:
     216            print('gdb done', ecode)
     217        self._lock('_execute_gdb')
     218        self.ecode = ecode
     219        self.process = None
     220        self.running = False
     221        self._unlock('_execute_gdb')
     222
     223    def _monitor(self, timeout):
     224        output_length = self.output_length
     225        step = 0.25
     226        period = timeout[0]
     227        seconds = timeout[1]
     228        while self.process and period > 0 and seconds > 0:
     229            current_length = self.output_length
     230            if output_length != current_length:
     231                period = timeout[0]
     232            output_length = current_length
     233            if seconds < step:
     234                seconds = 0
     235            else:
     236                seconds -= step
     237            if period < step:
     238                step = period
     239                period = 0
     240            else:
     241                period -= step
     242            self._unlock('_monitor')
     243            time.sleep(step)
     244            self._lock('_monitor')
     245        if self.process is not None:
     246            if period == 0:
     247                self._timeout()
     248            elif seconds == 0:
     249                self._test_too_long()
     250
    184251    def open(self, command, executable,
    185              output, gdb_console, script = None, tty = None,
    186              timeout = 300):
     252             output, gdb_console, timeout,
     253             script = None, tty = None):
    187254        self._lock('_open')
     255        self.timeout = timeout[2]
     256        self.test_too_long = timeout[3]
    188257        try:
    189258            cmds = execute.arg_list(command) + ['-i=mi',
     
    197266            self.gdb_console = gdb_console
    198267            self.script = script
    199             self.running = False
    200268            self.process = execute.execute(output = self._reader,
    201269                                           input = self._writer,
    202270                                           cleanup = self._cleanup)
     271            exec_thread = threading.Thread(target=self._execute_gdb,
     272                                           args=[cmds])
     273            exec_thread.start()
     274            self._monitor(timeout)
     275            if self.ecode is not None and self.ecode > 0:
     276                raise error.general('gdb exec: %s: %s' % (cmds[0],
     277                                                          os.strerror(self.ecode)))
    203278        finally:
    204279            self._unlock('_open')
    205         self.gdb_console('gdb: %s' % (' '.join(cmds)))
    206         ec, proc = self.process.open(cmds, timeout = (timeout, self._timeout))
    207         if self.trace:
    208             print('gdb done', ec)
    209         if ec > 0:
    210             raise error.general('gdb exec: %s: %s' % (cmds[0], os.strerror(ec)))
    211         self._lock('_open')
    212         try:
    213             self.process = None
    214         finally:
    215             self._unlock('_open')
    216280
    217281    def kill(self):
    218         self._lock('_open')
    219         try:
    220             if self.process:
    221                 self.process.kill()
    222             self.process = None
    223         finally:
    224             self._unlock('_open')
     282        self._lock('_kill')
     283        try:
     284            self._kill()
     285        finally:
     286            self._unlock('_kill')
    225287
    226288    def gdb_expect(self):
     
    283345                        lines = self.output_buffer[:last_lf]
    284346                        if self.trace:
    285                             print('/// console output')
     347                            print('/// console output: ', len(lines))
    286348                        for line in lines.splitlines():
     349                            self.output_length += len(line)
    287350                            self.output(line)
    288351                        self.output_buffer = self.output_buffer[last_lf + 1:]
  • tester/rt/report.py

    rb1c6a98 rcd8fa2f  
    6464        self.benchmark = 0
    6565        self.timeouts = 0
     66        self.test_too_long = 0
    6667        self.invalids = 0
    6768        self.wrong_version = 0
     
    8081        msg += 'Benchmark:     %*d%s' % (self.total_len, self.self.benchmark, os.linesep)
    8182        msg += 'Timeout:       %*d%s' % (self.total_len, self.timeouts, os.linesep)
     83        msg += 'Test too long: %*d%s' % (self.total_len, self.test_too_long, os.linesep)
    8284        msg += 'Invalid:       %*d%s' % (self.total_len, self.invalids, os.linesep)
    8385        msg += 'Wrong Version  %*d%s' % (self.total_len, self.wrong_version, os.linesep)
     
    8890    def start(self, index, total, name, executable, bsp_arch, bsp, show_header):
    8991        header = '[%*d/%*d] p:%-*d f:%-*d u:%-*d e:%-*d I:%-*d B:%-*d ' \
    90                  't:%-*d i:%-*d W:%-*d | %s/%s: %s' % \
     92                 't:%-*d L:%-*d i:%-*d W:%-*d | %s/%s: %s' % \
    9193                 (len(str(total)), index,
    9294                  len(str(total)), total,
     
    98100                  len(str(total)), self.benchmark,
    99101                  len(str(total)), self.timeouts,
     102                  len(str(total)), self.test_too_long,
    100103                  len(str(total)), self.invalids,
    101104                  len(str(total)), self.wrong_version + self.wrong_build + self.wrong_tools,
     
    124127        start = False
    125128        end = False
     129        fatal = False
    126130        state = None
    127131        version = None
     
    129133        tools = None
    130134        timeout = False
     135        test_too_long = False
    131136        prefixed_output = []
    132137        for line in output:
     
    138143                    elif line[1][4:].startswith('END OF '):
    139144                        end = True
     145                    elif line[1][4:].startswith('FATAL'):
     146                        fatal = True
    140147                    elif banner.startswith('TIMEOUT TIMEOUT'):
    141148                        timeout = True
     149                    elif banner.startswith('TEST TOO LONG'):
     150                        test_too_long = True
    142151                    elif banner.startswith('TEST VERSION:'):
    143152                        version = banner[13:].strip()
     
    185194                        status = 'passed'
    186195                        self.passed += 1
     196                elif fatal:
     197                    status = 'fatal error'
     198                    self.failed += 1
    187199                elif timeout:
    188200                    status = 'timeout'
    189201                    self.timeouts += 1
     202                elif test_too_long:
     203                    status = 'test-too-long'
     204                    self.test_too_long += 1
    190205                elif start:
    191206                    if not end:
     
    241256
    242257    def log(self, name, mode):
    243         status_fails = ['failed', 'timeout', 'invalid',
     258        status_fails = ['failed', 'timeout', 'test-too-long', 'invalid',
    244259                        'wrong-version', 'wrong-build', 'wrong-tools']
    245260        if mode != 'none':
     
    274289        if mode == 'short':
    275290            wrongs = self.wrong_version + self.wrong_build + self.wrong_tools
    276             return 'Passed:%d Failed:%d Timeout:%d Invalid:%d Wrong:%d' % \
    277                 (self.passed, self.failed, self.timeouts, self.invalids, wrongs)
     291            return 'Passed:%d Failed:%d Timeout:%d Test-Too-long:%d Invalid:%d Wrong:%d' % \
     292                (self.passed, self.failed, self.timeouts, self.test_too_long,
     293                 self.invalids, wrongs)
    278294        elif mode == 'full':
    279295            l = []
     
    285301            l += ['Benchmark:     %*d' % (self.total_len, self.benchmark)]
    286302            l += ['Timeout:       %*d' % (self.total_len, self.timeouts)]
     303            l += ['Test too long: %*d' % (self.total_len, self.test_too_long)]
    287304            l += ['Invalid:       %*d' % (self.total_len, self.invalids)]
    288305            l += ['Wrong Version: %*d' % (self.total_len, self.wrong_version)]
     
    320337            l += ['Timeouts:']
    321338            l += show_state(self.results, 'timeout', self.name_max_len)
     339        if self.test_too_long:
     340            l += ['Test too long:']
     341            l += show_state(self.results, 'test-too-long', self.name_max_len)
    322342        if self.invalids:
    323343            l += ['Invalid:']
  • tester/rt/test.py

    rb1c6a98 rcd8fa2f  
    236236    json_log['summary']['benchmark_count'] = reports.benchmark
    237237    json_log['summary']['timeout_count'] = reports.timeouts
     238    json_log['summary']['too_long_count'] = reports.too_long
    238239    json_log['summary']['invalid_count'] = reports.invalids
    239240    json_log['summary']['wrong-version_count'] = reports.wrong_version
     
    247248    result_types = [
    248249            'failed', 'user-input', 'expected-fail', 'indeterminate',
    249             'benchmark', 'timeout', 'invalid', 'wrong-version', 'wrong-build',
    250             'wrong-tools'
     250            'benchmark', 'timeout', 'too-long', 'invalid', 'wrong-version',
     251            'wrong-build', 'wrong-tools'
    251252    ]
    252253    json_results = {}
     
    305306    junit_prop['benchmark_count'] = reports.benchmark
    306307    junit_prop['timeout_count'] = reports.timeouts
     308    junit_prop['too_long_count'] = reports.too_long
    307309    junit_prop['invalid_count'] = reports.invalids
    308310    junit_prop['wrong-version_count'] = reports.wrong_version
  • tester/rt/tftp.py

    rb1c6a98 rcd8fa2f  
    6767        self.exe = None
    6868        self.timeout = None
     69        self.test_too_long = None
    6970        self.timer = None
    7071        self.running = False
     
    109110        if self.timeout is not None:
    110111            self.timeout()
     112
     113    def _test_too_long(self):
     114        self._stop()
     115        while self.running or not self.finished:
     116            self._unlock('_test_too_long')
     117            time.sleep(0.1)
     118            self._lock('_test_too_long')
     119        if self.test_too_long is not None:
     120            self.test_too_long()
    111121
    112122    def _exe_handle(self, req_file, raddress, rport):
     
    167177        if self.console:
    168178            self.console('tftp: exe: %s' % (executable))
    169         self.timeout = timeout[1]
     179        self.timeout = timeout[2]
     180        self.test_too_long = timeout[3]
    170181        self.listener = threading.Thread(target = self._runner,
    171182                                         name = 'tftp-listener')
    172183        self.listener.start()
    173         step = 0.5
     184        step = 0.25
    174185        period = timeout[0]
     186        seconds = timeout[1]
    175187        output_len = self.output_length()
    176         while not self.finished and period > 0:
     188        while not self.finished and period > 0 and seconds > 0:
     189            if not self.running and self.caught:
     190                break
    177191            current_length = self.output_length()
    178192            if output_length != current_length:
    179193                period = timeout[0]
    180194            output_length = current_length
     195            if seconds < step:
     196                seconds = 0
     197            else:
     198                seconds -= step
    181199            if period < step:
     200                step = period
    182201                period = 0
    183202            else:
     
    186205            time.sleep(step)
    187206            self._lock('_open')
    188         if not self.finished and period == 0:
    189             self._timeout()
     207        if not self.finished:
     208            if period == 0:
     209                self._timeout()
     210            elif seconds == 0:
     211                self._test_too_long()
    190212        caught = self.caught
    191         self.caught = None
    192213        self._init()
    193214        self._unlock('_open')
  • tester/rtems/testing/testing.mc

    rb1c6a98 rcd8fa2f  
    5252
    5353# Defaults
    54 timeout:              none,    none,     '180'
     54timeout:              none,    none,     '180'  # seconds
     55max_test_period:      none,    none,     '300'  # seconds
    5556
    5657# Tests detected as invalid that are valid
  • tester/wscript

    rb1c6a98 rcd8fa2f  
    6161                  'rt/console.py',
    6262                  'rt/coverage.py',
     63                  'rt/exe.py',
    6364                  'rt/gdb.py',
    6465                  'rt/options.py',
Note: See TracChangeset for help on using the changeset viewer.