Changeset 3a867a4 in rtems-tools


Ignore:
Timestamp:
Sep 21, 2017, 8:26:20 AM (20 months ago)
Author:
Chris Johns <chrisj@…>
Branches:
master
Children:
3ed65c0
Parents:
fa81491
Message:

Add TFTP as a back end option for testing. Add telnet as a console option.

TFTP runs a local TFTP server on port 69 or another specified port and
serves each test for any requested file.

Telnet is now a console option.

Location:
tester
Files:
14 added
5 edited

Legend:

Unmodified
Added
Removed
  • tester/rt/config.py

    rfa81491 r3a867a4  
    11#
    22# RTEMS Tools Project (http://www.rtems.org/)
    3 # Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
     3# Copyright 2013-2017 Chris Johns (chrisj@rtems.org)
    44# All rights reserved.
    55#
     
    4747from . import console
    4848from . import gdb
     49from . import tftp
    4950
    5051timeout = 15
     
    5556    _directives = ['%execute',
    5657                   '%gdb',
     58                   '%tftp',
    5759                   '%console']
    5860
    59     def __init__(self, report, name, opts, _directives = _directives):
     61    def __init__(self, index, report, name, opts, _directives = _directives):
    6062        super(file, self).__init__(name, opts, directives = _directives)
    6163        self.lock = threading.Lock()
     
    6466        self.console = None
    6567        self.output = None
     68        self.index = index
    6669        self.report = report
    6770        self.name = name
    6871        self.timedout = False
     72        self.test_started = False
    6973        self.kill_good = False
     74        self.kill_on_end = False
     75        self.test_label = None
    7076
    7177    def __del__(self):
     
    9298        except:
    9399            pass
     100
     101    def _target_reset(self):
     102        if self.defined('target_reset_command'):
     103            reset_cmd = self.expand('%{target_reset_command}').strip()
     104            if len(reset_cmd) > 0:
     105                rs_proc = execute.capture_execution()
     106                ec, proc, output = rs_proc.open(reset_cmd, shell = True)
     107                self._capture_console('target reset: %s: %s' % (reset_cmd, output))
     108
     109    def _output_length(self):
     110        self._lock()
     111        if self.test_started:
     112            l = len(self.output)
     113            self._unlock()
     114            return l
     115        self._unlock()
     116        return 0
     117
     118    def _capture_console(self, text):
     119        text = [('>', l) for l in text.replace(chr(13), '').splitlines()]
     120        if self.output is not None:
     121            self._realtime_trace(text)
     122            self.output += text
    94123
    95124    def _dir_console(self, data):
     
    153182                self.console.close()
    154183
     184    def _dir_tftp(self, data, total, index, exe, bsp_arch, bsp):
     185        if len(data) != 2:
     186            raise error.general('invalid %tftp arguments')
     187        try:
     188            port = int(data[1])
     189        except:
     190            raise error.general('invalid %tftp port')
     191        self.kill_on_end = True
     192        self.process = tftp.tftp(bsp_arch, bsp,
     193                                 trace = self.debug_trace('gdb'))
     194        if not self.in_error:
     195            if self.console:
     196                self.console.open()
     197            self.process.open(executable = data[0],
     198                              port = port,
     199                              output_length = self._output_length,
     200                              console = self.capture_console,
     201                              timeout = (int(self.expand('%{timeout}')),
     202                                         self._timeout))
     203            if self.console:
     204                self.console.close()
     205
    155206    def _directive_filter(self, results, directive, info, data):
    156207        if results[0] == 'directive':
     
    169220                self._lock()
    170221                try:
     222                    self.output = []
    171223                    total = int(self.expand('%{test_total}'))
    172224                    index = int(self.expand('%{test_index}'))
     
    175227                    bsp = self.expand('%{bsp}')
    176228                    self.report.start(index, total, exe, exe, bsp_arch, bsp)
    177                     self.output = []
     229                    if self.index == 1:
     230                        self._target_reset()
    178231                finally:
    179232                    self._unlock()
     
    182235                elif _directive == '%gdb':
    183236                    self._dir_gdb(ds, total, index, exe, bsp_arch, bsp)
     237                elif _directive == '%tftp':
     238                    self._dir_tftp(ds, total, index, exe, bsp_arch, bsp)
    184239                else:
    185240                    raise error.general(self._name_line_msg('invalid directive'))
    186241                self._lock()
    187242                try:
    188                     self.report.end(exe, self.output)
     243                    status = self.report.end(exe, self.output)
     244                    if status == 'timeout':
     245                        self._target_reset()
    189246                    self.process = None
    190247                    self.output = None
     
    202259
    203260    def capture(self, text):
    204         ok_to_kill = '*** TEST STATE: USER_INPUT' in text or '*** TEST STATE: BENCHMARK' in text
     261        if not self.test_started:
     262            self.test_started = '*** BEGIN OF TEST ' in text
     263        ok_to_kill = '*** TEST STATE: USER_INPUT' in text or \
     264                     '*** TEST STATE: BENCHMARK' in text
     265        reset_target = False
     266        if ok_to_kill:
     267            reset_target = True
     268        if self.kill_on_end:
     269            if self.test_label is None:
     270                s = text.find('*** BEGIN OF TEST ')
     271                if s >= 0:
     272                    e = text[s + 3:].find('***')
     273                    if e >= 0:
     274                        self.test_label = text[s + len('*** BEGIN OF TEST '):s + e + 3 - 1]
     275            if not ok_to_kill and self.test_label is not None:
     276                ok_to_kill = '*** END OF TEST %s ***' % (self.test_label) in text
    205277        text = [(']', l) for l in text.replace(chr(13), '').splitlines()]
    206278        self._lock()
     
    208280            self._realtime_trace(text)
    209281            self.output += text
     282        if reset_target:
     283            self._target_reset()
    210284        if ok_to_kill:
    211285            self._ok_kill()
     
    213287
    214288    def capture_console(self, text):
    215         text = [('>', l) for l in text.replace(chr(13), '').splitlines()]
    216289        self._lock()
    217         if self.output is not None:
    218             self._realtime_trace(text)
    219             self.output += text
     290        self._capture_console(text)
    220291        self._unlock()
    221292
  • tester/rt/console.py

    rfa81491 r3a867a4  
    4040import time
    4141
     42from rtemstoolkit import path
     43
     44from . import telnet
     45
    4246#
    4347# Not available on Windows. Not sure what this means.
    4448#
    4549if os.name != 'nt':
    46     import fcntl
    4750    from . import stty
    4851else:
    49     fcntl = None
    5052    stty = None
    5153
     
    8587
    8688class tty(console):
    87     '''TTY console connects to serial ports.'''
    88 
    89     raw = 'B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS'
     89    '''TTY console connects to the target's console.'''
    9090
    9191    def __init__(self, dev, output, setup = None, trace = False):
     
    9494        self.dev = dev
    9595        self.output = output
    96         if setup is None:
    97             self.setup = raw
    98         else:
    99             self.setup = setup
     96        self.setup = setup
    10097        super(tty, self).__init__(dev, trace)
    10198
    10299    def __del__(self):
    103100        super(tty, self).__del__()
    104         if self._tracing():
    105             print(':: tty close', self.dev)
    106         if fcntl is not None:
    107             fcntl.fcntl(me.tty.fd, fcntl.F_SETFL,
    108                         fcntl.fcntl(me.tty.fd, fcntl.F_GETFL) & ~os.O_NONBLOCK)
    109101        self.close()
    110102
    111103    def open(self):
    112104        def _readthread(me, x):
    113             if self._tracing():
    114                 print(':: tty runner started', self.dev)
    115             if fcntl is not None:
    116                 fcntl.fcntl(me.tty.fd, fcntl.F_SETFL,
    117                             fcntl.fcntl(me.tty.fd, fcntl.F_GETFL) | os.O_NONBLOCK)
    118105            line = ''
    119106            while me.running:
    120107                time.sleep(0.05)
    121108                try:
    122                     data = me.tty.fd.read()
     109                    data = me.tty.read()
    123110                except IOError as ioe:
    124111                    if ioe.errno == errno.EAGAIN:
     
    135122                        me.output(line)
    136123                        line = ''
    137             if self._tracing():
    138                 print(':: tty runner finished', self.dev)
    139         if self._tracing():
    140             print(':: tty open', self.dev)
    141         self.tty = stty.tty(self.dev)
     124        if stty and path.exists(self.dev):
     125            self.tty = stty.tty(self.dev)
     126        else:
     127            self.tty = telnet.tty(self.dev)
    142128        self.tty.set(self.setup)
    143129        self.tty.on()
  • tester/rt/report.py

    rfa81491 r3a867a4  
    4040from rtemstoolkit import log
    4141from rtemstoolkit import path
     42
     43#
     44# Maybe this should be a configuration.
     45#
     46test_fail_excludes = [
     47    'minimum'
     48]
    4249
    4350class report(object):
     
    111118            if line[0] == ']':
    112119                if line[1].startswith('*** '):
     120                    if line[1][4:].startswith('BEGIN OF '):
     121                        start = True
    113122                    if line[1][4:].startswith('END OF '):
    114123                        end = True
     
    117126                    if line[1][4:].startswith('TIMEOUT TIMEOUT'):
    118127                        timeout = True
    119                     else:
    120                         start = True
    121128            prefixed_output += [line[0] + ' ' + line[1]]
    122129        self.lock.acquire()
     
    141148                    self.failed += 1
    142149            else:
    143                 status = 'invalid'
    144                 self.invalids += 1
     150                exe_name = name.split('.')[0]
     151                if exe_name in test_fail_excludes:
     152                    status = 'passed'
     153                    self.passed += 1
     154                else:
     155                    status = 'invalid'
     156                    self.invalids += 1
    145157        else:
    146158            if state == 'EXPECTED_FAIL':
     
    171183            self.name_max_len = len(path.basename(name))
    172184        self.lock.release()
     185        return status
    173186
    174187    def log(self, name, mode):
  • tester/rt/stty.py

    rfa81491 r3a867a4  
    3333#
    3434
     35import fcntl
    3536import os
    3637import sys
     
    5960
    6061class tty:
     62
     63    raw = 'B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS'
    6164
    6265    def __init__(self, dev):
     
    8083            self.default_attr = termios.tcgetattr(self.fd)
    8184        except:
     85            close(self.fd)
    8286            raise error.general('cannot get termios attrs: %s' % (dev))
     87        try:
     88            fcntl.fcntl(self.fd, fcntl.F_SETFL,
     89                        fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK)
     90        except:
     91            close(self.fd)
     92            raise error.general('cannot make tty non-blocking: %s' % (dev))
    8393        self.attr = self.default_attr
    8494
     
    8696        if self.fd and self.default_attr:
    8797            try:
     98                fcntl.fcntl(self.fd, fcntl.F_SETFL,
     99                            fcntl.fcntl(self.fd, fcntl.F_GETFL) & ~os.O_NONBLOCK)
    88100                self.fd.close()
    89101            except:
     
    488500        self.attr[6][termios.VTIME] = _vtime
    489501
    490     def set(self, flags):
     502    def set(self, flags = None):
     503        if flags is None:
     504            flags = self.raw
    491505        for f in flags.split(','):
    492506            if len(f) < 2:
     
    543557            raise error.general('unknown tty flag: %s' % (f))
    544558        self._update()
     559
     560    def read(self):
     561        return self.fs.read()
    545562
    546563if __name__ == "__main__":
  • tester/rt/test.py

    rfa81491 r3a867a4  
    4242from rtemstoolkit import log
    4343from rtemstoolkit import path
     44from rtemstoolkit import reraise
    4445from rtemstoolkit import stacktraces
    4546from rtemstoolkit import version
     
    5051from . import options
    5152from . import report
    52 
    53 #
    54 # The following fragment is taken from https://bitbucket.org/gutworth/six
    55 # to raise an exception. The python2 code cause a syntax error with python3.
    56 #
    57 # Copyright (c) 2010-2016 Benjamin Peterson
    58 #
    59 # Permission is hereby granted, free of charge, to any person obtaining a copy
    60 # of this software and associated documentation files (the "Software"), to deal
    61 # in the Software without restriction, including without limitation the rights
    62 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    63 # copies of the Software, and to permit persons to whom the Software is
    64 # furnished to do so, subject to the following conditions:
    65 #
    66 # The above copyright notice and this permission notice shall be included in all
    67 # copies or substantial portions of the Software.
    68 #
    69 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    70 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    71 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    72 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    73 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    74 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    75 # SOFTWARE.
    76 #
    77 # Taken from six.
    78 #
    79 if sys.version_info[0] == 3:
    80     def _test_reraise(tp, value, tb = None):
    81         raise value.with_traceback(tb)
    82 else:
    83     def exec_(_code_, _globs_ = None, _locs_ = None):
    84         if _globs_ is None:
    85             frame = sys._getframe(1)
    86             _globs_ = frame.f_globals
    87             if _locs_ is None:
    88                 _locs_ = frame.f_locals
    89             del frame
    90         elif _locs_ is None:
    91             _locs_ = _globs_
    92         exec("""exec _code_ in _globs_, _locs_""")
    93 
    94     exec_("""def _test_reraise(tp, value, tb = None):
    95     raise tp, value, tb
    96 """)
    9753
    9854class test(object):
     
    11773                raise error.general('cannot find RTEMS tools path: %s' % (rtems_tools_bin))
    11874            self.opts.defaults['rtems_tools'] = rtems_tools_bin
    119         self.config = config.file(self.report, self.bsp_config, self.opts)
     75        self.config = config.file(index, self.report, self.bsp_config, self.opts)
    12076
    12177    def run(self):
     
    166122    def reraise(self):
    167123        if self.result is not None:
    168             _test_reraise(*self.result)
     124            reraise.reraise(*self.result)
    169125
    170126    def kill(self):
Note: See TracChangeset for help on using the changeset viewer.