blob: f57784de657c42c521bdb8817aacbde104983d34 [file] [log] [blame]
Victor Stinner3844fe52015-09-26 10:38:01 +02001import faulthandler
2import importlib
3import io
Victor Stinner3844fe52015-09-26 10:38:01 +02004import os
5import sys
6import time
7import traceback
8import unittest
9from test import support
10from test.libregrtest.refleak import dash_R
11from test.libregrtest.save_env import saved_test_environment
12
13
14# Test result constants.
15PASSED = 1
16FAILED = 0
17ENV_CHANGED = -1
18SKIPPED = -2
19RESOURCE_DENIED = -3
20INTERRUPTED = -4
21CHILD_ERROR = -5 # error in a child process
22
23
Victor Stinner3844fe52015-09-26 10:38:01 +020024# small set of tests to determine if we have a basically functioning interpreter
25# (i.e. if any of these fail, then anything else is likely to follow)
26STDTESTS = [
27 'test_grammar',
28 'test_opcodes',
29 'test_dict',
30 'test_builtin',
31 'test_exceptions',
32 'test_types',
33 'test_unittest',
34 'test_doctest',
35 'test_doctest2',
36 'test_support'
37]
38
39# set of tests that we don't want to be executed when using regrtest
40NOTTESTS = set()
41
42
43def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
44 """Return a list of all applicable test modules."""
45 testdir = findtestdir(testdir)
46 names = os.listdir(testdir)
47 tests = []
48 others = set(stdtests) | nottests
49 for name in names:
50 mod, ext = os.path.splitext(name)
51 if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
52 tests.append(mod)
53 return stdtests + sorted(tests)
54
55
56def runtest(test, verbose, quiet,
57 huntrleaks=False, use_resources=None,
58 output_on_failure=False, failfast=False, match_tests=None,
59 timeout=None):
60 """Run a single test.
61
62 test -- the name of the test
63 verbose -- if true, print more messages
64 quiet -- if true, don't print 'skipped' messages (probably redundant)
65 huntrleaks -- run multiple times to test for leaks; requires a debug
66 build; a triple corresponding to -R's three arguments
67 use_resources -- list of extra resources to use
68 output_on_failure -- if true, display test output on failure
69 timeout -- dump the traceback and exit if a test takes more than
70 timeout seconds
71 failfast, match_tests -- See regrtest command-line flags for these.
72
73 Returns the tuple result, test_time, where result is one of the constants:
74 INTERRUPTED KeyboardInterrupt when run under -j
75 RESOURCE_DENIED test skipped because resource denied
76 SKIPPED test skipped for some other reason
77 ENV_CHANGED test failed because it changed the execution environment
78 FAILED test failed
79 PASSED test passed
80 """
81
82 if use_resources is not None:
83 support.use_resources = use_resources
84 use_timeout = (timeout is not None)
85 if use_timeout:
86 faulthandler.dump_traceback_later(timeout, exit=True)
87 try:
88 support.match_tests = match_tests
89 if failfast:
90 support.failfast = True
91 if output_on_failure:
92 support.verbose = True
93
94 # Reuse the same instance to all calls to runtest(). Some
95 # tests keep a reference to sys.stdout or sys.stderr
96 # (eg. test_argparse).
97 if runtest.stringio is None:
98 stream = io.StringIO()
99 runtest.stringio = stream
100 else:
101 stream = runtest.stringio
102 stream.seek(0)
103 stream.truncate()
104
105 orig_stdout = sys.stdout
106 orig_stderr = sys.stderr
107 try:
108 sys.stdout = stream
109 sys.stderr = stream
110 result = runtest_inner(test, verbose, quiet, huntrleaks,
111 display_failure=False)
112 if result[0] == FAILED:
113 output = stream.getvalue()
114 orig_stderr.write(output)
115 orig_stderr.flush()
116 finally:
117 sys.stdout = orig_stdout
118 sys.stderr = orig_stderr
119 else:
120 support.verbose = verbose # Tell tests to be moderately quiet
121 result = runtest_inner(test, verbose, quiet, huntrleaks,
122 display_failure=not verbose)
123 return result
124 finally:
125 if use_timeout:
126 faulthandler.cancel_dump_traceback_later()
127 cleanup_test_droppings(test, verbose)
128runtest.stringio = None
129
130
131def runtest_inner(test, verbose, quiet,
132 huntrleaks=False, display_failure=True):
133 support.unload(test)
134
135 test_time = 0.0
136 refleak = False # True if the test leaked references.
137 try:
138 if test.startswith('test.'):
139 abstest = test
140 else:
141 # Always import it from the test package
142 abstest = 'test.' + test
143 with saved_test_environment(test, verbose, quiet) as environment:
144 start_time = time.time()
145 the_module = importlib.import_module(abstest)
146 # If the test has a test_main, that will run the appropriate
147 # tests. If not, use normal unittest test loading.
148 test_runner = getattr(the_module, "test_main", None)
149 if test_runner is None:
150 def test_runner():
151 loader = unittest.TestLoader()
152 tests = loader.loadTestsFromModule(the_module)
153 for error in loader.errors:
154 print(error, file=sys.stderr)
155 if loader.errors:
156 raise Exception("errors while loading tests")
157 support.run_unittest(tests)
158 test_runner()
159 if huntrleaks:
160 refleak = dash_R(the_module, test, test_runner, huntrleaks)
161 test_time = time.time() - start_time
162 except support.ResourceDenied as msg:
163 if not quiet:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200164 print(test, "skipped --", msg, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200165 return RESOURCE_DENIED, test_time
166 except unittest.SkipTest as msg:
167 if not quiet:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200168 print(test, "skipped --", msg, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200169 return SKIPPED, test_time
170 except KeyboardInterrupt:
171 raise
172 except support.TestFailed as msg:
173 if display_failure:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200174 print("test", test, "failed --", msg, file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200175 else:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200176 print("test", test, "failed", file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200177 return FAILED, test_time
178 except:
179 msg = traceback.format_exc()
Victor Stinnerf33536c2015-09-30 00:48:27 +0200180 print("test", test, "crashed --", msg, file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200181 return FAILED, test_time
182 else:
183 if refleak:
184 return FAILED, test_time
185 if environment.changed:
186 return ENV_CHANGED, test_time
187 return PASSED, test_time
188
189
190def cleanup_test_droppings(testname, verbose):
191 import shutil
192 import stat
193 import gc
194
195 # First kill any dangling references to open files etc.
196 # This can also issue some ResourceWarnings which would otherwise get
197 # triggered during the following test run, and possibly produce failures.
198 gc.collect()
199
200 # Try to clean up junk commonly left behind. While tests shouldn't leave
201 # any files or directories behind, when a test fails that can be tedious
202 # for it to arrange. The consequences can be especially nasty on Windows,
203 # since if a test leaves a file open, it cannot be deleted by name (while
204 # there's nothing we can do about that here either, we can display the
205 # name of the offending test, which is a real help).
206 for name in (support.TESTFN,
207 "db_home",
208 ):
209 if not os.path.exists(name):
210 continue
211
212 if os.path.isdir(name):
213 kind, nuker = "directory", shutil.rmtree
214 elif os.path.isfile(name):
215 kind, nuker = "file", os.unlink
216 else:
217 raise SystemError("os.path says %r exists but is neither "
218 "directory nor file" % name)
219
220 if verbose:
221 print("%r left behind %s %r" % (testname, kind, name))
222 try:
223 # if we have chmod, fix possible permissions problems
224 # that might prevent cleanup
225 if (hasattr(os, 'chmod')):
226 os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
227 nuker(name)
228 except Exception as msg:
229 print(("%r left behind %s %r and it couldn't be "
230 "removed: %s" % (testname, kind, name, msg)), file=sys.stderr)
231
232
233def findtestdir(path=None):
234 return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir