blob: daff4766c27a7bb1a152838c12e8cdd5becc60f7 [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
Victor Stinner69649f22016-03-23 12:14:10 +010023# Minimum duration of a test to display its duration or to mention that
24# the test is running in background
25PROGRESS_MIN_TIME = 30.0 # seconds
26
27
Victor Stinner3844fe52015-09-26 10:38:01 +020028
Victor Stinner3844fe52015-09-26 10:38:01 +020029# small set of tests to determine if we have a basically functioning interpreter
30# (i.e. if any of these fail, then anything else is likely to follow)
31STDTESTS = [
32 'test_grammar',
33 'test_opcodes',
34 'test_dict',
35 'test_builtin',
36 'test_exceptions',
37 'test_types',
38 'test_unittest',
39 'test_doctest',
40 'test_doctest2',
41 'test_support'
42]
43
44# set of tests that we don't want to be executed when using regrtest
45NOTTESTS = set()
46
47
48def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
49 """Return a list of all applicable test modules."""
50 testdir = findtestdir(testdir)
51 names = os.listdir(testdir)
52 tests = []
53 others = set(stdtests) | nottests
54 for name in names:
55 mod, ext = os.path.splitext(name)
56 if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
57 tests.append(mod)
58 return stdtests + sorted(tests)
59
60
Victor Stinner6f20a2e2015-09-30 02:32:11 +020061def runtest(ns, test):
Victor Stinner3844fe52015-09-26 10:38:01 +020062 """Run a single test.
63
64 test -- the name of the test
65 verbose -- if true, print more messages
66 quiet -- if true, don't print 'skipped' messages (probably redundant)
67 huntrleaks -- run multiple times to test for leaks; requires a debug
68 build; a triple corresponding to -R's three arguments
Victor Stinner3844fe52015-09-26 10:38:01 +020069 output_on_failure -- if true, display test output on failure
70 timeout -- dump the traceback and exit if a test takes more than
71 timeout seconds
72 failfast, match_tests -- See regrtest command-line flags for these.
Brett Cannon11faa212015-10-02 16:20:49 -070073 pgo -- if true, suppress any info irrelevant to a generating a PGO build
Victor Stinner3844fe52015-09-26 10:38:01 +020074
75 Returns the tuple result, test_time, where result is one of the constants:
76 INTERRUPTED KeyboardInterrupt when run under -j
77 RESOURCE_DENIED test skipped because resource denied
78 SKIPPED test skipped for some other reason
79 ENV_CHANGED test failed because it changed the execution environment
80 FAILED test failed
81 PASSED test passed
82 """
83
Victor Stinner6f20a2e2015-09-30 02:32:11 +020084 verbose = ns.verbose
85 quiet = ns.quiet
86 huntrleaks = ns.huntrleaks
87 output_on_failure = ns.verbose3
88 failfast = ns.failfast
89 match_tests = ns.match_tests
90 timeout = ns.timeout
Brett Cannon11faa212015-10-02 16:20:49 -070091 pgo = ns.pgo
Victor Stinner6f20a2e2015-09-30 02:32:11 +020092
Victor Stinner3844fe52015-09-26 10:38:01 +020093 use_timeout = (timeout is not None)
94 if use_timeout:
95 faulthandler.dump_traceback_later(timeout, exit=True)
96 try:
97 support.match_tests = match_tests
98 if failfast:
99 support.failfast = True
100 if output_on_failure:
101 support.verbose = True
102
103 # Reuse the same instance to all calls to runtest(). Some
104 # tests keep a reference to sys.stdout or sys.stderr
105 # (eg. test_argparse).
106 if runtest.stringio is None:
107 stream = io.StringIO()
108 runtest.stringio = stream
109 else:
110 stream = runtest.stringio
111 stream.seek(0)
112 stream.truncate()
113
114 orig_stdout = sys.stdout
115 orig_stderr = sys.stderr
116 try:
117 sys.stdout = stream
118 sys.stderr = stream
119 result = runtest_inner(test, verbose, quiet, huntrleaks,
Brett Cannon11faa212015-10-02 16:20:49 -0700120 display_failure=False, pgo=pgo)
Victor Stinner3844fe52015-09-26 10:38:01 +0200121 if result[0] == FAILED:
122 output = stream.getvalue()
123 orig_stderr.write(output)
124 orig_stderr.flush()
125 finally:
126 sys.stdout = orig_stdout
127 sys.stderr = orig_stderr
128 else:
129 support.verbose = verbose # Tell tests to be moderately quiet
130 result = runtest_inner(test, verbose, quiet, huntrleaks,
Brett Cannon11faa212015-10-02 16:20:49 -0700131 display_failure=not verbose, pgo=pgo)
Victor Stinner3844fe52015-09-26 10:38:01 +0200132 return result
133 finally:
134 if use_timeout:
135 faulthandler.cancel_dump_traceback_later()
136 cleanup_test_droppings(test, verbose)
137runtest.stringio = None
138
139
140def runtest_inner(test, verbose, quiet,
Brett Cannon11faa212015-10-02 16:20:49 -0700141 huntrleaks=False, display_failure=True, *, pgo=False):
Victor Stinner3844fe52015-09-26 10:38:01 +0200142 support.unload(test)
143
144 test_time = 0.0
145 refleak = False # True if the test leaked references.
146 try:
147 if test.startswith('test.'):
148 abstest = test
149 else:
150 # Always import it from the test package
151 abstest = 'test.' + test
Brett Cannon11faa212015-10-02 16:20:49 -0700152 with saved_test_environment(test, verbose, quiet, pgo=pgo) as environment:
Victor Stinner3844fe52015-09-26 10:38:01 +0200153 start_time = time.time()
154 the_module = importlib.import_module(abstest)
155 # If the test has a test_main, that will run the appropriate
156 # tests. If not, use normal unittest test loading.
157 test_runner = getattr(the_module, "test_main", None)
158 if test_runner is None:
159 def test_runner():
160 loader = unittest.TestLoader()
161 tests = loader.loadTestsFromModule(the_module)
162 for error in loader.errors:
163 print(error, file=sys.stderr)
164 if loader.errors:
165 raise Exception("errors while loading tests")
166 support.run_unittest(tests)
167 test_runner()
168 if huntrleaks:
169 refleak = dash_R(the_module, test, test_runner, huntrleaks)
170 test_time = time.time() - start_time
171 except support.ResourceDenied as msg:
Brett Cannon11faa212015-10-02 16:20:49 -0700172 if not quiet and not pgo:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200173 print(test, "skipped --", msg, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200174 return RESOURCE_DENIED, test_time
175 except unittest.SkipTest as msg:
Brett Cannon11faa212015-10-02 16:20:49 -0700176 if not quiet and not pgo:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200177 print(test, "skipped --", msg, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200178 return SKIPPED, test_time
179 except KeyboardInterrupt:
180 raise
181 except support.TestFailed as msg:
Brett Cannon11faa212015-10-02 16:20:49 -0700182 if not pgo:
183 if display_failure:
184 print("test", test, "failed --", msg, file=sys.stderr,
185 flush=True)
186 else:
187 print("test", test, "failed", file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200188 return FAILED, test_time
189 except:
190 msg = traceback.format_exc()
Brett Cannon11faa212015-10-02 16:20:49 -0700191 if not pgo:
192 print("test", test, "crashed --", msg, file=sys.stderr,
193 flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200194 return FAILED, test_time
195 else:
196 if refleak:
197 return FAILED, test_time
198 if environment.changed:
199 return ENV_CHANGED, test_time
200 return PASSED, test_time
201
202
203def cleanup_test_droppings(testname, verbose):
204 import shutil
205 import stat
206 import gc
207
208 # First kill any dangling references to open files etc.
209 # This can also issue some ResourceWarnings which would otherwise get
210 # triggered during the following test run, and possibly produce failures.
211 gc.collect()
212
213 # Try to clean up junk commonly left behind. While tests shouldn't leave
214 # any files or directories behind, when a test fails that can be tedious
215 # for it to arrange. The consequences can be especially nasty on Windows,
216 # since if a test leaves a file open, it cannot be deleted by name (while
217 # there's nothing we can do about that here either, we can display the
218 # name of the offending test, which is a real help).
219 for name in (support.TESTFN,
220 "db_home",
221 ):
222 if not os.path.exists(name):
223 continue
224
225 if os.path.isdir(name):
226 kind, nuker = "directory", shutil.rmtree
227 elif os.path.isfile(name):
228 kind, nuker = "file", os.unlink
229 else:
230 raise SystemError("os.path says %r exists but is neither "
231 "directory nor file" % name)
232
233 if verbose:
234 print("%r left behind %s %r" % (testname, kind, name))
235 try:
236 # if we have chmod, fix possible permissions problems
237 # that might prevent cleanup
238 if (hasattr(os, 'chmod')):
239 os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
240 nuker(name)
241 except Exception as msg:
242 print(("%r left behind %s %r and it couldn't be "
243 "removed: %s" % (testname, kind, name, msg)), file=sys.stderr)
244
245
246def findtestdir(path=None):
247 return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir