blob: 2716536c4f85bdb88df798a87d1b0c1e1b8cb2b9 [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
22try:
Victor Stinner3844fe52015-09-26 10:38:01 +020023 import threading
24except ImportError:
25 threading = None
26
27
Victor Stinner3844fe52015-09-26 10:38:01 +020028# When tests are run from the Python build directory, it is best practice
29# to keep the test files in a subfolder. This eases the cleanup of leftover
30# files using the "make distclean" command.
31if sysconfig.is_python_build():
32 TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
33else:
34 TEMPDIR = tempfile.gettempdir()
35TEMPDIR = os.path.abspath(TEMPDIR)
36
37
Victor Stinnerdad20e42015-09-29 22:48:52 +020038def setup_python():
39 # Display the Python traceback on fatal errors (e.g. segfault)
40 faulthandler.enable(all_threads=True)
41
42 # Display the Python traceback on SIGALRM or SIGUSR1 signal
43 signals = []
44 if hasattr(signal, 'SIGALRM'):
45 signals.append(signal.SIGALRM)
46 if hasattr(signal, 'SIGUSR1'):
47 signals.append(signal.SIGUSR1)
48 for signum in signals:
49 faulthandler.register(signum, chain=True)
50
51 replace_stdout()
52 support.record_original_stdout(sys.stdout)
53
54 # Some times __path__ and __file__ are not absolute (e.g. while running from
55 # Lib/) and, if we change the CWD to run the tests in a temporary dir, some
56 # imports might fail. This affects only the modules imported before os.chdir().
57 # These modules are searched first in sys.path[0] (so '' -- the CWD) and if
58 # they are found in the CWD their __file__ and __path__ will be relative (this
59 # happens before the chdir). All the modules imported after the chdir, are
60 # not found in the CWD, and since the other paths in sys.path[1:] are absolute
61 # (site.py absolutize them), the __file__ and __path__ will be absolute too.
62 # Therefore it is necessary to absolutize manually the __file__ and __path__ of
63 # the packages to prevent later imports to fail when the CWD is different.
64 for module in sys.modules.values():
65 if hasattr(module, '__path__'):
66 module.__path__ = [os.path.abspath(path) for path in module.__path__]
67 if hasattr(module, '__file__'):
68 module.__file__ = os.path.abspath(module.__file__)
69
70 # MacOSX (a.k.a. Darwin) has a default stack size that is too small
71 # for deeply recursive regular expressions. We see this as crashes in
72 # the Python test suite when running test_re.py and test_sre.py. The
73 # fix is to set the stack limit to 2048.
74 # This approach may also be useful for other Unixy platforms that
75 # suffer from small default stack limits.
76 if sys.platform == 'darwin':
77 try:
78 import resource
79 except ImportError:
80 pass
81 else:
82 soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
83 newsoft = min(hard, max(soft, 1024*2048))
84 resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard))
85
86
87class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020088 """Execute a test suite.
89
90 This also parses command-line options and modifies its behavior
91 accordingly.
92
93 tests -- a list of strings containing test names (optional)
94 testdir -- the directory in which to look for tests (optional)
95
96 Users other than the Python test suite will certainly want to
97 specify testdir; if it's omitted, the directory containing the
98 Python test suite is searched for.
99
100 If the tests argument is omitted, the tests listed on the
101 command-line will be used. If that's empty, too, then all *.py
102 files beginning with test_ will be used.
103
104 The other default arguments (verbose, quiet, exclude,
105 single, randomize, findleaks, use_resources, trace, coverdir,
106 print_slow, and random_seed) allow programmers calling main()
107 directly to set the values that would normally be set by flags
108 on the command line.
109 """
Victor Stinnerdad20e42015-09-29 22:48:52 +0200110 def __init__(self):
111 # Namespace of command line options
112 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200113
Victor Stinnerdad20e42015-09-29 22:48:52 +0200114 # tests
115 self.tests = []
116 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200117
Victor Stinnerdad20e42015-09-29 22:48:52 +0200118 # test results
119 self.good = []
120 self.bad = []
121 self.skipped = []
122 self.resource_denieds = []
123 self.environment_changed = []
124 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +0200125
Victor Stinnerdad20e42015-09-29 22:48:52 +0200126 # used by --slow
127 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200128
Victor Stinnerdad20e42015-09-29 22:48:52 +0200129 # used by --coverage, trace.Trace instance
130 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200131
Victor Stinnerdad20e42015-09-29 22:48:52 +0200132 # used by --findleaks, store for gc.garbage
133 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200134
Victor Stinnerdad20e42015-09-29 22:48:52 +0200135 # used to display the progress bar "[ 3/100]"
136 self.test_count = ''
137 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +0200138
Victor Stinnerdad20e42015-09-29 22:48:52 +0200139 # used by --single
140 self.next_single_test = None
141 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200142
Victor Stinnerdad20e42015-09-29 22:48:52 +0200143 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +0200144 ok, test_time = result
Victor Stinnerdad20e42015-09-29 22:48:52 +0200145 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +0200146 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200147 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200148 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200149 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200150 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200151 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200152 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200153 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200154 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200155 self.skipped.append(test)
156 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200157
Victor Stinnerdad20e42015-09-29 22:48:52 +0200158 def display_progress(self, test_index, test):
159 if self.ns.quiet:
160 return
161 fmt = "[{1:{0}}{2}/{3}] {4}" if self.bad else "[{1:{0}}{2}] {4}"
162 print(fmt.format(
163 self.test_count_width, test_index, self.test_count, len(self.bad), test))
164 sys.stdout.flush()
Victor Stinner3844fe52015-09-26 10:38:01 +0200165
Victor Stinnerdad20e42015-09-29 22:48:52 +0200166 def setup_regrtest(self):
167 if self.ns.huntrleaks:
168 # Avoid false positives due to various caches
169 # filling slowly with random data:
170 warm_caches()
171
172 if self.ns.memlimit is not None:
173 support.set_memlimit(self.ns.memlimit)
174
175 if self.ns.threshold is not None:
176 if gc is not None:
177 gc.set_threshold(self.ns.threshold)
178 else:
179 print('No GC available, ignore --threshold.')
180
181 if self.ns.nowindows:
182 import msvcrt
183 msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
184 msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
185 msvcrt.SEM_NOGPFAULTERRORBOX|
186 msvcrt.SEM_NOOPENFILEERRORBOX)
187 try:
188 msvcrt.CrtSetReportMode
189 except AttributeError:
190 # release build
191 pass
192 else:
193 for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
194 msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
195 msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
196
197 if self.ns.findleaks:
198 if gc is not None:
199 # Uncomment the line below to report garbage that is not
200 # freeable by reference counting alone. By default only
201 # garbage that is not collectable by the GC is reported.
202 pass
203 #gc.set_debug(gc.DEBUG_SAVEALL)
204 else:
205 print('No GC available, disabling --findleaks')
206 self.ns.findleaks = False
207
208 if self.ns.huntrleaks:
209 unittest.BaseTestSuite._cleanup = False
210
211 # Strip .py extensions.
212 removepy(self.ns.args)
213
214 if self.ns.trace:
215 import trace
216 self.tracer = trace.Trace(ignoredirs=[sys.base_prefix,
217 sys.base_exec_prefix,
218 tempfile.gettempdir()],
219 trace=False, count=True)
220
221 def find_tests(self, tests):
222 self.tests = tests
223
224 if self.ns.single:
225 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
226 try:
227 with open(self.next_single_filename, 'r') as fp:
228 next_test = fp.read().strip()
229 self.tests = [next_test]
230 except OSError:
231 pass
232
233 if self.ns.fromfile:
234 self.tests = []
235 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
236 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
237 for line in fp:
238 line = count_pat.sub('', line)
239 guts = line.split() # assuming no test has whitespace in its name
240 if guts and not guts[0].startswith('#'):
241 self.tests.extend(guts)
242
243 removepy(self.tests)
244
245 stdtests = STDTESTS[:]
246 nottests = NOTTESTS.copy()
247 if self.ns.exclude:
248 for arg in self.ns.args:
249 if arg in stdtests:
250 stdtests.remove(arg)
251 nottests.add(arg)
252 self.ns.args = []
253
254 # For a partial run, we do not need to clutter the output.
255 if self.ns.verbose or self.ns.header or not (self.ns.quiet or self.ns.single or self.tests or self.ns.args):
256 # 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:
286 print("Couldn't find starting test (%s), using all tests" % self.ns.start)
287
288 if self.ns.randomize:
289 if self.ns.random_seed is None:
290 self.ns.random_seed = random.randrange(10000000)
291 random.seed(self.ns.random_seed)
292 print("Using random seed", self.ns.random_seed)
293 random.shuffle(self.selected)
294
295 def display_result(self):
296 if self.interrupted:
297 # print a newline after ^C
298 print()
299 print("Test suite interrupted by signal SIGINT.")
300 omitted = set(self.selected) - set(self.good) - set(self.bad) - set(self.skipped)
301 print(count(len(omitted), "test"), "omitted:")
302 printlist(omitted)
303
304 if self.good and not self.ns.quiet:
305 if not self.bad and not self.skipped and not self.interrupted and len(self.good) > 1:
306 print("All", end=' ')
307 print(count(len(self.good), "test"), "OK.")
308
309 if self.ns.print_slow:
310 self.test_times.sort(reverse=True)
311 print("10 slowest tests:")
312 for time, test in self.test_times[:10]:
313 print("%s: %.1fs" % (test, time))
314
315 if self.bad:
316 print(count(len(self.bad), "test"), "failed:")
317 printlist(self.bad)
318
319 if self.environment_changed:
320 print("{} altered the execution environment:".format(
321 count(len(self.environment_changed), "test")))
322 printlist(self.environment_changed)
323
324 if self.skipped and not self.ns.quiet:
325 print(count(len(self.skipped), "test"), "skipped:")
326 printlist(self.skipped)
327
328 if self.ns.verbose2 and self.bad:
329 print("Re-running failed tests in verbose mode")
330 for test in self.bad[:]:
331 print("Re-running test %r in verbose mode" % test)
332 sys.stdout.flush()
333 try:
334 self.ns.verbose = True
335 ok = runtest(test, True, self.ns.quiet, self.ns.huntrleaks,
336 timeout=self.ns.timeout)
337 except KeyboardInterrupt:
338 # print a newline separate from the ^C
339 print()
340 break
341 else:
342 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
343 self.bad.remove(test)
344 else:
345 if self.bad:
346 print(count(len(self.bad), 'test'), "failed again:")
347 printlist(self.bad)
348
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200349 def run_test(self, test):
350 result = runtest(test,
351 self.ns.verbose,
352 self.ns.quiet,
353 self.ns.huntrleaks,
354 output_on_failure=self.ns.verbose3,
355 timeout=self.ns.timeout,
356 failfast=self.ns.failfast,
357 match_tests=self.ns.match_tests)
358 self.accumulate_result(test, result)
359
360 def run_tests_sequential(self):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200361 save_modules = sys.modules.keys()
362
363 for test_index, test in enumerate(self.tests, 1):
364 self.display_progress(test_index, test)
365 if self.ns.trace:
Victor Stinner3844fe52015-09-26 10:38:01 +0200366 # If we're tracing code coverage, then we don't exit with status
367 # if on a false return value from main.
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200368 cmd = 'self.run_test(test)'
Victor Stinnerdad20e42015-09-29 22:48:52 +0200369 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200370 else:
371 try:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200372 self.run_test(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200373 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200374 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200375 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200376
Victor Stinnerdad20e42015-09-29 22:48:52 +0200377 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200378 gc.collect()
379 if gc.garbage:
380 print("Warning: test created", len(gc.garbage), end=' ')
381 print("uncollectable object(s).")
382 # move the uncollectable objects somewhere so we don't see
383 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200384 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200385 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200386
Victor Stinner3844fe52015-09-26 10:38:01 +0200387 # Unload the newly imported modules (best effort finalization)
388 for module in sys.modules.keys():
389 if module not in save_modules and module.startswith("test."):
390 support.unload(module)
391
Victor Stinnerdad20e42015-09-29 22:48:52 +0200392 def run_tests(self):
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200393 support.verbose = self.ns.verbose # Tell tests to be moderately quiet
Victor Stinnerdad20e42015-09-29 22:48:52 +0200394 support.use_resources = self.ns.use_resources
Victor Stinner3844fe52015-09-26 10:38:01 +0200395
Victor Stinnerdad20e42015-09-29 22:48:52 +0200396 if self.ns.forever:
397 def test_forever(tests):
398 while True:
399 for test in tests:
400 yield test
401 if self.bad:
402 return
403 self.tests = test_forever(list(self.selected))
404 self.test_count = ''
405 self.test_count_width = 3
406 else:
407 self.tests = iter(self.selected)
408 self.test_count = '/{}'.format(len(self.selected))
409 self.test_count_width = len(self.test_count) - 1
410
411 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200412 from test.libregrtest.runtest_mp import run_tests_multiprocess
413 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200414 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200415 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200416
417 def finalize(self):
418 if self.next_single_filename:
419 if self.next_single_test:
420 with open(self.next_single_filename, 'w') as fp:
421 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200422 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200423 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200424
Victor Stinnerdad20e42015-09-29 22:48:52 +0200425 if self.ns.trace:
426 r = self.tracer.results()
427 r.write_results(show_missing=True, summary=True,
428 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200429
Victor Stinnerdad20e42015-09-29 22:48:52 +0200430 if self.ns.runleaks:
431 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200432
Victor Stinnerdad20e42015-09-29 22:48:52 +0200433 def main(self, tests=None, **kwargs):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200434 self.ns = _parse_args(sys.argv[1:], **kwargs)
Victor Stinner37554522015-09-29 23:37:14 +0200435 setup_python()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200436 self.setup_regrtest()
437 if self.ns.wait:
438 input("Press any key to continue...")
439 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200440 from test.libregrtest.runtest_mp import run_tests_slave
441 run_tests_slave(self.ns.slaveargs)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200442 self.find_tests(tests)
443 self.run_tests()
444 self.display_result()
445 self.finalize()
446 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200447
448
Victor Stinner3844fe52015-09-26 10:38:01 +0200449def replace_stdout():
450 """Set stdout encoder error handler to backslashreplace (as stderr error
451 handler) to avoid UnicodeEncodeError when printing a traceback"""
452 import atexit
453
454 stdout = sys.stdout
455 sys.stdout = open(stdout.fileno(), 'w',
456 encoding=stdout.encoding,
457 errors="backslashreplace",
458 closefd=False,
459 newline='\n')
460
461 def restore_stdout():
462 sys.stdout.close()
463 sys.stdout = stdout
464 atexit.register(restore_stdout)
465
466
467def removepy(names):
468 if not names:
469 return
470 for idx, name in enumerate(names):
471 basename, ext = os.path.splitext(name)
472 if ext == '.py':
473 names[idx] = basename
474
475
476def count(n, word):
477 if n == 1:
478 return "%d %s" % (n, word)
479 else:
480 return "%d %ss" % (n, word)
481
482
483def printlist(x, width=70, indent=4):
484 """Print the elements of iterable x to stdout.
485
486 Optional arg width (default 70) is the maximum line length.
487 Optional arg indent (default 4) is the number of blanks with which to
488 begin each line.
489 """
490
Victor Stinner3844fe52015-09-26 10:38:01 +0200491 blanks = ' ' * indent
492 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200493 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
494 initial_indent=blanks, subsequent_indent=blanks))
495
496
497def main(tests=None, **kwargs):
498 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200499
500
501def main_in_temp_cwd():
502 """Run main() in a temporary working directory."""
503 if sysconfig.is_python_build():
504 try:
505 os.mkdir(TEMPDIR)
506 except FileExistsError:
507 pass
508
509 # Define a writable temp dir that will be used as cwd while running
510 # the tests. The name of the dir includes the pid to allow parallel
511 # testing (see the -j option).
512 test_cwd = 'test_python_{}'.format(os.getpid())
513 test_cwd = os.path.join(TEMPDIR, test_cwd)
514
515 # Run the tests in a context manager that temporarily changes the CWD to a
516 # temporary and writable directory. If it's not possible to create or
517 # change the CWD, the original CWD will be used. The original CWD is
518 # available from support.SAVEDCWD.
519 with support.temp_cwd(test_cwd, quiet=True):
520 main()