blob: 043f23c095164244eb0b515ccc5d9ff1bb4c76ef [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
Victor Stinner6f20a2e2015-09-30 02:32:11 +020056def runtest(ns, test):
Victor Stinner3844fe52015-09-26 10:38:01 +020057 """Run a single test.
58
59 test -- the name of the test
60 verbose -- if true, print more messages
61 quiet -- if true, don't print 'skipped' messages (probably redundant)
62 huntrleaks -- run multiple times to test for leaks; requires a debug
63 build; a triple corresponding to -R's three arguments
Victor Stinner3844fe52015-09-26 10:38:01 +020064 output_on_failure -- if true, display test output on failure
65 timeout -- dump the traceback and exit if a test takes more than
66 timeout seconds
67 failfast, match_tests -- See regrtest command-line flags for these.
Brett Cannon11faa212015-10-02 16:20:49 -070068 pgo -- if true, suppress any info irrelevant to a generating a PGO build
Victor Stinner3844fe52015-09-26 10:38:01 +020069
70 Returns the tuple result, test_time, where result is one of the constants:
71 INTERRUPTED KeyboardInterrupt when run under -j
72 RESOURCE_DENIED test skipped because resource denied
73 SKIPPED test skipped for some other reason
74 ENV_CHANGED test failed because it changed the execution environment
75 FAILED test failed
76 PASSED test passed
77 """
78
Victor Stinner6f20a2e2015-09-30 02:32:11 +020079 verbose = ns.verbose
80 quiet = ns.quiet
81 huntrleaks = ns.huntrleaks
82 output_on_failure = ns.verbose3
83 failfast = ns.failfast
84 match_tests = ns.match_tests
85 timeout = ns.timeout
Brett Cannon11faa212015-10-02 16:20:49 -070086 pgo = ns.pgo
Victor Stinner6f20a2e2015-09-30 02:32:11 +020087
Victor Stinner3844fe52015-09-26 10:38:01 +020088 use_timeout = (timeout is not None)
89 if use_timeout:
90 faulthandler.dump_traceback_later(timeout, exit=True)
91 try:
92 support.match_tests = match_tests
93 if failfast:
94 support.failfast = True
95 if output_on_failure:
96 support.verbose = True
97
98 # Reuse the same instance to all calls to runtest(). Some
99 # tests keep a reference to sys.stdout or sys.stderr
100 # (eg. test_argparse).
101 if runtest.stringio is None:
102 stream = io.StringIO()
103 runtest.stringio = stream
104 else:
105 stream = runtest.stringio
106 stream.seek(0)
107 stream.truncate()
108
109 orig_stdout = sys.stdout
110 orig_stderr = sys.stderr
111 try:
112 sys.stdout = stream
113 sys.stderr = stream
114 result = runtest_inner(test, verbose, quiet, huntrleaks,
Brett Cannon11faa212015-10-02 16:20:49 -0700115 display_failure=False, pgo=pgo)
Victor Stinner3844fe52015-09-26 10:38:01 +0200116 if result[0] == FAILED:
117 output = stream.getvalue()
118 orig_stderr.write(output)
119 orig_stderr.flush()
120 finally:
121 sys.stdout = orig_stdout
122 sys.stderr = orig_stderr
123 else:
124 support.verbose = verbose # Tell tests to be moderately quiet
125 result = runtest_inner(test, verbose, quiet, huntrleaks,
Brett Cannon11faa212015-10-02 16:20:49 -0700126 display_failure=not verbose, pgo=pgo)
Victor Stinner3844fe52015-09-26 10:38:01 +0200127 return result
128 finally:
129 if use_timeout:
130 faulthandler.cancel_dump_traceback_later()
131 cleanup_test_droppings(test, verbose)
132runtest.stringio = None
133
134
135def runtest_inner(test, verbose, quiet,
Brett Cannon11faa212015-10-02 16:20:49 -0700136 huntrleaks=False, display_failure=True, *, pgo=False):
Victor Stinner3844fe52015-09-26 10:38:01 +0200137 support.unload(test)
138
139 test_time = 0.0
140 refleak = False # True if the test leaked references.
141 try:
142 if test.startswith('test.'):
143 abstest = test
144 else:
145 # Always import it from the test package
146 abstest = 'test.' + test
Brett Cannon11faa212015-10-02 16:20:49 -0700147 with saved_test_environment(test, verbose, quiet, pgo=pgo) as environment:
Victor Stinner3844fe52015-09-26 10:38:01 +0200148 start_time = time.time()
149 the_module = importlib.import_module(abstest)
150 # If the test has a test_main, that will run the appropriate
151 # tests. If not, use normal unittest test loading.
152 test_runner = getattr(the_module, "test_main", None)
153 if test_runner is None:
154 def test_runner():
155 loader = unittest.TestLoader()
156 tests = loader.loadTestsFromModule(the_module)
157 for error in loader.errors:
158 print(error, file=sys.stderr)
159 if loader.errors:
160 raise Exception("errors while loading tests")
161 support.run_unittest(tests)
162 test_runner()
163 if huntrleaks:
164 refleak = dash_R(the_module, test, test_runner, huntrleaks)
165 test_time = time.time() - start_time
166 except support.ResourceDenied as msg:
Brett Cannon11faa212015-10-02 16:20:49 -0700167 if not quiet and not pgo:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200168 print(test, "skipped --", msg, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200169 return RESOURCE_DENIED, test_time
170 except unittest.SkipTest as msg:
Brett Cannon11faa212015-10-02 16:20:49 -0700171 if not quiet and not pgo:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200172 print(test, "skipped --", msg, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200173 return SKIPPED, test_time
174 except KeyboardInterrupt:
175 raise
176 except support.TestFailed as msg:
Brett Cannon11faa212015-10-02 16:20:49 -0700177 if not pgo:
178 if display_failure:
179 print("test", test, "failed --", msg, file=sys.stderr,
180 flush=True)
181 else:
182 print("test", test, "failed", file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200183 return FAILED, test_time
184 except:
185 msg = traceback.format_exc()
Brett Cannon11faa212015-10-02 16:20:49 -0700186 if not pgo:
187 print("test", test, "crashed --", msg, file=sys.stderr,
188 flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200189 return FAILED, test_time
190 else:
191 if refleak:
192 return FAILED, test_time
193 if environment.changed:
194 return ENV_CHANGED, test_time
195 return PASSED, test_time
196
197
198def cleanup_test_droppings(testname, verbose):
199 import shutil
200 import stat
201 import gc
202
203 # First kill any dangling references to open files etc.
204 # This can also issue some ResourceWarnings which would otherwise get
205 # triggered during the following test run, and possibly produce failures.
206 gc.collect()
207
208 # Try to clean up junk commonly left behind. While tests shouldn't leave
209 # any files or directories behind, when a test fails that can be tedious
210 # for it to arrange. The consequences can be especially nasty on Windows,
211 # since if a test leaves a file open, it cannot be deleted by name (while
212 # there's nothing we can do about that here either, we can display the
213 # name of the offending test, which is a real help).
214 for name in (support.TESTFN,
215 "db_home",
216 ):
217 if not os.path.exists(name):
218 continue
219
220 if os.path.isdir(name):
221 kind, nuker = "directory", shutil.rmtree
222 elif os.path.isfile(name):
223 kind, nuker = "file", os.unlink
224 else:
225 raise SystemError("os.path says %r exists but is neither "
226 "directory nor file" % name)
227
228 if verbose:
229 print("%r left behind %s %r" % (testname, kind, name))
230 try:
231 # if we have chmod, fix possible permissions problems
232 # that might prevent cleanup
233 if (hasattr(os, 'chmod')):
234 os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
235 nuker(name)
236 except Exception as msg:
237 print(("%r left behind %s %r and it couldn't be "
238 "removed: %s" % (testname, kind, name, msg)), file=sys.stderr)
239
240
241def findtestdir(path=None):
242 return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir