blob: 927c47066297052a33175da6bd8dddd704c1b797 [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 os_helper
Victor Stinner10417dd2021-03-23 00:17:05 +010015from test.libregrtest.utils import clear_caches
Victor Stinner3844fe52015-09-26 10:38:01 +020016from test.libregrtest.save_env import saved_test_environment
Victor Stinnerb0c83692019-08-14 14:18:51 +020017from test.libregrtest.utils import format_duration, print_warning
Victor Stinner3844fe52015-09-26 10:38:01 +020018
19
20# Test result constants.
21PASSED = 1
22FAILED = 0
23ENV_CHANGED = -1
24SKIPPED = -2
25RESOURCE_DENIED = -3
26INTERRUPTED = -4
27CHILD_ERROR = -5 # error in a child process
Victor Stinnerb0917df2019-05-13 19:17:54 +020028TEST_DID_NOT_RUN = -6
Victor Stinnerb0c83692019-08-14 14:18:51 +020029TIMEOUT = -7
Victor Stinner3844fe52015-09-26 10:38:01 +020030
Victor Stinner1b8b4232016-05-20 13:37:40 +020031_FORMAT_TEST_RESULT = {
32 PASSED: '%s passed',
33 FAILED: '%s failed',
34 ENV_CHANGED: '%s failed (env changed)',
35 SKIPPED: '%s skipped',
36 RESOURCE_DENIED: '%s skipped (resource denied)',
37 INTERRUPTED: '%s interrupted',
38 CHILD_ERROR: '%s crashed',
Pablo Galindo97243482018-11-29 17:17:44 +000039 TEST_DID_NOT_RUN: '%s run no tests',
Victor Stinnerb0c83692019-08-14 14:18:51 +020040 TIMEOUT: '%s timed out',
Victor Stinner1b8b4232016-05-20 13:37:40 +020041}
42
Victor Stinner69649f22016-03-23 12:14:10 +010043# Minimum duration of a test to display its duration or to mention that
44# the test is running in background
45PROGRESS_MIN_TIME = 30.0 # seconds
46
Victor Stinner3844fe52015-09-26 10:38:01 +020047# small set of tests to determine if we have a basically functioning interpreter
48# (i.e. if any of these fail, then anything else is likely to follow)
49STDTESTS = [
50 'test_grammar',
51 'test_opcodes',
52 'test_dict',
53 'test_builtin',
54 'test_exceptions',
55 'test_types',
56 'test_unittest',
57 'test_doctest',
58 'test_doctest2',
59 'test_support'
60]
61
62# set of tests that we don't want to be executed when using regrtest
63NOTTESTS = set()
64
65
Victor Stinner4d299832019-04-26 04:08:53 +020066# used by --findleaks, store for gc.garbage
Victor Stinner75120d22019-04-26 09:28:53 +020067FOUND_GARBAGE = []
Victor Stinner4d299832019-04-26 04:08:53 +020068
69
Victor Stinnerb0917df2019-05-13 19:17:54 +020070def is_failed(result, ns):
71 ok = result.result
72 if ok in (PASSED, RESOURCE_DENIED, SKIPPED, TEST_DID_NOT_RUN):
73 return False
74 if ok == ENV_CHANGED:
75 return ns.fail_env_changed
76 return True
77
78
Victor Stinner4d299832019-04-26 04:08:53 +020079def format_test_result(result):
80 fmt = _FORMAT_TEST_RESULT.get(result.result, "%s")
Victor Stinnerb0c83692019-08-14 14:18:51 +020081 text = fmt % result.test_name
82 if result.result == TIMEOUT:
83 text = '%s (%s)' % (text, format_duration(result.test_time))
84 return text
Victor Stinner4d299832019-04-26 04:08:53 +020085
86
87def findtestdir(path=None):
88 return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir
Victor Stinner1b8b4232016-05-20 13:37:40 +020089
90
Victor Stinner3844fe52015-09-26 10:38:01 +020091def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
92 """Return a list of all applicable test modules."""
93 testdir = findtestdir(testdir)
94 names = os.listdir(testdir)
95 tests = []
96 others = set(stdtests) | nottests
97 for name in names:
98 mod, ext = os.path.splitext(name)
99 if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
100 tests.append(mod)
101 return stdtests + sorted(tests)
102
103
Victor Stinner4d299832019-04-26 04:08:53 +0200104def get_abs_module(ns, test_name):
105 if test_name.startswith('test.') or ns.testdir:
106 return test_name
mlouielua49c9352017-06-16 17:36:19 +0800107 else:
Victor Stinner4d299832019-04-26 04:08:53 +0200108 # Import it from the test package
109 return 'test.' + test_name
mlouielua49c9352017-06-16 17:36:19 +0800110
111
Victor Stinner4d299832019-04-26 04:08:53 +0200112TestResult = collections.namedtuple('TestResult',
113 'test_name result test_time xml_data')
114
115def _runtest(ns, test_name):
116 # Handle faulthandler timeout, capture stdout+stderr, XML serialization
117 # and measure time.
118
119 output_on_failure = ns.verbose3
120
121 use_timeout = (ns.timeout is not None)
122 if use_timeout:
123 faulthandler.dump_traceback_later(ns.timeout, exit=True)
124
125 start_time = time.perf_counter()
126 try:
Pablo Galindoe0cd8aa2019-11-19 23:46:49 +0000127 support.set_match_tests(ns.match_tests, ns.ignore_tests)
Victor Stinner4d299832019-04-26 04:08:53 +0200128 support.junit_xml_list = xml_list = [] if ns.xmlpath else None
129 if ns.failfast:
130 support.failfast = True
131
132 if output_on_failure:
133 support.verbose = True
134
135 stream = io.StringIO()
136 orig_stdout = sys.stdout
137 orig_stderr = sys.stderr
138 try:
139 sys.stdout = stream
140 sys.stderr = stream
141 result = _runtest_inner(ns, test_name,
142 display_failure=False)
143 if result != PASSED:
144 output = stream.getvalue()
145 orig_stderr.write(output)
146 orig_stderr.flush()
147 finally:
148 sys.stdout = orig_stdout
149 sys.stderr = orig_stderr
150 else:
151 # Tell tests to be moderately quiet
152 support.verbose = ns.verbose
153
154 result = _runtest_inner(ns, test_name,
155 display_failure=not ns.verbose)
156
157 if xml_list:
158 import xml.etree.ElementTree as ET
159 xml_data = [ET.tostring(x).decode('us-ascii') for x in xml_list]
160 else:
161 xml_data = None
162
163 test_time = time.perf_counter() - start_time
164
165 return TestResult(test_name, result, test_time, xml_data)
166 finally:
167 if use_timeout:
168 faulthandler.cancel_dump_traceback_later()
169 support.junit_xml_list = None
170
171
172def runtest(ns, test_name):
Victor Stinner3844fe52015-09-26 10:38:01 +0200173 """Run a single test.
174
Victor Stinnerab983672016-08-22 14:28:52 +0200175 ns -- regrtest namespace of options
Victor Stinner4d299832019-04-26 04:08:53 +0200176 test_name -- the name of the test
Victor Stinner3844fe52015-09-26 10:38:01 +0200177
Steve Dowerd0f49d22018-09-18 09:10:26 -0700178 Returns the tuple (result, test_time, xml_data), where result is one
179 of the constants:
Victor Stinnerab983672016-08-22 14:28:52 +0200180
Victor Stinner4d299832019-04-26 04:08:53 +0200181 INTERRUPTED KeyboardInterrupt
Victor Stinner3844fe52015-09-26 10:38:01 +0200182 RESOURCE_DENIED test skipped because resource denied
183 SKIPPED test skipped for some other reason
184 ENV_CHANGED test failed because it changed the execution environment
185 FAILED test failed
186 PASSED test passed
Pablo Galindo97243482018-11-29 17:17:44 +0000187 EMPTY_TEST_SUITE test ran no subtests.
Victor Stinnerb0c83692019-08-14 14:18:51 +0200188 TIMEOUT test timed out.
Steve Dowerd0f49d22018-09-18 09:10:26 -0700189
190 If ns.xmlpath is not None, xml_data is a list containing each
191 generated testsuite element.
Victor Stinner3844fe52015-09-26 10:38:01 +0200192 """
Victor Stinner3844fe52015-09-26 10:38:01 +0200193 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200194 return _runtest(ns, test_name)
195 except:
196 if not ns.pgo:
197 msg = traceback.format_exc()
198 print(f"test {test_name} crashed -- {msg}",
199 file=sys.stderr, flush=True)
200 return TestResult(test_name, FAILED, 0.0, None)
Victor Stinner3844fe52015-09-26 10:38:01 +0200201
202
Victor Stinner4d299832019-04-26 04:08:53 +0200203def _test_module(the_module):
204 loader = unittest.TestLoader()
205 tests = loader.loadTestsFromModule(the_module)
206 for error in loader.errors:
207 print(error, file=sys.stderr)
208 if loader.errors:
209 raise Exception("errors while loading tests")
210 support.run_unittest(tests)
Victor Stinner3844fe52015-09-26 10:38:01 +0200211
Victor Stinner4d299832019-04-26 04:08:53 +0200212
Victor Stinner532e0632021-03-22 23:52:13 +0100213def save_env(ns, test_name):
214 return saved_test_environment(test_name, ns.verbose, ns.quiet, pgo=ns.pgo)
215
216
Victor Stinner4d299832019-04-26 04:08:53 +0200217def _runtest_inner2(ns, test_name):
218 # Load the test function, run the test function, handle huntrleaks
219 # and findleaks to detect leaks
220
221 abstest = get_abs_module(ns, test_name)
222
223 # remove the module from sys.module to reload it if it was already imported
Victor Stinner0473fb22021-03-23 01:08:49 +0100224 try:
225 del sys.modules[abstest]
226 except KeyError:
227 pass
Victor Stinner4d299832019-04-26 04:08:53 +0200228
229 the_module = importlib.import_module(abstest)
230
Victor Stinner10417dd2021-03-23 00:17:05 +0100231 if ns.huntrleaks:
232 from test.libregrtest.refleak import dash_R
233
Victor Stinner4d299832019-04-26 04:08:53 +0200234 # If the test has a test_main, that will run the appropriate
235 # tests. If not, use normal unittest test loading.
236 test_runner = getattr(the_module, "test_main", None)
237 if test_runner is None:
238 test_runner = functools.partial(_test_module, the_module)
239
Victor Stinner3844fe52015-09-26 10:38:01 +0200240 try:
Victor Stinner532e0632021-03-22 23:52:13 +0100241 with save_env(ns, test_name):
242 if ns.huntrleaks:
243 # Return True if the test leaked references
244 refleak = dash_R(ns, test_name, test_runner)
245 else:
246 test_runner()
247 refleak = False
Victor Stinner4d299832019-04-26 04:08:53 +0200248 finally:
249 cleanup_test_droppings(test_name, ns.verbose)
250
Victor Stinner75120d22019-04-26 09:28:53 +0200251 support.gc_collect()
Victor Stinner4d299832019-04-26 04:08:53 +0200252
Victor Stinner75120d22019-04-26 09:28:53 +0200253 if gc.garbage:
254 support.environment_altered = True
255 print_warning(f"{test_name} created {len(gc.garbage)} "
256 f"uncollectable object(s).")
257
258 # move the uncollectable objects somewhere,
259 # so we don't see them again
260 FOUND_GARBAGE.extend(gc.garbage)
261 gc.garbage.clear()
262
263 support.reap_children()
Victor Stinner4d299832019-04-26 04:08:53 +0200264
265 return refleak
266
267
268def _runtest_inner(ns, test_name, display_failure=True):
269 # Detect environment changes, handle exceptions.
270
271 # Reset the environment_altered flag to detect if a test altered
272 # the environment
273 support.environment_altered = False
274
275 if ns.pgo:
276 display_failure = False
277
278 try:
Serhiy Storchaka83910262016-11-11 11:46:44 +0200279 clear_caches()
Victor Stinner4d299832019-04-26 04:08:53 +0200280
Victor Stinner532e0632021-03-22 23:52:13 +0100281 with save_env(ns, test_name):
Victor Stinner4d299832019-04-26 04:08:53 +0200282 refleak = _runtest_inner2(ns, test_name)
Victor Stinner3844fe52015-09-26 10:38:01 +0200283 except support.ResourceDenied as msg:
Victor Stinnerab983672016-08-22 14:28:52 +0200284 if not ns.quiet and not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200285 print(f"{test_name} skipped -- {msg}", flush=True)
286 return RESOURCE_DENIED
Victor Stinner3844fe52015-09-26 10:38:01 +0200287 except unittest.SkipTest as msg:
Victor Stinnerab983672016-08-22 14:28:52 +0200288 if not ns.quiet and not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200289 print(f"{test_name} skipped -- {msg}", flush=True)
290 return SKIPPED
291 except support.TestFailed as exc:
292 msg = f"test {test_name} failed"
293 if display_failure:
294 msg = f"{msg} -- {exc}"
295 print(msg, file=sys.stderr, flush=True)
296 return FAILED
Pablo Galindo97243482018-11-29 17:17:44 +0000297 except support.TestDidNotRun:
Victor Stinner4d299832019-04-26 04:08:53 +0200298 return TEST_DID_NOT_RUN
299 except KeyboardInterrupt:
Victor Stinner3cde4402019-04-26 08:40:25 +0200300 print()
Victor Stinner4d299832019-04-26 04:08:53 +0200301 return INTERRUPTED
Victor Stinner3844fe52015-09-26 10:38:01 +0200302 except:
Victor Stinnerab983672016-08-22 14:28:52 +0200303 if not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200304 msg = traceback.format_exc()
305 print(f"test {test_name} crashed -- {msg}",
306 file=sys.stderr, flush=True)
307 return FAILED
308
309 if refleak:
310 return FAILED
Victor Stinner532e0632021-03-22 23:52:13 +0100311 if support.environment_altered:
Victor Stinner4d299832019-04-26 04:08:53 +0200312 return ENV_CHANGED
313 return PASSED
Victor Stinner3844fe52015-09-26 10:38:01 +0200314
315
Victor Stinner4d299832019-04-26 04:08:53 +0200316def cleanup_test_droppings(test_name, verbose):
Victor Stinner3844fe52015-09-26 10:38:01 +0200317 # First kill any dangling references to open files etc.
318 # This can also issue some ResourceWarnings which would otherwise get
319 # triggered during the following test run, and possibly produce failures.
Victor Stinner4d299832019-04-26 04:08:53 +0200320 support.gc_collect()
Victor Stinner3844fe52015-09-26 10:38:01 +0200321
322 # Try to clean up junk commonly left behind. While tests shouldn't leave
323 # any files or directories behind, when a test fails that can be tedious
324 # for it to arrange. The consequences can be especially nasty on Windows,
325 # since if a test leaves a file open, it cannot be deleted by name (while
326 # there's nothing we can do about that here either, we can display the
327 # name of the offending test, which is a real help).
Hai Shif7ba40b2020-06-25 18:38:51 +0800328 for name in (os_helper.TESTFN,):
Victor Stinner3844fe52015-09-26 10:38:01 +0200329 if not os.path.exists(name):
330 continue
331
332 if os.path.isdir(name):
Victor Stinner4d299832019-04-26 04:08:53 +0200333 import shutil
Victor Stinner3844fe52015-09-26 10:38:01 +0200334 kind, nuker = "directory", shutil.rmtree
335 elif os.path.isfile(name):
336 kind, nuker = "file", os.unlink
337 else:
Victor Stinner4d299832019-04-26 04:08:53 +0200338 raise RuntimeError(f"os.path says {name!r} exists but is neither "
339 f"directory nor file")
Victor Stinner3844fe52015-09-26 10:38:01 +0200340
341 if verbose:
Victor Stinnerd663d342020-04-23 19:03:52 +0200342 print_warning(f"{test_name} left behind {kind} {name!r}")
Victor Stinner4d299832019-04-26 04:08:53 +0200343 support.environment_altered = True
344
Victor Stinner3844fe52015-09-26 10:38:01 +0200345 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200346 import stat
Anthony Sottile8377cd42019-02-25 14:32:27 -0800347 # fix possible permissions problems that might prevent cleanup
348 os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
Victor Stinner3844fe52015-09-26 10:38:01 +0200349 nuker(name)
Victor Stinner4d299832019-04-26 04:08:53 +0200350 except Exception as exc:
351 print_warning(f"{test_name} left behind {kind} {name!r} "
352 f"and it couldn't be removed: {exc}")