source: rtems-tools/tester/rt/config.py @ 15a3e06

5
Last change on this file since 15a3e06 was 15a3e06, checked in by Chris Johns <chrisj@…>, on 04/04/17 at 03:32:03

tester: Add support for expected-fail, user-input, and benchmarks.

Count the errors for the states listed and add running totals.

Kill the test process if the test state is user-input or benchmark.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# RTEMS Testing Config
33#
34
35from __future__ import print_function
36
37import datetime
38import os
39import threading
40
41from rtemstoolkit import config
42from rtemstoolkit import error
43from rtemstoolkit import execute
44from rtemstoolkit import log
45from rtemstoolkit import path
46
47from . import console
48from . import gdb
49
50timeout = 15
51
52class file(config.file):
53    """RTEMS Testing configuration."""
54
55    _directives = ['%execute',
56                   '%gdb',
57                   '%console']
58
59    def __init__(self, report, name, opts, _directives = _directives):
60        super(file, self).__init__(name, opts, directives = _directives)
61        self.lock = threading.Lock()
62        self.realtime_trace = self.debug_trace('output')
63        self.process = None
64        self.console = None
65        self.output = None
66        self.report = report
67        self.name = name
68        self.timedout = False
69        self.kill_good = False
70
71    def __del__(self):
72        if self.console:
73            del self.console
74        super(file, self).__del__()
75
76    def _lock(self):
77        self.lock.acquire()
78
79    def _unlock(self):
80        self.lock.release()
81
82    def _timeout(self):
83        self._lock()
84        self.timedout = True
85        self._unlock()
86        self.capture('*** TIMEOUT TIMEOUT')
87
88    def _ok_kill(self):
89        self.kill_good = True
90        try:
91            self.process.kill()
92        except:
93            pass
94
95    def _dir_console(self, data):
96        if self.console is not None:
97            raise error.general(self._name_line_msg('console already configured'))
98        if len(data) == 0:
99            raise error.general(self._name_line_msg('no console configuration provided'))
100        console_trace = trace = self.debug_trace('console')
101        if data[0] == 'stdio':
102            self.console = console.stdio(trace = console_trace)
103        elif data[0] == 'tty':
104            if len(data) < 2 or len(data) >3:
105                raise error.general(self._name_line_msg('no tty configuration provided'))
106            if len(data) == 3:
107                settings = data[2]
108            else:
109                settings = None
110            self.console = console.tty(data[1],
111                                       output = self.capture,
112                                       setup = settings,
113                                       trace = console_trace)
114        else:
115            raise error.general(self._name_line_msg('invalid console type'))
116
117    def _dir_execute(self, data, total, index, exe, bsp_arch, bsp):
118        self.process = execute.execute(output = self.capture)
119        if not self.in_error:
120            if self.console:
121                self.console.open()
122            self.capture_console('run: %s' % (' '.join(data)))
123            ec, proc = self.process.open(data,
124                                         timeout = (int(self.expand('%{timeout}')),
125                                                    self._timeout))
126            self._lock()
127            if not self.kill_good and ec > 0:
128                self._error('execute failed: %s: exit-code:%d' % (' '.join(data), ec))
129            elif self.timedout:
130                self.process.kill()
131            self._unlock()
132            if self.console:
133                self.console.close()
134
135    def _dir_gdb(self, data, total, index, exe, bsp_arch, bsp):
136        if len(data) < 3 or len(data) > 4:
137            raise error.general('invalid %gdb arguments')
138        self.process = gdb.gdb(bsp_arch, bsp,
139                               trace = self.debug_trace('gdb'),
140                               mi_trace = self.debug_trace('gdb-mi'))
141        script = self.expand('%%{%s}' % data[2])
142        if script:
143            script = [l.strip() for l in script.splitlines()]
144        if not self.in_error:
145            if self.console:
146                self.console.open()
147            self.process.open(data[0], data[1],
148                              script = script,
149                              output = self.capture,
150                              gdb_console = self.capture_console,
151                              timeout = int(self.expand('%{timeout}')))
152            if self.console:
153                self.console.close()
154
155    def _directive_filter(self, results, directive, info, data):
156        if results[0] == 'directive':
157            _directive = results[1]
158            _data = results[2]
159            ds = []
160            if len(_data):
161                ds = [_data[0]]
162                if len(_data) > 1:
163                    ds += _data[1].split()
164            ds = self.expand(ds)
165
166            if _directive == '%console':
167                self._dir_console(ds)
168            else:
169                self._lock()
170                try:
171                    total = int(self.expand('%{test_total}'))
172                    index = int(self.expand('%{test_index}'))
173                    exe = self.expand('%{test_executable}')
174                    bsp_arch = self.expand('%{bsp_arch}')
175                    bsp = self.expand('%{bsp}')
176                    self.report.start(index, total, exe, exe, bsp_arch, bsp)
177                    self.output = []
178                finally:
179                    self._unlock()
180                if _directive == '%execute':
181                    self._dir_execute(ds, total, index, exe, bsp_arch, bsp)
182                elif _directive == '%gdb':
183                    self._dir_gdb(ds, total, index, exe, bsp_arch, bsp)
184                else:
185                    raise error.general(self._name_line_msg('invalid directive'))
186                self._lock()
187                try:
188                    self.report.end(exe, self.output)
189                    self.process = None
190                    self.output = None
191                finally:
192                    self._unlock()
193        return None, None, None
194
195    def _realtime_trace(self, text):
196        if self.realtime_trace:
197            for l in text:
198                print(' '.join(l))
199
200    def run(self):
201        self.load(self.name)
202
203    def capture(self, text):
204        ok_to_kill = '*** TEST STATE: USER_INPUT' in text or '*** TEST STATE: BENCHMARK' in text
205        text = [(']', l) for l in text.replace(chr(13), '').splitlines()]
206        self._lock()
207        if self.output is not None:
208            self._realtime_trace(text)
209            self.output += text
210        if ok_to_kill:
211            self._ok_kill()
212        self._unlock()
213
214    def capture_console(self, text):
215        text = [('>', l) for l in text.replace(chr(13), '').splitlines()]
216        self._lock()
217        if self.output is not None:
218            self._realtime_trace(text)
219            self.output += text
220        self._unlock()
221
222    def debug_trace(self, flag):
223        dt = self.macros['debug_trace']
224        if dt:
225            if flag in dt.split(','):
226                return True
227        return False
228
229    def kill(self):
230        if self.process:
231            try:
232                self.process.kill()
233            except:
234                pass
Note: See TracBrowser for help on using the repository browser.