Commit 2b1c04d9 authored by Stefan Behnel's avatar Stefan Behnel

test runner: safer shutdown even if threads were kept alive by failing tests

parent 2e333d31
...@@ -10,6 +10,7 @@ import unittest ...@@ -10,6 +10,7 @@ import unittest
import doctest import doctest
import operator import operator
import tempfile import tempfile
import traceback
try: try:
from StringIO import StringIO from StringIO import StringIO
except ImportError: except ImportError:
...@@ -484,7 +485,6 @@ class CythonRunTestCase(CythonCompileTestCase): ...@@ -484,7 +485,6 @@ class CythonRunTestCase(CythonCompileTestCase):
output = open(result_file, 'wb') output = open(result_file, 'wb')
pickle.dump(partial_result.data(), output) pickle.dump(partial_result.data(), output)
except: except:
import traceback
traceback.print_exc() traceback.print_exc()
finally: finally:
try: output.close() try: output.close()
...@@ -848,7 +848,12 @@ def refactor_for_py3(distdir, cy3_dir): ...@@ -848,7 +848,12 @@ def refactor_for_py3(distdir, cy3_dir):
''') ''')
sys.path.insert(0, cy3_dir) sys.path.insert(0, cy3_dir)
def check_thread_termination(): class PendingThreadsError(RuntimeError):
pass
threads_seen = []
def check_thread_termination(ignore_seen=True):
if threading is None: # no threading enabled in CPython if threading is None: # no threading enabled in CPython
return return
current = threading.currentThread() current = threading.currentThread()
...@@ -858,15 +863,20 @@ def check_thread_termination(): ...@@ -858,15 +863,20 @@ def check_thread_termination():
continue continue
t.join(timeout=2) t.join(timeout=2)
if t.isAlive(): if t.isAlive():
blocking_threads.append(t) for seen in threads_seen:
if t is seen:
break
else:
threads_seen.append(t)
blocking_threads.append(t)
if not blocking_threads: if not blocking_threads:
return return
sys.stderr.write("warning: left-over threads found after running test:\n") sys.stderr.write("warning: left-over threads found after running test:\n")
for t in blocking_threads: for t in blocking_threads:
sys.stderr.write('...%s\n' % repr(t)) sys.stderr.write('...%s\n' % repr(t))
raise RuntimeError("left-over threads found after running test") raise PendingThreadsError("left-over threads found after running test")
if __name__ == '__main__': def main():
from optparse import OptionParser from optparse import OptionParser
parser = OptionParser() parser = OptionParser()
parser.add_option("--no-cleanup", dest="cleanup_workdir", parser.add_option("--no-cleanup", dest="cleanup_workdir",
...@@ -978,6 +988,7 @@ if __name__ == '__main__': ...@@ -978,6 +988,7 @@ if __name__ == '__main__':
coverage.start() coverage.start()
if WITH_CYTHON: if WITH_CYTHON:
global CompilationOptions, pyrex_default_options, cython_compile
from Cython.Compiler.Main import \ from Cython.Compiler.Main import \
CompilationOptions, \ CompilationOptions, \
default_options as pyrex_default_options, \ default_options as pyrex_default_options, \
...@@ -1121,6 +1132,24 @@ if __name__ == '__main__': ...@@ -1121,6 +1132,24 @@ if __name__ == '__main__':
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog])) sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
if options.exit_ok: if options.exit_ok:
sys.exit(0) return_code = 0
else: else:
sys.exit(not result.wasSuccessful()) return_code = not result.wasSuccessful()
try:
check_thread_termination(ignore_seen=False)
sys.exit(return_code)
except PendingThreadsError:
# normal program exit won't kill the threads, do it the hard way here
os._exit(return_code)
if __name__ == '__main__':
try:
main()
except Exception:
traceback.print_exc()
try:
check_thread_termination(ignore_seen=False)
except PendingThreadsError:
# normal program exit won't kill the threads, do it the hard way here
os._exit(1)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment