blob: 558f2099c66f5eb5ec180a1b4afb8c78d9b05edc [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
Serhiy Storchaka83910262016-11-11 11:46:44 +020014from test.libregrtest.refleak import dash_R, clear_caches
Victor Stinner3844fe52015-09-26 10:38:01 +020015from test.libregrtest.save_env import saved_test_environment
Victor Stinnerb0c83692019-08-14 14:18:51 +020016from test.libregrtest.utils import format_duration, print_warning
Victor Stinner3844fe52015-09-26 10:38:01 +020017
18
19# Test result constants.
20PASSED = 1
21FAILED = 0
22ENV_CHANGED = -1
23SKIPPED = -2
24RESOURCE_DENIED = -3
25INTERRUPTED = -4
26CHILD_ERROR = -5 # error in a child process
Victor Stinnerb0917df2019-05-13 19:17:54 +020027TEST_DID_NOT_RUN = -6
Victor Stinnerb0c83692019-08-14 14:18:51 +020028TIMEOUT = -7
Victor Stinner3844fe52015-09-26 10:38:01 +020029
Victor Stinner1b8b4232016-05-20 13:37:40 +020030_FORMAT_TEST_RESULT = {
31 PASSED: '%s passed',
32 FAILED: '%s failed',
33 ENV_CHANGED: '%s failed (env changed)',
34 SKIPPED: '%s skipped',
35 RESOURCE_DENIED: '%s skipped (resource denied)',
36 INTERRUPTED: '%s interrupted',
37 CHILD_ERROR: '%s crashed',
Pablo Galindo97243482018-11-29 17:17:44 +000038 TEST_DID_NOT_RUN: '%s run no tests',
Victor Stinnerb0c83692019-08-14 14:18:51 +020039 TIMEOUT: '%s timed out',
Victor Stinner1b8b4232016-05-20 13:37:40 +020040}
41
Victor Stinner69649f22016-03-23 12:14:10 +010042# Minimum duration of a test to display its duration or to mention that
43# the test is running in background
44PROGRESS_MIN_TIME = 30.0 # seconds
45
Victor Stinner3844fe52015-09-26 10:38:01 +020046# small set of tests to determine if we have a basically functioning interpreter
47# (i.e. if any of these fail, then anything else is likely to follow)
48STDTESTS = [
49 'test_grammar',
50 'test_opcodes',
51 'test_dict',
52 'test_builtin',
53 'test_exceptions',
54 'test_types',
55 'test_unittest',
56 'test_doctest',
57 'test_doctest2',
58 'test_support'
59]
60
61# set of tests that we don't want to be executed when using regrtest
62NOTTESTS = set()
63
64
Victor Stinner4d299832019-04-26 04:08:53 +020065# used by --findleaks, store for gc.garbage
Victor Stinner75120d22019-04-26 09:28:53 +020066FOUND_GARBAGE = []
Victor Stinner4d299832019-04-26 04:08:53 +020067
68
Victor Stinnerb0917df2019-05-13 19:17:54 +020069def is_failed(result, ns):
70 ok = result.result
71 if ok in (PASSED, RESOURCE_DENIED, SKIPPED, TEST_DID_NOT_RUN):
72 return False
73 if ok == ENV_CHANGED:
74 return ns.fail_env_changed
75 return True
76
77
Victor Stinner4d299832019-04-26 04:08:53 +020078def format_test_result(result):
79 fmt = _FORMAT_TEST_RESULT.get(result.result, "%s")
Victor Stinnerb0c83692019-08-14 14:18:51 +020080 text = fmt % result.test_name
81 if result.result == TIMEOUT:
82 text = '%s (%s)' % (text, format_duration(result.test_time))
83 return text
Victor Stinner4d299832019-04-26 04:08:53 +020084
85
86def findtestdir(path=None):
87 return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir
Victor Stinner1b8b4232016-05-20 13:37:40 +020088
89
Victor Stinner3844fe52015-09-26 10:38:01 +020090def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
91 """Return a list of all applicable test modules."""
92 testdir = findtestdir(testdir)
93 names = os.listdir(testdir)
94 tests = []
95 others = set(stdtests) | nottests
96 for name in names:
97 mod, ext = os.path.splitext(name)
98 if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
99 tests.append(mod)
100 return stdtests + sorted(tests)
101
102
Victor Stinner4d299832019-04-26 04:08:53 +0200103def get_abs_module(ns, test_name):
104 if test_name.startswith('test.') or ns.testdir:
105 return test_name
mlouielua49c9352017-06-16 17:36:19 +0800106 else:
Victor Stinner4d299832019-04-26 04:08:53 +0200107 # Import it from the test package
108 return 'test.' + test_name
mlouielua49c9352017-06-16 17:36:19 +0800109
110
Victor Stinner4d299832019-04-26 04:08:53 +0200111TestResult = collections.namedtuple('TestResult',
112 'test_name result test_time xml_data')
113
114def _runtest(ns, test_name):
115 # Handle faulthandler timeout, capture stdout+stderr, XML serialization
116 # and measure time.
117
118 output_on_failure = ns.verbose3
119
120 use_timeout = (ns.timeout is not None)
121 if use_timeout:
122 faulthandler.dump_traceback_later(ns.timeout, exit=True)
123
124 start_time = time.perf_counter()
125 try:
Pablo Galindoe0cd8aa2019-11-19 23:46:49 +0000126 support.set_match_tests(ns.match_tests, ns.ignore_tests)
Victor Stinner4d299832019-04-26 04:08:53 +0200127 support.junit_xml_list = xml_list = [] if ns.xmlpath else None
128 if ns.failfast:
129 support.failfast = True
130
131 if output_on_failure:
132 support.verbose = True
133
134 stream = io.StringIO()
135 orig_stdout = sys.stdout
136 orig_stderr = sys.stderr
137 try:
138 sys.stdout = stream
139 sys.stderr = stream
140 result = _runtest_inner(ns, test_name,
141 display_failure=False)
142 if result != PASSED:
143 output = stream.getvalue()
144 orig_stderr.write(output)
145 orig_stderr.flush()
146 finally:
147 sys.stdout = orig_stdout
148 sys.stderr = orig_stderr
149 else:
150 # Tell tests to be moderately quiet
151 support.verbose = ns.verbose
152
153 result = _runtest_inner(ns, test_name,
154 display_failure=not ns.verbose)
155
156 if xml_list:
157 import xml.etree.ElementTree as ET
158 xml_data = [ET.tostring(x).decode('us-ascii') for x in xml_list]
159 else:
160 xml_data = None
161
162 test_time = time.perf_counter() - start_time
163
164 return TestResult(test_name, result, test_time, xml_data)
165 finally:
166 if use_timeout:
167 faulthandler.cancel_dump_traceback_later()
168 support.junit_xml_list = None
169
170
171def runtest(ns, test_name):
Victor Stinner3844fe52015-09-26 10:38:01 +0200172 """Run a single test.
173
Victor Stinnerab983672016-08-22 14:28:52 +0200174 ns -- regrtest namespace of options
Victor Stinner4d299832019-04-26 04:08:53 +0200175 test_name -- the name of the test
Victor Stinner3844fe52015-09-26 10:38:01 +0200176
Steve Dowerd0f49d22018-09-18 09:10:26 -0700177 Returns the tuple (result, test_time, xml_data), where result is one
178 of the constants:
Victor Stinnerab983672016-08-22 14:28:52 +0200179
Victor Stinner4d299832019-04-26 04:08:53 +0200180 INTERRUPTED KeyboardInterrupt
Victor Stinner3844fe52015-09-26 10:38:01 +0200181 RESOURCE_DENIED test skipped because resource denied
182 SKIPPED test skipped for some other reason
183 ENV_CHANGED test failed because it changed the execution environment
184 FAILED test failed
185 PASSED test passed
Pablo Galindo97243482018-11-29 17:17:44 +0000186 EMPTY_TEST_SUITE test ran no subtests.
Victor Stinnerb0c83692019-08-14 14:18:51 +0200187 TIMEOUT test timed out.
Steve Dowerd0f49d22018-09-18 09:10:26 -0700188
189 If ns.xmlpath is not None, xml_data is a list containing each
190 generated testsuite element.
Victor Stinner3844fe52015-09-26 10:38:01 +0200191 """
Victor Stinner3844fe52015-09-26 10:38:01 +0200192 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200193 return _runtest(ns, test_name)
194 except:
195 if not ns.pgo:
196 msg = traceback.format_exc()
197 print(f"test {test_name} crashed -- {msg}",
198 file=sys.stderr, flush=True)
199 return TestResult(test_name, FAILED, 0.0, None)
Victor Stinner3844fe52015-09-26 10:38:01 +0200200
201
Victor Stinner4d299832019-04-26 04:08:53 +0200202def _test_module(the_module):
203 loader = unittest.TestLoader()
204 tests = loader.loadTestsFromModule(the_module)
205 for error in loader.errors:
206 print(error, file=sys.stderr)
207 if loader.errors:
208 raise Exception("errors while loading tests")
209 support.run_unittest(tests)
Victor Stinner3844fe52015-09-26 10:38:01 +0200210
Victor Stinner4d299832019-04-26 04:08:53 +0200211
212def _runtest_inner2(ns, test_name):
213 # Load the test function, run the test function, handle huntrleaks
214 # and findleaks to detect leaks
215
216 abstest = get_abs_module(ns, test_name)
217
218 # remove the module from sys.module to reload it if it was already imported
219 support.unload(abstest)
220
221 the_module = importlib.import_module(abstest)
222
223 # If the test has a test_main, that will run the appropriate
224 # tests. If not, use normal unittest test loading.
225 test_runner = getattr(the_module, "test_main", None)
226 if test_runner is None:
227 test_runner = functools.partial(_test_module, the_module)
228
Victor Stinner3844fe52015-09-26 10:38:01 +0200229 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200230 if ns.huntrleaks:
231 # Return True if the test leaked references
232 refleak = dash_R(ns, test_name, test_runner)
233 else:
234 test_runner()
235 refleak = False
236 finally:
237 cleanup_test_droppings(test_name, ns.verbose)
238
Victor Stinner75120d22019-04-26 09:28:53 +0200239 support.gc_collect()
Victor Stinner4d299832019-04-26 04:08:53 +0200240
Victor Stinner75120d22019-04-26 09:28:53 +0200241 if gc.garbage:
242 support.environment_altered = True
243 print_warning(f"{test_name} created {len(gc.garbage)} "
244 f"uncollectable object(s).")
245
246 # move the uncollectable objects somewhere,
247 # so we don't see them again
248 FOUND_GARBAGE.extend(gc.garbage)
249 gc.garbage.clear()
250
251 support.reap_children()
Victor Stinner4d299832019-04-26 04:08:53 +0200252
253 return refleak
254
255
256def _runtest_inner(ns, test_name, display_failure=True):
257 # Detect environment changes, handle exceptions.
258
259 # Reset the environment_altered flag to detect if a test altered
260 # the environment
261 support.environment_altered = False
262
263 if ns.pgo:
264 display_failure = False
265
266 try:
Serhiy Storchaka83910262016-11-11 11:46:44 +0200267 clear_caches()
Victor Stinner4d299832019-04-26 04:08:53 +0200268
269 with saved_test_environment(test_name, ns.verbose, ns.quiet, pgo=ns.pgo) as environment:
270 refleak = _runtest_inner2(ns, test_name)
Victor Stinner3844fe52015-09-26 10:38:01 +0200271 except support.ResourceDenied as msg:
Victor Stinnerab983672016-08-22 14:28:52 +0200272 if not ns.quiet and not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200273 print(f"{test_name} skipped -- {msg}", flush=True)
274 return RESOURCE_DENIED
Victor Stinner3844fe52015-09-26 10:38:01 +0200275 except unittest.SkipTest as msg:
Victor Stinnerab983672016-08-22 14:28:52 +0200276 if not ns.quiet and not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200277 print(f"{test_name} skipped -- {msg}", flush=True)
278 return SKIPPED
279 except support.TestFailed as exc:
280 msg = f"test {test_name} failed"
281 if display_failure:
282 msg = f"{msg} -- {exc}"
283 print(msg, file=sys.stderr, flush=True)
284 return FAILED
Pablo Galindo97243482018-11-29 17:17:44 +0000285 except support.TestDidNotRun:
Victor Stinner4d299832019-04-26 04:08:53 +0200286 return TEST_DID_NOT_RUN
287 except KeyboardInterrupt:
Victor Stinner3cde4402019-04-26 08:40:25 +0200288 print()
Victor Stinner4d299832019-04-26 04:08:53 +0200289 return INTERRUPTED
Victor Stinner3844fe52015-09-26 10:38:01 +0200290 except:
Victor Stinnerab983672016-08-22 14:28:52 +0200291 if not ns.pgo:
Victor Stinner4d299832019-04-26 04:08:53 +0200292 msg = traceback.format_exc()
293 print(f"test {test_name} crashed -- {msg}",
294 file=sys.stderr, flush=True)
295 return FAILED
296
297 if refleak:
298 return FAILED
299 if environment.changed:
300 return ENV_CHANGED
301 return PASSED
Victor Stinner3844fe52015-09-26 10:38:01 +0200302
303
Victor Stinner4d299832019-04-26 04:08:53 +0200304def cleanup_test_droppings(test_name, verbose):
Victor Stinner3844fe52015-09-26 10:38:01 +0200305 # First kill any dangling references to open files etc.
306 # This can also issue some ResourceWarnings which would otherwise get
307 # triggered during the following test run, and possibly produce failures.
Victor Stinner4d299832019-04-26 04:08:53 +0200308 support.gc_collect()
Victor Stinner3844fe52015-09-26 10:38:01 +0200309
310 # Try to clean up junk commonly left behind. While tests shouldn't leave
311 # any files or directories behind, when a test fails that can be tedious
312 # for it to arrange. The consequences can be especially nasty on Windows,
313 # since if a test leaves a file open, it cannot be deleted by name (while
314 # there's nothing we can do about that here either, we can display the
315 # name of the offending test, which is a real help).
Greg Price455122a2019-09-11 02:25:26 -0700316 for name in (support.TESTFN,):
Victor Stinner3844fe52015-09-26 10:38:01 +0200317 if not os.path.exists(name):
318 continue
319
320 if os.path.isdir(name):
Victor Stinner4d299832019-04-26 04:08:53 +0200321 import shutil
Victor Stinner3844fe52015-09-26 10:38:01 +0200322 kind, nuker = "directory", shutil.rmtree
323 elif os.path.isfile(name):
324 kind, nuker = "file", os.unlink
325 else:
Victor Stinner4d299832019-04-26 04:08:53 +0200326 raise RuntimeError(f"os.path says {name!r} exists but is neither "
327 f"directory nor file")
Victor Stinner3844fe52015-09-26 10:38:01 +0200328
329 if verbose:
Victor Stinner4d299832019-04-26 04:08:53 +0200330 print_warning("%r left behind %s %r" % (test_name, kind, name))
331 support.environment_altered = True
332
Victor Stinner3844fe52015-09-26 10:38:01 +0200333 try:
Victor Stinner4d299832019-04-26 04:08:53 +0200334 import stat
Anthony Sottile8377cd42019-02-25 14:32:27 -0800335 # fix possible permissions problems that might prevent cleanup
336 os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
Victor Stinner3844fe52015-09-26 10:38:01 +0200337 nuker(name)
Victor Stinner4d299832019-04-26 04:08:53 +0200338 except Exception as exc:
339 print_warning(f"{test_name} left behind {kind} {name!r} "
340 f"and it couldn't be removed: {exc}")