blob: ee1591df5f8b4fd64f7a47b08d0b64869199a4ff [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__'):
Victor Stinner6448b802015-09-29 23:43:33 +020066 module.__path__ = [os.path.abspath(path)
67 for path in module.__path__]
Victor Stinnerdad20e42015-09-29 22:48:52 +020068 if hasattr(module, '__file__'):
69 module.__file__ = os.path.abspath(module.__file__)
70
71 # MacOSX (a.k.a. Darwin) has a default stack size that is too small
72 # for deeply recursive regular expressions. We see this as crashes in
73 # the Python test suite when running test_re.py and test_sre.py. The
74 # fix is to set the stack limit to 2048.
75 # This approach may also be useful for other Unixy platforms that
76 # suffer from small default stack limits.
77 if sys.platform == 'darwin':
78 try:
79 import resource
80 except ImportError:
81 pass
82 else:
83 soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
84 newsoft = min(hard, max(soft, 1024*2048))
85 resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard))
86
87
88class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020089 """Execute a test suite.
90
91 This also parses command-line options and modifies its behavior
92 accordingly.
93
94 tests -- a list of strings containing test names (optional)
95 testdir -- the directory in which to look for tests (optional)
96
97 Users other than the Python test suite will certainly want to
98 specify testdir; if it's omitted, the directory containing the
99 Python test suite is searched for.
100
101 If the tests argument is omitted, the tests listed on the
102 command-line will be used. If that's empty, too, then all *.py
103 files beginning with test_ will be used.
104
105 The other default arguments (verbose, quiet, exclude,
106 single, randomize, findleaks, use_resources, trace, coverdir,
107 print_slow, and random_seed) allow programmers calling main()
108 directly to set the values that would normally be set by flags
109 on the command line.
110 """
Victor Stinnerdad20e42015-09-29 22:48:52 +0200111 def __init__(self):
112 # Namespace of command line options
113 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200114
Victor Stinnerdad20e42015-09-29 22:48:52 +0200115 # tests
116 self.tests = []
117 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200118
Victor Stinnerdad20e42015-09-29 22:48:52 +0200119 # test results
120 self.good = []
121 self.bad = []
122 self.skipped = []
123 self.resource_denieds = []
124 self.environment_changed = []
125 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +0200126
Victor Stinnerdad20e42015-09-29 22:48:52 +0200127 # used by --slow
128 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200129
Victor Stinnerdad20e42015-09-29 22:48:52 +0200130 # used by --coverage, trace.Trace instance
131 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200132
Victor Stinnerdad20e42015-09-29 22:48:52 +0200133 # used by --findleaks, store for gc.garbage
134 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +0200135
Victor Stinnerdad20e42015-09-29 22:48:52 +0200136 # used to display the progress bar "[ 3/100]"
137 self.test_count = ''
138 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +0200139
Victor Stinnerdad20e42015-09-29 22:48:52 +0200140 # used by --single
141 self.next_single_test = None
142 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +0200143
Victor Stinnerdad20e42015-09-29 22:48:52 +0200144 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +0200145 ok, test_time = result
Victor Stinnerdad20e42015-09-29 22:48:52 +0200146 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +0200147 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200148 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200149 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200150 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200151 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200152 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200153 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200154 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200155 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200156 self.skipped.append(test)
157 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200158
Victor Stinnerdad20e42015-09-29 22:48:52 +0200159 def display_progress(self, test_index, test):
160 if self.ns.quiet:
161 return
162 fmt = "[{1:{0}}{2}/{3}] {4}" if self.bad else "[{1:{0}}{2}] {4}"
Victor Stinner6448b802015-09-29 23:43:33 +0200163 print(fmt.format(self.test_count_width, test_index,
164 self.test_count, len(self.bad), test))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200165 sys.stdout.flush()
Victor Stinner3844fe52015-09-26 10:38:01 +0200166
Victor Stinnerdad20e42015-09-29 22:48:52 +0200167 def setup_regrtest(self):
168 if self.ns.huntrleaks:
169 # Avoid false positives due to various caches
170 # filling slowly with random data:
171 warm_caches()
172
173 if self.ns.memlimit is not None:
174 support.set_memlimit(self.ns.memlimit)
175
176 if self.ns.threshold is not None:
177 if gc is not None:
178 gc.set_threshold(self.ns.threshold)
179 else:
180 print('No GC available, ignore --threshold.')
181
182 if self.ns.nowindows:
183 import msvcrt
184 msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
185 msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
186 msvcrt.SEM_NOGPFAULTERRORBOX|
187 msvcrt.SEM_NOOPENFILEERRORBOX)
188 try:
189 msvcrt.CrtSetReportMode
190 except AttributeError:
191 # release build
192 pass
193 else:
194 for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
195 msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
196 msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
197
198 if self.ns.findleaks:
199 if gc is not None:
200 # Uncomment the line below to report garbage that is not
201 # freeable by reference counting alone. By default only
202 # garbage that is not collectable by the GC is reported.
203 pass
204 #gc.set_debug(gc.DEBUG_SAVEALL)
205 else:
206 print('No GC available, disabling --findleaks')
207 self.ns.findleaks = False
208
209 if self.ns.huntrleaks:
210 unittest.BaseTestSuite._cleanup = False
211
212 # Strip .py extensions.
213 removepy(self.ns.args)
214
215 if self.ns.trace:
216 import trace
217 self.tracer = trace.Trace(ignoredirs=[sys.base_prefix,
218 sys.base_exec_prefix,
219 tempfile.gettempdir()],
220 trace=False, count=True)
221
222 def find_tests(self, tests):
223 self.tests = tests
224
225 if self.ns.single:
226 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
227 try:
228 with open(self.next_single_filename, 'r') as fp:
229 next_test = fp.read().strip()
230 self.tests = [next_test]
231 except OSError:
232 pass
233
234 if self.ns.fromfile:
235 self.tests = []
236 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
237 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
238 for line in fp:
239 line = count_pat.sub('', line)
240 guts = line.split() # assuming no test has whitespace in its name
241 if guts and not guts[0].startswith('#'):
242 self.tests.extend(guts)
243
244 removepy(self.tests)
245
246 stdtests = STDTESTS[:]
247 nottests = NOTTESTS.copy()
248 if self.ns.exclude:
249 for arg in self.ns.args:
250 if arg in stdtests:
251 stdtests.remove(arg)
252 nottests.add(arg)
253 self.ns.args = []
254
255 # For a partial run, we do not need to clutter the output.
Victor Stinner6448b802015-09-29 23:43:33 +0200256 if (self.ns.verbose
257 or self.ns.header
258 or not (self.ns.quiet or self.ns.single
259 or self.tests or self.ns.args)):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200260 # Print basic platform information
261 print("==", platform.python_implementation(), *sys.version.split())
262 print("== ", platform.platform(aliased=True),
263 "%s-endian" % sys.byteorder)
264 print("== ", "hash algorithm:", sys.hash_info.algorithm,
265 "64bit" if sys.maxsize > 2**32 else "32bit")
266 print("== ", os.getcwd())
267 print("Testing with flags:", sys.flags)
268
269 # if testdir is set, then we are not running the python tests suite, so
270 # don't add default tests to be executed or skipped (pass empty values)
271 if self.ns.testdir:
272 alltests = findtests(self.ns.testdir, list(), set())
273 else:
274 alltests = findtests(self.ns.testdir, stdtests, nottests)
275
276 self.selected = self.tests or self.ns.args or alltests
277 if self.ns.single:
278 self.selected = self.selected[:1]
279 try:
280 pos = alltests.index(self.selected[0])
281 self.next_single_test = alltests[pos + 1]
282 except IndexError:
283 pass
284
285 # Remove all the self.selected tests that precede start if it's set.
286 if self.ns.start:
287 try:
288 del self.selected[:self.selected.index(self.ns.start)]
289 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200290 print("Couldn't find starting test (%s), using all tests"
291 % self.ns.start)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200292
293 if self.ns.randomize:
294 if self.ns.random_seed is None:
295 self.ns.random_seed = random.randrange(10000000)
296 random.seed(self.ns.random_seed)
297 print("Using random seed", self.ns.random_seed)
298 random.shuffle(self.selected)
299
300 def display_result(self):
301 if self.interrupted:
302 # print a newline after ^C
303 print()
304 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200305 executed = set(self.good) | set(self.bad) | set(self.skipped)
306 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200307 print(count(len(omitted), "test"), "omitted:")
308 printlist(omitted)
309
310 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200311 if (not self.bad
312 and not self.skipped
313 and not self.interrupted
314 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200315 print("All", end=' ')
316 print(count(len(self.good), "test"), "OK.")
317
318 if self.ns.print_slow:
319 self.test_times.sort(reverse=True)
320 print("10 slowest tests:")
321 for time, test in self.test_times[:10]:
322 print("%s: %.1fs" % (test, time))
323
324 if self.bad:
325 print(count(len(self.bad), "test"), "failed:")
326 printlist(self.bad)
327
328 if self.environment_changed:
329 print("{} altered the execution environment:".format(
330 count(len(self.environment_changed), "test")))
331 printlist(self.environment_changed)
332
333 if self.skipped and not self.ns.quiet:
334 print(count(len(self.skipped), "test"), "skipped:")
335 printlist(self.skipped)
336
337 if self.ns.verbose2 and self.bad:
338 print("Re-running failed tests in verbose mode")
339 for test in self.bad[:]:
340 print("Re-running test %r in verbose mode" % test)
341 sys.stdout.flush()
342 try:
343 self.ns.verbose = True
344 ok = runtest(test, True, self.ns.quiet, self.ns.huntrleaks,
345 timeout=self.ns.timeout)
346 except KeyboardInterrupt:
347 # print a newline separate from the ^C
348 print()
349 break
350 else:
351 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
352 self.bad.remove(test)
353 else:
354 if self.bad:
355 print(count(len(self.bad), 'test'), "failed again:")
356 printlist(self.bad)
357
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200358 def run_test(self, test):
359 result = runtest(test,
360 self.ns.verbose,
361 self.ns.quiet,
362 self.ns.huntrleaks,
363 output_on_failure=self.ns.verbose3,
364 timeout=self.ns.timeout,
365 failfast=self.ns.failfast,
366 match_tests=self.ns.match_tests)
367 self.accumulate_result(test, result)
368
369 def run_tests_sequential(self):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200370 save_modules = sys.modules.keys()
371
372 for test_index, test in enumerate(self.tests, 1):
373 self.display_progress(test_index, test)
374 if self.ns.trace:
Victor Stinner3844fe52015-09-26 10:38:01 +0200375 # If we're tracing code coverage, then we don't exit with status
376 # if on a false return value from main.
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200377 cmd = 'self.run_test(test)'
Victor Stinnerdad20e42015-09-29 22:48:52 +0200378 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200379 else:
380 try:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200381 self.run_test(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200382 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200383 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200384 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200385
Victor Stinnerdad20e42015-09-29 22:48:52 +0200386 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200387 gc.collect()
388 if gc.garbage:
389 print("Warning: test created", len(gc.garbage), end=' ')
390 print("uncollectable object(s).")
391 # move the uncollectable objects somewhere so we don't see
392 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200393 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200394 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200395
Victor Stinner3844fe52015-09-26 10:38:01 +0200396 # Unload the newly imported modules (best effort finalization)
397 for module in sys.modules.keys():
398 if module not in save_modules and module.startswith("test."):
399 support.unload(module)
400
Victor Stinnerdad20e42015-09-29 22:48:52 +0200401 def run_tests(self):
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200402 support.verbose = self.ns.verbose # Tell tests to be moderately quiet
Victor Stinnerdad20e42015-09-29 22:48:52 +0200403 support.use_resources = self.ns.use_resources
Victor Stinner3844fe52015-09-26 10:38:01 +0200404
Victor Stinnerdad20e42015-09-29 22:48:52 +0200405 if self.ns.forever:
406 def test_forever(tests):
407 while True:
408 for test in tests:
409 yield test
410 if self.bad:
411 return
412 self.tests = test_forever(list(self.selected))
413 self.test_count = ''
414 self.test_count_width = 3
415 else:
416 self.tests = iter(self.selected)
417 self.test_count = '/{}'.format(len(self.selected))
418 self.test_count_width = len(self.test_count) - 1
419
420 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200421 from test.libregrtest.runtest_mp import run_tests_multiprocess
422 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200423 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200424 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200425
426 def finalize(self):
427 if self.next_single_filename:
428 if self.next_single_test:
429 with open(self.next_single_filename, 'w') as fp:
430 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200431 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200432 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200433
Victor Stinnerdad20e42015-09-29 22:48:52 +0200434 if self.ns.trace:
435 r = self.tracer.results()
436 r.write_results(show_missing=True, summary=True,
437 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200438
Victor Stinnerdad20e42015-09-29 22:48:52 +0200439 if self.ns.runleaks:
440 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200441
Victor Stinnerdad20e42015-09-29 22:48:52 +0200442 def main(self, tests=None, **kwargs):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200443 self.ns = _parse_args(sys.argv[1:], **kwargs)
Victor Stinner37554522015-09-29 23:37:14 +0200444 setup_python()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200445 self.setup_regrtest()
446 if self.ns.wait:
447 input("Press any key to continue...")
448 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200449 from test.libregrtest.runtest_mp import run_tests_slave
450 run_tests_slave(self.ns.slaveargs)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200451 self.find_tests(tests)
452 self.run_tests()
453 self.display_result()
454 self.finalize()
455 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200456
457
Victor Stinner3844fe52015-09-26 10:38:01 +0200458def replace_stdout():
459 """Set stdout encoder error handler to backslashreplace (as stderr error
460 handler) to avoid UnicodeEncodeError when printing a traceback"""
461 import atexit
462
463 stdout = sys.stdout
464 sys.stdout = open(stdout.fileno(), 'w',
465 encoding=stdout.encoding,
466 errors="backslashreplace",
467 closefd=False,
468 newline='\n')
469
470 def restore_stdout():
471 sys.stdout.close()
472 sys.stdout = stdout
473 atexit.register(restore_stdout)
474
475
476def removepy(names):
477 if not names:
478 return
479 for idx, name in enumerate(names):
480 basename, ext = os.path.splitext(name)
481 if ext == '.py':
482 names[idx] = basename
483
484
485def count(n, word):
486 if n == 1:
487 return "%d %s" % (n, word)
488 else:
489 return "%d %ss" % (n, word)
490
491
492def printlist(x, width=70, indent=4):
493 """Print the elements of iterable x to stdout.
494
495 Optional arg width (default 70) is the maximum line length.
496 Optional arg indent (default 4) is the number of blanks with which to
497 begin each line.
498 """
499
Victor Stinner3844fe52015-09-26 10:38:01 +0200500 blanks = ' ' * indent
501 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200502 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
503 initial_indent=blanks, subsequent_indent=blanks))
504
505
506def main(tests=None, **kwargs):
507 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200508
509
510def main_in_temp_cwd():
511 """Run main() in a temporary working directory."""
512 if sysconfig.is_python_build():
513 try:
514 os.mkdir(TEMPDIR)
515 except FileExistsError:
516 pass
517
518 # Define a writable temp dir that will be used as cwd while running
519 # the tests. The name of the dir includes the pid to allow parallel
520 # testing (see the -j option).
521 test_cwd = 'test_python_{}'.format(os.getpid())
522 test_cwd = os.path.join(TEMPDIR, test_cwd)
523
524 # Run the tests in a context manager that temporarily changes the CWD to a
525 # temporary and writable directory. If it's not possible to create or
526 # change the CWD, the original CWD will be used. The original CWD is
527 # available from support.SAVEDCWD.
528 with support.temp_cwd(test_cwd, quiet=True):
529 main()