mirror of
https://git.rtems.org/rtems-tools/
synced 2025-10-18 10:44:32 +08:00
tester: Correctly handle contro-c.
Add support to kill running tests if the user presses control-c.
This commit is contained in:
@@ -116,6 +116,7 @@ class execute(object):
|
|||||||
self.environment = None
|
self.environment = None
|
||||||
self.outputting = False
|
self.outputting = False
|
||||||
self.timing_out = False
|
self.timing_out = False
|
||||||
|
self.proc = None
|
||||||
|
|
||||||
def _capture(self, command, proc, timeout = None):
|
def _capture(self, command, proc, timeout = None):
|
||||||
"""Create 3 threads to read stdout and stderr and send to the output handler
|
"""Create 3 threads to read stdout and stderr and send to the output handler
|
||||||
@@ -262,12 +263,25 @@ class execute(object):
|
|||||||
timeout_thread.daemon = True
|
timeout_thread.daemon = True
|
||||||
timeout_thread.start()
|
timeout_thread.start()
|
||||||
try:
|
try:
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
|
self.proc = proc
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
exitcode = proc.wait()
|
exitcode = proc.wait()
|
||||||
except:
|
except:
|
||||||
print 'killing'
|
|
||||||
proc.kill()
|
proc.kill()
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
|
self.proc = None
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
if self.cleanup:
|
if self.cleanup:
|
||||||
self.cleanup(proc)
|
self.cleanup(proc)
|
||||||
if timeout_thread:
|
if timeout_thread:
|
||||||
@@ -415,6 +429,37 @@ class execute(object):
|
|||||||
self.environment = environment
|
self.environment = environment
|
||||||
return old_environment
|
return old_environment
|
||||||
|
|
||||||
|
def kill(self):
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
|
if self.proc is not None:
|
||||||
|
self.proc.kill()
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
|
def terminate(self):
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
|
if self.proc is not None:
|
||||||
|
self.proc.terminate()
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
|
def send_signal(self, signal):
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
|
if self.proc is not None:
|
||||||
|
print "sending sig"
|
||||||
|
self.proc.send_signal(signal)
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
class capture_execution(execute):
|
class capture_execution(execute):
|
||||||
"""Capture all output as a string and return it."""
|
"""Capture all output as a string and return it."""
|
||||||
|
|
||||||
|
43
rtemstoolkit/stacktraces.py
Normal file
43
rtemstoolkit/stacktraces.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# RTEMS Tools Project (http://www.rtems.org/)
|
||||||
|
# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
def trace():
|
||||||
|
code = []
|
||||||
|
for threadId, stack in sys._current_frames().items():
|
||||||
|
code.append("\n# thread-id: %s" % threadId)
|
||||||
|
for filename, lineno, name, line in traceback.extract_stack(stack):
|
||||||
|
code.append('file: "%s", line %d, in %s' % (filename, lineno, name))
|
||||||
|
if line:
|
||||||
|
code.append(" %s" % (line.strip()))
|
||||||
|
return '\n'.join(code)
|
||||||
|
|
41
tester/rt/bsps.py
Normal file
41
tester/rt/bsps.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# RTEMS Tools Project (http://www.rtems.org/)
|
||||||
|
# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
from rtemstoolkit import error
|
||||||
|
from rtemstoolkit import log
|
||||||
|
from rtemstoolkit import path
|
||||||
|
|
||||||
|
def list(opts):
|
||||||
|
path_ = opts.defaults.expand('%%{_configdir}/bsps/*.mc')
|
||||||
|
bsps = path.collect_files(path_)
|
||||||
|
log.notice(' BSP List:')
|
||||||
|
for bsp in bsps:
|
||||||
|
log.notice(' %s' % (path.basename(bsp[:-3])))
|
||||||
|
raise error.exit()
|
@@ -62,7 +62,7 @@ class file(config.file):
|
|||||||
self.console = None
|
self.console = None
|
||||||
self.output = None
|
self.output = None
|
||||||
self.report = report
|
self.report = report
|
||||||
self.load(name)
|
self.name = name
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if self.console:
|
if self.console:
|
||||||
@@ -181,6 +181,9 @@ class file(config.file):
|
|||||||
for l in text:
|
for l in text:
|
||||||
print ' '.join(l)
|
print ' '.join(l)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.load(self.name)
|
||||||
|
|
||||||
def capture(self, text):
|
def capture(self, text):
|
||||||
text = [(']', l) for l in text.replace(chr(13), '').splitlines()]
|
text = [(']', l) for l in text.replace(chr(13), '').splitlines()]
|
||||||
self._lock()
|
self._lock()
|
||||||
@@ -203,3 +206,7 @@ class file(config.file):
|
|||||||
if flag in dt.split(','):
|
if flag in dt.split(','):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def kill(self):
|
||||||
|
if self.process:
|
||||||
|
self.process.kill()
|
||||||
|
@@ -38,7 +38,9 @@ import time
|
|||||||
from rtemstoolkit import error
|
from rtemstoolkit import error
|
||||||
from rtemstoolkit import log
|
from rtemstoolkit import log
|
||||||
from rtemstoolkit import path
|
from rtemstoolkit import path
|
||||||
|
from rtemstoolkit import stacktraces
|
||||||
|
|
||||||
|
import bsps
|
||||||
import config
|
import config
|
||||||
import console
|
import console
|
||||||
import options
|
import options
|
||||||
@@ -46,17 +48,6 @@ import report
|
|||||||
import version
|
import version
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
|
||||||
def stacktraces():
|
|
||||||
import traceback
|
|
||||||
code = []
|
|
||||||
for threadId, stack in sys._current_frames().items():
|
|
||||||
code.append("\n# thread-id: %s" % threadId)
|
|
||||||
for filename, lineno, name, line in traceback.extract_stack(stack):
|
|
||||||
code.append('file: "%s", line %d, in %s' % (filename, lineno, name))
|
|
||||||
if line:
|
|
||||||
code.append(" %s" % (line.strip()))
|
|
||||||
return '\n'.join(code)
|
|
||||||
|
|
||||||
class test(object):
|
class test(object):
|
||||||
def __init__(self, index, total, report, executable, rtems_tools, bsp, bsp_config, opts):
|
def __init__(self, index, total, report, executable, rtems_tools, bsp, bsp_config, opts):
|
||||||
self.index = index
|
self.index = index
|
||||||
@@ -78,7 +69,15 @@ class test(object):
|
|||||||
if not path.isdir(rtems_tools_bin):
|
if not path.isdir(rtems_tools_bin):
|
||||||
raise error.general('cannot find RTEMS tools path: %s' % (rtems_tools_bin))
|
raise error.general('cannot find RTEMS tools path: %s' % (rtems_tools_bin))
|
||||||
self.opts.defaults['rtems_tools'] = rtems_tools_bin
|
self.opts.defaults['rtems_tools'] = rtems_tools_bin
|
||||||
self.config = config.file(report, bsp_config, self.opts)
|
self.config = config.file(self.report, self.bsp_config, self.opts)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if self.config:
|
||||||
|
self.config.run()
|
||||||
|
|
||||||
|
def kill(self):
|
||||||
|
if self.config:
|
||||||
|
self.config.kill()
|
||||||
|
|
||||||
class test_run(object):
|
class test_run(object):
|
||||||
def __init__(self, index, total, report, executable, rtems_tools, bsp, bsp_config, opts):
|
def __init__(self, index, total, report, executable, rtems_tools, bsp, bsp_config, opts):
|
||||||
@@ -102,6 +101,7 @@ class test_run(object):
|
|||||||
self.executable, self.rtems_tools,
|
self.executable, self.rtems_tools,
|
||||||
self.bsp, self.bsp_config,
|
self.bsp, self.bsp_config,
|
||||||
self.opts)
|
self.opts)
|
||||||
|
self.test.run()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
@@ -120,6 +120,10 @@ class test_run(object):
|
|||||||
if self.result is not None:
|
if self.result is not None:
|
||||||
raise self.result[0], self.result[1], self.result[2]
|
raise self.result[0], self.result[1], self.result[2]
|
||||||
|
|
||||||
|
def kill(self):
|
||||||
|
if self.test:
|
||||||
|
self.test.kill()
|
||||||
|
|
||||||
def find_executables(paths, glob):
|
def find_executables(paths, glob):
|
||||||
executables = []
|
executables = []
|
||||||
for p in paths:
|
for p in paths:
|
||||||
@@ -175,8 +179,13 @@ def list_bsps(opts):
|
|||||||
log.notice(' %s' % (path.basename(bsp[:-3])))
|
log.notice(' %s' % (path.basename(bsp[:-3])))
|
||||||
raise error.exit()
|
raise error.exit()
|
||||||
|
|
||||||
|
def killall(tests):
|
||||||
|
for test in tests:
|
||||||
|
test.kill()
|
||||||
|
|
||||||
def run(command_path = None):
|
def run(command_path = None):
|
||||||
import sys
|
import sys
|
||||||
|
tests = []
|
||||||
stdtty = console.save()
|
stdtty = console.save()
|
||||||
opts = None
|
opts = None
|
||||||
default_exefilter = '*.exe'
|
default_exefilter = '*.exe'
|
||||||
@@ -194,7 +203,7 @@ def run(command_path = None):
|
|||||||
command_path = command_path)
|
command_path = command_path)
|
||||||
log.notice('RTEMS Testing - Tester, v%s' % (version.str()))
|
log.notice('RTEMS Testing - Tester, v%s' % (version.str()))
|
||||||
if opts.find_arg('--list-bsps'):
|
if opts.find_arg('--list-bsps'):
|
||||||
list_bsps(opts)
|
bsps.list(opts)
|
||||||
exe_filter = opts.find_arg('--filter')
|
exe_filter = opts.find_arg('--filter')
|
||||||
if exe_filter:
|
if exe_filter:
|
||||||
exe_filter = exe_filter[1]
|
exe_filter = exe_filter[1]
|
||||||
@@ -246,7 +255,6 @@ def run(command_path = None):
|
|||||||
reporting = 1
|
reporting = 1
|
||||||
jobs = int(opts.jobs(opts.defaults['_ncpus']))
|
jobs = int(opts.jobs(opts.defaults['_ncpus']))
|
||||||
exe = 0
|
exe = 0
|
||||||
tests = []
|
|
||||||
finished = []
|
finished = []
|
||||||
if jobs > len(executables):
|
if jobs > len(executables):
|
||||||
jobs = len(executables)
|
jobs = len(executables)
|
||||||
@@ -288,7 +296,8 @@ def run(command_path = None):
|
|||||||
report_finished(reports, report_mode, -1, finished, job_trace)
|
report_finished(reports, report_mode, -1, finished, job_trace)
|
||||||
reports.summary()
|
reports.summary()
|
||||||
end_time = datetime.datetime.now()
|
end_time = datetime.datetime.now()
|
||||||
log.notice('Testing time: %s' % (str(end_time - start_time)))
|
log.notice('Average test time: %s' % (str((end_time - start_time) / total)))
|
||||||
|
log.notice('Testing time : %s' % (str(end_time - start_time)))
|
||||||
except error.general, gerr:
|
except error.general, gerr:
|
||||||
print gerr
|
print gerr
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -302,8 +311,9 @@ def run(command_path = None):
|
|||||||
print '}} dumping:', threading.active_count()
|
print '}} dumping:', threading.active_count()
|
||||||
for t in threading.enumerate():
|
for t in threading.enumerate():
|
||||||
print '}} ', t.name
|
print '}} ', t.name
|
||||||
print stacktraces()
|
print stacktraces.trace()
|
||||||
log.notice('abort: user terminated')
|
log.notice('abort: user terminated')
|
||||||
|
killall(tests)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
finally:
|
finally:
|
||||||
console.restore(stdtty)
|
console.restore(stdtty)
|
||||||
|
Reference in New Issue
Block a user