blob: 306beb81fc7a2817c28413206b6f420b8b4b1a57 [file] [log] [blame]
Victor Stinner3844fe52015-09-26 10:38:01 +02001import faulthandler
Victor Stinner3844fe52015-09-26 10:38:01 +02002import os
Victor Stinner3844fe52015-09-26 10:38:01 +02003import platform
Victor Stinnerdad20e42015-09-29 22:48:52 +02004import random
5import re
6import signal
7import sys
8import sysconfig
9import tempfile
10import textwrap
Victor Stinner3844fe52015-09-26 10:38:01 +020011import unittest
12from test.libregrtest.runtest import (
Victor Stinner56e05dd2015-09-29 23:15:38 +020013 findtests, runtest,
14 STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED)
Victor Stinner3844fe52015-09-26 10:38:01 +020015from test.libregrtest.refleak import warm_caches
16from test.libregrtest.cmdline import _parse_args
17from test import support
18try:
Victor Stinnerdad20e42015-09-29 22:48:52 +020019 import gc
20except ImportError:
21 gc = None
Victor Stinner3844fe52015-09-26 10:38:01 +020022
23
Victor Stinner3844fe52015-09-26 10:38:01 +020024# When tests are run from the Python build directory, it is best practice
25# to keep the test files in a subfolder. This eases the cleanup of leftover
26# files using the "make distclean" command.
27if sysconfig.is_python_build():
28 TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
29else:
30 TEMPDIR = tempfile.gettempdir()
31TEMPDIR = os.path.abspath(TEMPDIR)
32
33
Victor Stinnerdad20e42015-09-29 22:48:52 +020034def setup_python():
35 # Display the Python traceback on fatal errors (e.g. segfault)
36 faulthandler.enable(all_threads=True)
37
38 # Display the Python traceback on SIGALRM or SIGUSR1 signal
39 signals = []
40 if hasattr(signal, 'SIGALRM'):
41 signals.append(signal.SIGALRM)
42 if hasattr(signal, 'SIGUSR1'):
43 signals.append(signal.SIGUSR1)
44 for signum in signals:
45 faulthandler.register(signum, chain=True)
46
47 replace_stdout()
48 support.record_original_stdout(sys.stdout)
49
50 # Some times __path__ and __file__ are not absolute (e.g. while running from
51 # Lib/) and, if we change the CWD to run the tests in a temporary dir, some
52 # imports might fail. This affects only the modules imported before os.chdir().
53 # These modules are searched first in sys.path[0] (so '' -- the CWD) and if
54 # they are found in the CWD their __file__ and __path__ will be relative (this
55 # happens before the chdir). All the modules imported after the chdir, are
56 # not found in the CWD, and since the other paths in sys.path[1:] are absolute
57 # (site.py absolutize them), the __file__ and __path__ will be absolute too.
58 # Therefore it is necessary to absolutize manually the __file__ and __path__ of
59 # the packages to prevent later imports to fail when the CWD is different.
60 for module in sys.modules.values():
61 if hasattr(module, '__path__'):
Victor Stinner6448b802015-09-29 23:43:33 +020062 module.__path__ = [os.path.abspath(path)
63 for path in module.__path__]
Victor Stinnerdad20e42015-09-29 22:48:52 +020064 if hasattr(module, '__file__'):
65 module.__file__ = os.path.abspath(module.__file__)
66
67 # MacOSX (a.k.a. Darwin) has a default stack size that is too small
68 # for deeply recursive regular expressions. We see this as crashes in
69 # the Python test suite when running test_re.py and test_sre.py. The
70 # fix is to set the stack limit to 2048.
71 # This approach may also be useful for other Unixy platforms that
72 # suffer from small default stack limits.
73 if sys.platform == 'darwin':
74 try:
75 import resource
76 except ImportError:
77 pass
78 else:
79 soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
80 newsoft = min(hard, max(soft, 1024*2048))
81 resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard))
82
83
84class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020085 """Execute a test suite.
86
87 This also parses command-line options and modifies its behavior
88 accordingly.
89
90 tests -- a list of strings containing test names (optional)
91 testdir -- the directory in which to look for tests (optional)
92
93 Users other than the Python test suite will certainly want to
94 specify testdir; if it's omitted, the directory containing the
95 Python test suite is searched for.
96
97 If the tests argument is omitted, the tests listed on the
98 command-line will be used. If that's empty, too, then all *.py
99 files beginning with test_ will be used.
100
101 The other default arguments (verbose, quiet, exclude,
102 single, randomize, findleaks, use_resources, trace, coverdir,
103 print_slow, and random_seed) allow programmers calling main()
104 directly to set the values that would normally be set by flags
105 on the command line.
106 """
Victor Stinnerdad20e42015-09-29 22:48:52 +0200107 def __init__(self):
108 # Namespace of command line options
109 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200110
Victor Stinnerdad20e42015-09-29 22:48:52 +0200111 # tests
112 self.tests = []
113 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200114
Victor Stinnerdad20e42015-09-29 22:48:52 +0200115 # test results
116 self.good = []
117 self.bad = []
118 self.skipped = []
119 self.resource_denieds = []
120 self.environment_changed = []
121 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +0200122
Victor Stinnerdad20e42015-09-29 22:48:52 +0200123 # used by --slow
124 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200125
Victor Stinnerdad20e42015-09-29 22:48:52 +0200126 # used by --coverage, trace.Trace instance
127 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200128
Victor Stinnerdad20e42015-09-29 22:48:52 +0200129 # used by --findleaks, store for gc.garbage
130 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200131
Victor Stinnerdad20e42015-09-29 22:48:52 +0200132 # used to display the progress bar "[ 3/100]"
133 self.test_count = ''
134 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +0200135
Victor Stinnerdad20e42015-09-29 22:48:52 +0200136 # used by --single
137 self.next_single_test = None
138 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200139
Victor Stinnerdad20e42015-09-29 22:48:52 +0200140 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +0200141 ok, test_time = result
Victor Stinnerdad20e42015-09-29 22:48:52 +0200142 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +0200143 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200144 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200145 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200146 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200147 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200148 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200149 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200150 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200151 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200152 self.skipped.append(test)
153 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200154
Victor Stinnerdad20e42015-09-29 22:48:52 +0200155 def display_progress(self, test_index, test):
156 if self.ns.quiet:
157 return
158 fmt = "[{1:{0}}{2}/{3}] {4}" if self.bad else "[{1:{0}}{2}] {4}"
Victor Stinner6448b802015-09-29 23:43:33 +0200159 print(fmt.format(self.test_count_width, test_index,
160 self.test_count, len(self.bad), test))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200161 sys.stdout.flush()
Victor Stinner3844fe52015-09-26 10:38:01 +0200162
Victor Stinnerdad20e42015-09-29 22:48:52 +0200163 def setup_regrtest(self):
164 if self.ns.huntrleaks:
165 # Avoid false positives due to various caches
166 # filling slowly with random data:
167 warm_caches()
168
169 if self.ns.memlimit is not None:
170 support.set_memlimit(self.ns.memlimit)
171
172 if self.ns.threshold is not None:
173 if gc is not None:
174 gc.set_threshold(self.ns.threshold)
175 else:
176 print('No GC available, ignore --threshold.')
177
178 if self.ns.nowindows:
179 import msvcrt
180 msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
181 msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
182 msvcrt.SEM_NOGPFAULTERRORBOX|
183 msvcrt.SEM_NOOPENFILEERRORBOX)
184 try:
185 msvcrt.CrtSetReportMode
186 except AttributeError:
187 # release build
188 pass
189 else:
190 for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
191 msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
192 msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
193
194 if self.ns.findleaks:
195 if gc is not None:
196 # Uncomment the line below to report garbage that is not
197 # freeable by reference counting alone. By default only
198 # garbage that is not collectable by the GC is reported.
199 pass
200 #gc.set_debug(gc.DEBUG_SAVEALL)
201 else:
202 print('No GC available, disabling --findleaks')
203 self.ns.findleaks = False
204
205 if self.ns.huntrleaks:
206 unittest.BaseTestSuite._cleanup = False
207
208 # Strip .py extensions.
209 removepy(self.ns.args)
210
211 if self.ns.trace:
212 import trace
213 self.tracer = trace.Trace(ignoredirs=[sys.base_prefix,
214 sys.base_exec_prefix,
215 tempfile.gettempdir()],
216 trace=False, count=True)
217
218 def find_tests(self, tests):
219 self.tests = tests
220
221 if self.ns.single:
222 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
223 try:
224 with open(self.next_single_filename, 'r') as fp:
225 next_test = fp.read().strip()
226 self.tests = [next_test]
227 except OSError:
228 pass
229
230 if self.ns.fromfile:
231 self.tests = []
232 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
233 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
234 for line in fp:
235 line = count_pat.sub('', line)
236 guts = line.split() # assuming no test has whitespace in its name
237 if guts and not guts[0].startswith('#'):
238 self.tests.extend(guts)
239
240 removepy(self.tests)
241
242 stdtests = STDTESTS[:]
243 nottests = NOTTESTS.copy()
244 if self.ns.exclude:
245 for arg in self.ns.args:
246 if arg in stdtests:
247 stdtests.remove(arg)
248 nottests.add(arg)
249 self.ns.args = []
250
251 # For a partial run, we do not need to clutter the output.
Victor Stinner6448b802015-09-29 23:43:33 +0200252 if (self.ns.verbose
253 or self.ns.header
254 or not (self.ns.quiet or self.ns.single
255 or self.tests or self.ns.args)):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200256 # Print basic platform information
257 print("==", platform.python_implementation(), *sys.version.split())
258 print("== ", platform.platform(aliased=True),
259 "%s-endian" % sys.byteorder)
260 print("== ", "hash algorithm:", sys.hash_info.algorithm,
261 "64bit" if sys.maxsize > 2**32 else "32bit")
262 print("== ", os.getcwd())
263 print("Testing with flags:", sys.flags)
264
265 # if testdir is set, then we are not running the python tests suite, so
266 # don't add default tests to be executed or skipped (pass empty values)
267 if self.ns.testdir:
268 alltests = findtests(self.ns.testdir, list(), set())
269 else:
270 alltests = findtests(self.ns.testdir, stdtests, nottests)
271
272 self.selected = self.tests or self.ns.args or alltests
273 if self.ns.single:
274 self.selected = self.selected[:1]
275 try:
276 pos = alltests.index(self.selected[0])
277 self.next_single_test = alltests[pos + 1]
278 except IndexError:
279 pass
280
281 # Remove all the self.selected tests that precede start if it's set.
282 if self.ns.start:
283 try:
284 del self.selected[:self.selected.index(self.ns.start)]
285 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200286 print("Couldn't find starting test (%s), using all tests"
287 % self.ns.start)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200288
289 if self.ns.randomize:
290 if self.ns.random_seed is None:
291 self.ns.random_seed = random.randrange(10000000)
292 random.seed(self.ns.random_seed)
293 print("Using random seed", self.ns.random_seed)
294 random.shuffle(self.selected)
295
296 def display_result(self):
297 if self.interrupted:
298 # print a newline after ^C
299 print()
300 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200301 executed = set(self.good) | set(self.bad) | set(self.skipped)
302 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200303 print(count(len(omitted), "test"), "omitted:")
304 printlist(omitted)
305
306 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200307 if (not self.bad
308 and not self.skipped
309 and not self.interrupted
310 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200311 print("All", end=' ')
312 print(count(len(self.good), "test"), "OK.")
313
314 if self.ns.print_slow:
315 self.test_times.sort(reverse=True)
316 print("10 slowest tests:")
317 for time, test in self.test_times[:10]:
318 print("%s: %.1fs" % (test, time))
319
320 if self.bad:
321 print(count(len(self.bad), "test"), "failed:")
322 printlist(self.bad)
323
324 if self.environment_changed:
325 print("{} altered the execution environment:".format(
326 count(len(self.environment_changed), "test")))
327 printlist(self.environment_changed)
328
329 if self.skipped and not self.ns.quiet:
330 print(count(len(self.skipped), "test"), "skipped:")
331 printlist(self.skipped)
332
333 if self.ns.verbose2 and self.bad:
334 print("Re-running failed tests in verbose mode")
335 for test in self.bad[:]:
336 print("Re-running test %r in verbose mode" % test)
337 sys.stdout.flush()
338 try:
339 self.ns.verbose = True
340 ok = runtest(test, True, self.ns.quiet, self.ns.huntrleaks,
341 timeout=self.ns.timeout)
342 except KeyboardInterrupt:
343 # print a newline separate from the ^C
344 print()
345 break
346 else:
347 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
348 self.bad.remove(test)
349 else:
350 if self.bad:
351 print(count(len(self.bad), 'test'), "failed again:")
352 printlist(self.bad)
353
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200354 def run_test(self, test):
355 result = runtest(test,
356 self.ns.verbose,
357 self.ns.quiet,
358 self.ns.huntrleaks,
359 output_on_failure=self.ns.verbose3,
360 timeout=self.ns.timeout,
361 failfast=self.ns.failfast,
362 match_tests=self.ns.match_tests)
363 self.accumulate_result(test, result)
364
365 def run_tests_sequential(self):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200366 save_modules = sys.modules.keys()
367
368 for test_index, test in enumerate(self.tests, 1):
369 self.display_progress(test_index, test)
370 if self.ns.trace:
Victor Stinner3844fe52015-09-26 10:38:01 +0200371 # If we're tracing code coverage, then we don't exit with status
372 # if on a false return value from main.
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200373 cmd = 'self.run_test(test)'
Victor Stinnerdad20e42015-09-29 22:48:52 +0200374 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200375 else:
376 try:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200377 self.run_test(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200378 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200379 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200380 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200381
Victor Stinnerdad20e42015-09-29 22:48:52 +0200382 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200383 gc.collect()
384 if gc.garbage:
385 print("Warning: test created", len(gc.garbage), end=' ')
386 print("uncollectable object(s).")
387 # move the uncollectable objects somewhere so we don't see
388 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200389 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200390 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200391
Victor Stinner3844fe52015-09-26 10:38:01 +0200392 # Unload the newly imported modules (best effort finalization)
393 for module in sys.modules.keys():
394 if module not in save_modules and module.startswith("test."):
395 support.unload(module)
396
Victor Stinnerdad20e42015-09-29 22:48:52 +0200397 def run_tests(self):
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200398 support.verbose = self.ns.verbose # Tell tests to be moderately quiet
Victor Stinnerdad20e42015-09-29 22:48:52 +0200399 support.use_resources = self.ns.use_resources
Victor Stinner3844fe52015-09-26 10:38:01 +0200400
Victor Stinnerdad20e42015-09-29 22:48:52 +0200401 if self.ns.forever:
402 def test_forever(tests):
403 while True:
404 for test in tests:
405 yield test
406 if self.bad:
407 return
408 self.tests = test_forever(list(self.selected))
409 self.test_count = ''
410 self.test_count_width = 3
411 else:
412 self.tests = iter(self.selected)
413 self.test_count = '/{}'.format(len(self.selected))
414 self.test_count_width = len(self.test_count) - 1
415
416 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200417 from test.libregrtest.runtest_mp import run_tests_multiprocess
418 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200419 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200420 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200421
422 def finalize(self):
423 if self.next_single_filename:
424 if self.next_single_test:
425 with open(self.next_single_filename, 'w') as fp:
426 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200427 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200428 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200429
Victor Stinnerdad20e42015-09-29 22:48:52 +0200430 if self.ns.trace:
431 r = self.tracer.results()
432 r.write_results(show_missing=True, summary=True,
433 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200434
Victor Stinnerdad20e42015-09-29 22:48:52 +0200435 if self.ns.runleaks:
436 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200437
Victor Stinnerdad20e42015-09-29 22:48:52 +0200438 def main(self, tests=None, **kwargs):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200439 self.ns = _parse_args(sys.argv[1:], **kwargs)
Victor Stinner37554522015-09-29 23:37:14 +0200440 setup_python()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200441 self.setup_regrtest()
442 if self.ns.wait:
443 input("Press any key to continue...")
444 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200445 from test.libregrtest.runtest_mp import run_tests_slave
446 run_tests_slave(self.ns.slaveargs)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200447 self.find_tests(tests)
448 self.run_tests()
449 self.display_result()
450 self.finalize()
451 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200452
453
Victor Stinner3844fe52015-09-26 10:38:01 +0200454def replace_stdout():
455 """Set stdout encoder error handler to backslashreplace (as stderr error
456 handler) to avoid UnicodeEncodeError when printing a traceback"""
457 import atexit
458
459 stdout = sys.stdout
460 sys.stdout = open(stdout.fileno(), 'w',
461 encoding=stdout.encoding,
462 errors="backslashreplace",
463 closefd=False,
464 newline='\n')
465
466 def restore_stdout():
467 sys.stdout.close()
468 sys.stdout = stdout
469 atexit.register(restore_stdout)
470
471
472def removepy(names):
473 if not names:
474 return
475 for idx, name in enumerate(names):
476 basename, ext = os.path.splitext(name)
477 if ext == '.py':
478 names[idx] = basename
479
480
481def count(n, word):
482 if n == 1:
483 return "%d %s" % (n, word)
484 else:
485 return "%d %ss" % (n, word)
486
487
488def printlist(x, width=70, indent=4):
489 """Print the elements of iterable x to stdout.
490
491 Optional arg width (default 70) is the maximum line length.
492 Optional arg indent (default 4) is the number of blanks with which to
493 begin each line.
494 """
495
Victor Stinner3844fe52015-09-26 10:38:01 +0200496 blanks = ' ' * indent
497 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200498 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
499 initial_indent=blanks, subsequent_indent=blanks))
500
501
502def main(tests=None, **kwargs):
503 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200504
505
506def main_in_temp_cwd():
507 """Run main() in a temporary working directory."""
508 if sysconfig.is_python_build():
509 try:
510 os.mkdir(TEMPDIR)
511 except FileExistsError:
512 pass
513
514 # Define a writable temp dir that will be used as cwd while running
515 # the tests. The name of the dir includes the pid to allow parallel
516 # testing (see the -j option).
517 test_cwd = 'test_python_{}'.format(os.getpid())
518 test_cwd = os.path.join(TEMPDIR, test_cwd)
519
520 # Run the tests in a context manager that temporarily changes the CWD to a
521 # temporary and writable directory. If it's not possible to create or
522 # change the CWD, the original CWD will be used. The original CWD is
523 # available from support.SAVEDCWD.
524 with support.temp_cwd(test_cwd, quiet=True):
525 main()