blob: e46cc31caea5aecdaf7d4dccf7c31d8a8d093960 [file] [log] [blame]
Victor Stinner4d299832019-04-26 04:08:53 +02001import collections
Victor Stinner3844fe52015-09-26 10:38:01 +02002import faulthandler
Victor Stinner4d299832019-04-26 04:08:53 +02003import functools
Victor Stinner75120d22019-04-26 09:28:53 +02004import gc
Victor Stinner3844fe52015-09-26 10:38:01 +02005import importlib
6import io
Victor Stinner3844fe52015-09-26 10:38:01 +02007import os
8import sys
9import time
10import traceback
11import unittest
Victor Stinner75120d22019-04-26 09:28:53 +020012
Victor Stinner3844fe52015-09-26 10:38:01 +020013from test import support
Hai Shif7ba40b2020-06-25 18:38:51 +080014from test.support import import_helper
15from test.support import os_helper
Serhiy Storchaka83910262016-11-11 11:46:44 +020016from test.libregrtest.refleak import dash_R, clear_caches
Victor Stinner3844fe52015-09-26 10:38:01 +020017from test.libregrtest.save_env import saved_test_environment
Victor Stinnerb0c83692019-08-14 14:18:51 +020018from test.libregrtest.utils import format_duration, print_warning
Victor Stinner3844fe52015-09-26 10:38:01 +020019
20
21# Test result constants.
22PASSED = 1
23FAILED = 0
24ENV_CHANGED = -1
25SKIPPED = -2
26RESOURCE_DENIED = -3
27INTERRUPTED = -4
28CHILD_ERROR = -5 # error in a child process
Victor Stinnerb0917df2019-05-13 19:17:54 +020029TEST_DID_NOT_RUN = -6
Victor Stinnerb0c83692019-08-14 14:18:51 +020030TIMEOUT = -7
Victor Stinner3844fe52015-09-26 10:38:01 +020031
Victor Stinner1b8b4232016-05-20 13:37:40 +020032_FORMAT_TEST_RESULT = {
33 PASSED: '%s passed',
34 FAILED: '%s failed',
35 ENV_CHANGED: '%s failed (env changed)',
36 SKIPPED: '%s skipped',
37 RESOURCE_DENIED: '%s skipped (resource denied)',
38 INTERRUPTED: '%s interrupted',
39 CHILD_ERROR: '%s crashed',
Pablo Galindo97243482018-11-29 17:17:44 +000040 TEST_DID_NOT_RUN: '%s run no tests',
Victor Stinnerb0c83692019-08-14 14:18:51 +020041 TIMEOUT: '%s timed out',
Victor Stinner1b8b4232016-05-20 13:37:40 +020042}
43
Victor Stinner69649f22016-03-23 12:14:10 +010044# Minimum duration of a test to display its duration or to mention that
45# the test is running in background
46PROGRESS_MIN_TIME = 30.0 # seconds
47
Victor Stinner3844fe52015-09-26 10:38:01 +020048# small set of tests to determine if we have a basically functioning interpreter
49# (i.e. if any of these fail, then anything else is likely to follow)
50STDTESTS = [
51 'test_grammar',
52 'test_opcodes',
53 'test_dict',
54 'test_builtin',
55 'test_exceptions',
56 'test_types',
57 'test_unittest',
58 'test_doctest',
59 'test_doctest2',
60 'test_support'
61]
62
63# set of tests that we don't want to be executed when using regrtest
64NOTTESTS = set()
65
66
Victor Stinner4d299832019-04-26 04:08:53 +020067# used by --findleaks, store for gc.garbage
Victor Stinner75120d22019-04-26 09:28:53 +020068FOUND_GARBAGE = []
Victor Stinner4d299832019-04-26 04:08:53 +020069
70
Victor Stinnerb0917df2019-05-13 19:17:54 +020071def is_failed(result, ns):
72 ok = result.result
73 if ok in (PASSED, RESOURCE_DENIED, SKIPPED, TEST_DID_NOT_RUN):
74 return False
75 if ok == ENV_CHANGED:
76 return ns.fail_env_changed
77 return True
78
79
Victor Stinner4d299832019-04-26 04:08:53 +020080def format_test_result(result):
81 fmt = _FORMAT_TEST_RESULT.get(result.result, "%s")
Victor Stinnerb0c83692019-08-14 14:18:51 +020082 text = fmt % result.test_name
83 if result.result == TIMEOUT:
84 text = '%s (%s)' % (text, format_duration(result.test_time))
85 return text
Victor Stinner4d299832019-04-26 04:08:53 +020086
87
88def findtestdir(path=None):
89 return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir
Victor Stinner1b8b4232016-05-20 13:37:40 +020090
91
Victor Stinner3844fe52015-09-26 10:38:01 +020092def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
93 """Return a list of all applicable test modules."""
94 testdir = findtestdir(testdir)
95 names = os.listdir(testdir)
96 tests = []
97 others = set(stdtests) | nottests
98 for name in names:
99 mod, ext = os.path.splitext(name)
100 if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
101 tests.append(mod)
102 return stdtests + sorted(tests)
103
104
Victor Stinner4d299832019-04-26 04:08:53 +0200105def get_abs_module(ns, test_name):
106 if test_name.startswith('test.') or ns.testdir:
107 return test_name
mlouielua49c9352017-06-16 17:36:19 +0800108 else:
Victor Stinner4d299832019-04-26 04:08:53 +0200109 # Import it from the test package
110 return 'test.' + test_name
mlouielua49c9352017-06-16 17:36:19 +0800111
112
Victor Stinner4d299832019-04-26 04:08:53 +0200113TestResult = collections.namedtuple('TestResult',
114 'test_name result test_time xml_data')
115
116def _runtest(ns, test_name):
117 # Handle faulthandler timeout, capture stdout+stderr, XML serialization
118 # and measure time.
119
120 output_on_failure = ns.verbose3
121
122 use_timeout = (ns.timeout is not None)
123 if use_timeout:
124 faulthandler.dump_traceback_later(ns.timeout, exit=True)
125
126 start_time = time.perf_counter()
127 try:
Pablo Galindoe0cd8aa2019-11-19 23:46:49 +0000128 support.set_match_tests(ns.match_tests, ns.ignore_tests)
Victor Stinner4d299832019-04-26 04:08:53 +0200129 support.junit_xml_list = xml_list = [] if ns.xmlpath else None
130 if ns.failfast:
131 support.failfast = True
132
133 if output_on_failure:
134 support.verbose = True
135
136 stream = io.StringIO()
137 orig_stdout = sys.stdout
138 orig_stderr = sys.stderr
139 try:
140 sys.stdout = stream
141 sys.stderr = stream
142 result = _runtest_inner(ns, test_name,
143 display_failure=False)
144 if result != PASSED:
145 output = stream.getvalue()
146 orig_stderr.write(output)
147 orig_stderr.flush()
148 finally:
149 sys.stdout = orig_stdout
150 sys.stderr = orig_stderr
151 else:
152 # Tell tests to be moderately quiet
153 support.verbose = ns.verbose
154
155 result = _runtest_inner(ns, test_name,
156 display_failure=not ns.verbose)
157
158 if xml_list:
159 import xml.etree.ElementTree as ET
160 xml_data = [ET.tostring(x).decode('us-ascii') for x in xml_list]
161 else:
162 xml_data = None
163
164 test_time = time.perf_counter() - start_time
165
166 return TestResult(test_name, result, test_time, xml_data)
167 finally:
168 if use_timeout:
169 faulthandler.cancel_dump_traceback_later()
170 support.junit_xml_list = None
171
172
173def runtest(ns, test_name):
Victor Stinner3844fe52015-09-26 10:38:01 +0200174 """Run a single test.
175
Victor Stinnerab983672016-08-22 14:28:52 +0200176 ns -- regrtest namespace of options
Victor Stinner4d299832019-04-26 04:08:53 +0200177 test_name -- the name of the test
Victor Stinner3844fe52015-09-26 10:38:01 +0200178
Steve Dowerd0f49d22018-09-18 09:10:26 -0700179 Returns the tuple (result, test_time, xml_data), where result is one
180 of the constants:
Victor Stinnerab983672016-08-22 14:28:52 +0200181
Victor Stinner4d299832019-04-26 04:08:53 +0200182 INTERRUPTED KeyboardInterrupt
Victor Stinner3844fe52015-09-26 10:38:01 +0200183 RESOURCE_DENIED test skipped because resource denied
184 SKIPPED test skipped for some other reason
185 ENV_CHANGED test failed because it changed the execution environment
186 FAILED test failed
187 PASSED test passed
Pablo Galindo97243482018-11-29 17:17:44 +0000188 EMPTY_TEST_SUITE test ran no subtests.
Victor Stinnerb0c83692019-08-14 14:18:51 +0200189 TIMEOUT test timed out.
Steve Dowerd0f49d22018-09-18 09:10:26 -0700190
191 If ns.xmlpath is not None, xml_data is a list containing each
192 generated testsuite element.
Victor Stinner3844fe52015-09-26 10:38:01 +0200193 """
Victor Stinner3844fe52015-09-26 10:38:01 +0200194 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200195 return _runtest(ns, test_name)
196 except:
197 if not ns.pgo:
198 msg = traceback.format_exc()
199 print(f"test {test_name} crashed -- {msg}",
200 file=sys.stderr, flush=True)
201 return TestResult(test_name, FAILED, 0.0, None)
Victor Stinner3844fe52015-09-26 10:38:01 +0200202
203
Victor Stinner4d299832019-04-26 04:08:53 +0200204def _test_module(the_module):
205 loader = unittest.TestLoader()
206 tests = loader.loadTestsFromModule(the_module)
207 for error in loader.errors:
208 print(error, file=sys.stderr)
209 if loader.errors:
210 raise Exception("errors while loading tests")
211 support.run_unittest(tests)
Victor Stinner3844fe52015-09-26 10:38:01 +0200212
Victor Stinner4d299832019-04-26 04:08:53 +0200213
214def _runtest_inner2(ns, test_name):
215 # Load the test function, run the test function, handle huntrleaks
216 # and findleaks to detect leaks
217
218 abstest = get_abs_module(ns, test_name)
219
220 # remove the module from sys.module to reload it if it was already imported
Hai Shif7ba40b2020-06-25 18:38:51 +0800221 import_helper.unload(abstest)
Victor Stinner4d299832019-04-26 04:08:53 +0200222
223 the_module = importlib.import_module(abstest)
224
225 # If the test has a test_main, that will run the appropriate
226 # tests. If not, use normal unittest test loading.
227 test_runner = getattr(the_module, "test_main", None)
228 if test_runner is None:
229 test_runner = functools.partial(_test_module, the_module)
230
Victor Stinner3844fe52015-09-26 10:38:01 +0200231 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200232 if ns.huntrleaks:
233 # Return True if the test leaked references
234 refleak = dash_R(ns, test_name, test_runner)
235 else:
236 test_runner()
237 refleak = False
238 finally:
239 cleanup_test_droppings(test_name, ns.verbose)
240
Victor Stinner75120d22019-04-26 09:28:53 +0200241 support.gc_collect()
Victor Stinner4d299832019-04-26 04:08:53 +0200242
Victor Stinner75120d22019-04-26 09:28:53 +0200243 if gc.garbage:
244 support.environment_altered = True
245 print_warning(f"{test_name} created {len(gc.garbage)} "
246 f"uncollectable object(s).")
247
248 # move the uncollectable objects somewhere,
249 # so we don't see them again
250 FOUND_GARBAGE.extend(gc.garbage)
251 gc.garbage.clear()
252
253 support.reap_children()
Victor Stinner4d299832019-04-26 04:08:53 +0200254
255 return refleak
256
257
258def _runtest_inner(ns, test_name, display_failure=True):
259 # Detect environment changes, handle exceptions.
260
261 # Reset the environment_altered flag to detect if a test altered
262 # the environment
263 support.environment_altered = False
264
265 if ns.pgo:
266 display_failure = False
267
268 try:
Serhiy Storchaka83910262016-11-11 11:46:44 +0200269 clear_caches()
Victor Stinner4d299832019-04-26 04:08:53 +0200270
271 with saved_test_environment(test_name, ns.verbose, ns.quiet, pgo=ns.pgo) as environment:
272 refleak = _runtest_inner2(ns, test_name)
Victor Stinner3844fe52015-09-26 10:38:01 +0200273 except support.ResourceDenied as msg:
Victor Stinnerab983672016-08-22 14:28:52 +0200274 if not ns.quiet and not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200275 print(f"{test_name} skipped -- {msg}", flush=True)
276 return RESOURCE_DENIED
Victor Stinner3844fe52015-09-26 10:38:01 +0200277 except unittest.SkipTest as msg:
Victor Stinnerab983672016-08-22 14:28:52 +0200278 if not ns.quiet and not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200279 print(f"{test_name} skipped -- {msg}", flush=True)
280 return SKIPPED
281 except support.TestFailed as exc:
282 msg = f"test {test_name} failed"
283 if display_failure:
284 msg = f"{msg} -- {exc}"
285 print(msg, file=sys.stderr, flush=True)
286 return FAILED
Pablo Galindo97243482018-11-29 17:17:44 +0000287 except support.TestDidNotRun:
Victor Stinner4d299832019-04-26 04:08:53 +0200288 return TEST_DID_NOT_RUN
289 except KeyboardInterrupt:
Victor Stinner3cde4402019-04-26 08:40:25 +0200290 print()
Victor Stinner4d299832019-04-26 04:08:53 +0200291 return INTERRUPTED
Victor Stinner3844fe52015-09-26 10:38:01 +0200292 except:
Victor Stinnerab983672016-08-22 14:28:52 +0200293 if not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200294 msg = traceback.format_exc()
295 print(f"test {test_name} crashed -- {msg}",
296 file=sys.stderr, flush=True)
297 return FAILED
298
299 if refleak:
300 return FAILED
301 if environment.changed:
302 return ENV_CHANGED
303 return PASSED
Victor Stinner3844fe52015-09-26 10:38:01 +0200304
305
Victor Stinner4d299832019-04-26 04:08:53 +0200306def cleanup_test_droppings(test_name, verbose):
Victor Stinner3844fe52015-09-26 10:38:01 +0200307 # First kill any dangling references to open files etc.
308 # This can also issue some ResourceWarnings which would otherwise get
309 # triggered during the following test run, and possibly produce failures.
Victor Stinner4d299832019-04-26 04:08:53 +0200310 support.gc_collect()
Victor Stinner3844fe52015-09-26 10:38:01 +0200311
312 # Try to clean up junk commonly left behind. While tests shouldn't leave
313 # any files or directories behind, when a test fails that can be tedious
314 # for it to arrange. The consequences can be especially nasty on Windows,
315 # since if a test leaves a file open, it cannot be deleted by name (while
316 # there's nothing we can do about that here either, we can display the
317 # name of the offending test, which is a real help).
Hai Shif7ba40b2020-06-25 18:38:51 +0800318 for name in (os_helper.TESTFN,):
Victor Stinner3844fe52015-09-26 10:38:01 +0200319 if not os.path.exists(name):
320 continue
321
322 if os.path.isdir(name):
Victor Stinner4d299832019-04-26 04:08:53 +0200323 import shutil
Victor Stinner3844fe52015-09-26 10:38:01 +0200324 kind, nuker = "directory", shutil.rmtree
325 elif os.path.isfile(name):
326 kind, nuker = "file", os.unlink
327 else:
Victor Stinner4d299832019-04-26 04:08:53 +0200328 raise RuntimeError(f"os.path says {name!r} exists but is neither "
329 f"directory nor file")
Victor Stinner3844fe52015-09-26 10:38:01 +0200330
331 if verbose:
Victor Stinnerd663d342020-04-23 19:03:52 +0200332 print_warning(f"{test_name} left behind {kind} {name!r}")
Victor Stinner4d299832019-04-26 04:08:53 +0200333 support.environment_altered = True
334
Victor Stinner3844fe52015-09-26 10:38:01 +0200335 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200336 import stat
Anthony Sottile8377cd42019-02-25 14:32:27 -0800337 # fix possible permissions problems that might prevent cleanup
338 os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
Victor Stinner3844fe52015-09-26 10:38:01 +0200339 nuker(name)
Victor Stinner4d299832019-04-26 04:08:53 +0200340 except Exception as exc:
341 print_warning(f"{test_name} left behind {kind} {name!r} "
342 f"and it couldn't be removed: {exc}")