blob: b66f045045fb79f2345e44f78799f88b136de7b0 [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 Stinnerdad20e42015-09-29 22:48:52 +0200349 def _run_tests_sequential(self):
350 save_modules = sys.modules.keys()
351
352 for test_index, test in enumerate(self.tests, 1):
353 self.display_progress(test_index, test)
354 if self.ns.trace:
Victor Stinner3844fe52015-09-26 10:38:01 +0200355 # If we're tracing code coverage, then we don't exit with status
356 # if on a false return value from main.
Victor Stinnerdad20e42015-09-29 22:48:52 +0200357 cmd = 'runtest(test, self.ns.verbose, self.ns.quiet, timeout=self.ns.timeout)'
358 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200359 else:
360 try:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200361 result = runtest(test, self.ns.verbose, self.ns.quiet,
362 self.ns.huntrleaks,
363 output_on_failure=self.ns.verbose3,
364 timeout=self.ns.timeout, failfast=self.ns.failfast,
365 match_tests=self.ns.match_tests)
366 self.accumulate_result(test, result)
Victor Stinner3844fe52015-09-26 10:38:01 +0200367 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200368 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200369 break
Victor Stinnerdad20e42015-09-29 22:48:52 +0200370 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200371 gc.collect()
372 if gc.garbage:
373 print("Warning: test created", len(gc.garbage), end=' ')
374 print("uncollectable object(s).")
375 # move the uncollectable objects somewhere so we don't see
376 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200377 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200378 del gc.garbage[:]
379 # Unload the newly imported modules (best effort finalization)
380 for module in sys.modules.keys():
381 if module not in save_modules and module.startswith("test."):
382 support.unload(module)
383
Victor Stinnerdad20e42015-09-29 22:48:52 +0200384 def run_tests(self):
385 support.verbose = self.ns.verbose # Tell tests to be moderately quiet
386 support.use_resources = self.ns.use_resources
Victor Stinner3844fe52015-09-26 10:38:01 +0200387
Victor Stinnerdad20e42015-09-29 22:48:52 +0200388 if self.ns.forever:
389 def test_forever(tests):
390 while True:
391 for test in tests:
392 yield test
393 if self.bad:
394 return
395 self.tests = test_forever(list(self.selected))
396 self.test_count = ''
397 self.test_count_width = 3
398 else:
399 self.tests = iter(self.selected)
400 self.test_count = '/{}'.format(len(self.selected))
401 self.test_count_width = len(self.test_count) - 1
402
403 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200404 from test.libregrtest.runtest_mp import run_tests_multiprocess
405 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200406 else:
407 self._run_tests_sequential()
408
409 def finalize(self):
410 if self.next_single_filename:
411 if self.next_single_test:
412 with open(self.next_single_filename, 'w') as fp:
413 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200414 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200415 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200416
Victor Stinnerdad20e42015-09-29 22:48:52 +0200417 if self.ns.trace:
418 r = self.tracer.results()
419 r.write_results(show_missing=True, summary=True,
420 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200421
Victor Stinnerdad20e42015-09-29 22:48:52 +0200422 if self.ns.runleaks:
423 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200424
Victor Stinnerdad20e42015-09-29 22:48:52 +0200425 def main(self, tests=None, **kwargs):
426 setup_python()
427 self.ns = _parse_args(sys.argv[1:], **kwargs)
428 self.setup_regrtest()
429 if self.ns.wait:
430 input("Press any key to continue...")
431 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200432 from test.libregrtest.runtest_mp import run_tests_slave
433 run_tests_slave(self.ns.slaveargs)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200434 self.find_tests(tests)
435 self.run_tests()
436 self.display_result()
437 self.finalize()
438 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200439
440
Victor Stinner3844fe52015-09-26 10:38:01 +0200441def replace_stdout():
442 """Set stdout encoder error handler to backslashreplace (as stderr error
443 handler) to avoid UnicodeEncodeError when printing a traceback"""
444 import atexit
445
446 stdout = sys.stdout
447 sys.stdout = open(stdout.fileno(), 'w',
448 encoding=stdout.encoding,
449 errors="backslashreplace",
450 closefd=False,
451 newline='\n')
452
453 def restore_stdout():
454 sys.stdout.close()
455 sys.stdout = stdout
456 atexit.register(restore_stdout)
457
458
459def removepy(names):
460 if not names:
461 return
462 for idx, name in enumerate(names):
463 basename, ext = os.path.splitext(name)
464 if ext == '.py':
465 names[idx] = basename
466
467
468def count(n, word):
469 if n == 1:
470 return "%d %s" % (n, word)
471 else:
472 return "%d %ss" % (n, word)
473
474
475def printlist(x, width=70, indent=4):
476 """Print the elements of iterable x to stdout.
477
478 Optional arg width (default 70) is the maximum line length.
479 Optional arg indent (default 4) is the number of blanks with which to
480 begin each line.
481 """
482
Victor Stinner3844fe52015-09-26 10:38:01 +0200483 blanks = ' ' * indent
484 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200485 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
486 initial_indent=blanks, subsequent_indent=blanks))
487
488
489def main(tests=None, **kwargs):
490 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200491
492
493def main_in_temp_cwd():
494 """Run main() in a temporary working directory."""
495 if sysconfig.is_python_build():
496 try:
497 os.mkdir(TEMPDIR)
498 except FileExistsError:
499 pass
500
501 # Define a writable temp dir that will be used as cwd while running
502 # the tests. The name of the dir includes the pid to allow parallel
503 # testing (see the -j option).
504 test_cwd = 'test_python_{}'.format(os.getpid())
505 test_cwd = os.path.join(TEMPDIR, test_cwd)
506
507 # Run the tests in a context manager that temporarily changes the CWD to a
508 # temporary and writable directory. If it's not possible to create or
509 # change the CWD, the original CWD will be used. The original CWD is
510 # available from support.SAVEDCWD.
511 with support.temp_cwd(test_cwd, quiet=True):
512 main()