blob: 82788ad941d95067c1a0a78e706d40c4cf1f10fe [file] [log] [blame]
Victor Stinner5f9d3ac2015-10-03 00:21:12 +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
Victor Stinnerdad20e42015-09-29 22:48:52 +02006import sys
7import sysconfig
8import tempfile
9import textwrap
Victor Stinner3909e582015-10-11 10:37:25 +020010from test.libregrtest.cmdline import _parse_args
Victor Stinner3844fe52015-09-26 10:38:01 +020011from test.libregrtest.runtest import (
Victor Stinner6f20a2e2015-09-30 02:32:11 +020012 findtests, runtest,
Victor Stinner3909e582015-10-11 10:37:25 +020013 STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
14 INTERRUPTED, CHILD_ERROR)
Victor Stinnera2045022015-09-30 02:17:28 +020015from test.libregrtest.setup import setup_tests
Victor Stinner3844fe52015-09-26 10:38:01 +020016from test import support
17try:
Victor Stinnerdad20e42015-09-29 22:48:52 +020018 import gc
19except ImportError:
20 gc = None
Victor Stinner3844fe52015-09-26 10:38:01 +020021
22
Victor Stinner3844fe52015-09-26 10:38:01 +020023# When tests are run from the Python build directory, it is best practice
24# to keep the test files in a subfolder. This eases the cleanup of leftover
25# files using the "make distclean" command.
26if sysconfig.is_python_build():
27 TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
28else:
29 TEMPDIR = tempfile.gettempdir()
30TEMPDIR = os.path.abspath(TEMPDIR)
31
32
Victor Stinnerdad20e42015-09-29 22:48:52 +020033class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020034 """Execute a test suite.
35
36 This also parses command-line options and modifies its behavior
37 accordingly.
38
39 tests -- a list of strings containing test names (optional)
40 testdir -- the directory in which to look for tests (optional)
41
42 Users other than the Python test suite will certainly want to
43 specify testdir; if it's omitted, the directory containing the
44 Python test suite is searched for.
45
46 If the tests argument is omitted, the tests listed on the
47 command-line will be used. If that's empty, too, then all *.py
48 files beginning with test_ will be used.
49
50 The other default arguments (verbose, quiet, exclude,
51 single, randomize, findleaks, use_resources, trace, coverdir,
52 print_slow, and random_seed) allow programmers calling main()
53 directly to set the values that would normally be set by flags
54 on the command line.
55 """
Victor Stinnerdad20e42015-09-29 22:48:52 +020056 def __init__(self):
57 # Namespace of command line options
58 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +020059
Victor Stinnerdad20e42015-09-29 22:48:52 +020060 # tests
61 self.tests = []
62 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +020063
Victor Stinnerdad20e42015-09-29 22:48:52 +020064 # test results
65 self.good = []
66 self.bad = []
67 self.skipped = []
68 self.resource_denieds = []
69 self.environment_changed = []
70 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +020071
Victor Stinnerdad20e42015-09-29 22:48:52 +020072 # used by --slow
73 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +020074
Victor Stinnerdad20e42015-09-29 22:48:52 +020075 # used by --coverage, trace.Trace instance
76 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +020077
Victor Stinnerdad20e42015-09-29 22:48:52 +020078 # used by --findleaks, store for gc.garbage
79 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +020080
Victor Stinnerdad20e42015-09-29 22:48:52 +020081 # used to display the progress bar "[ 3/100]"
82 self.test_count = ''
83 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +020084
Victor Stinnerdad20e42015-09-29 22:48:52 +020085 # used by --single
86 self.next_single_test = None
87 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +020088
Victor Stinnerdad20e42015-09-29 22:48:52 +020089 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +020090 ok, test_time = result
Victor Stinner3909e582015-10-11 10:37:25 +020091 if ok not in (CHILD_ERROR, INTERRUPTED):
92 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +020093 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020094 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020095 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020096 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020097 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020098 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020099 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200100 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200101 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200102 self.skipped.append(test)
103 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200104
Victor Stinnerdad20e42015-09-29 22:48:52 +0200105 def display_progress(self, test_index, test):
106 if self.ns.quiet:
107 return
Brett Cannon11faa212015-10-02 16:20:49 -0700108 if self.bad and not self.ns.pgo:
109 fmt = "[{1:{0}}{2}/{3}] {4}"
110 else:
111 fmt = "[{1:{0}}{2}] {4}"
Victor Stinner6448b802015-09-29 23:43:33 +0200112 print(fmt.format(self.test_count_width, test_index,
Victor Stinnerf33536c2015-09-30 00:48:27 +0200113 self.test_count, len(self.bad), test),
114 flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200115
Victor Stinner234cbef2015-09-30 01:13:53 +0200116 def parse_args(self, kwargs):
117 ns = _parse_args(sys.argv[1:], **kwargs)
118
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200119 if ns.timeout and not hasattr(faulthandler, 'dump_traceback_later'):
120 print("Warning: The timeout option requires "
121 "faulthandler.dump_traceback_later", file=sys.stderr)
122 ns.timeout = None
123
Victor Stinner234cbef2015-09-30 01:13:53 +0200124 if ns.threshold is not None and gc is None:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200125 print('No GC available, ignore --threshold.', file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200126 ns.threshold = None
127
128 if ns.findleaks:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200129 if gc is not None:
130 # Uncomment the line below to report garbage that is not
131 # freeable by reference counting alone. By default only
132 # garbage that is not collectable by the GC is reported.
133 pass
134 #gc.set_debug(gc.DEBUG_SAVEALL)
135 else:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200136 print('No GC available, disabling --findleaks',
137 file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200138 ns.findleaks = False
Victor Stinnerdad20e42015-09-29 22:48:52 +0200139
Victor Stinnerdad20e42015-09-29 22:48:52 +0200140 # Strip .py extensions.
Victor Stinner234cbef2015-09-30 01:13:53 +0200141 removepy(ns.args)
142
143 return ns
Victor Stinnerdad20e42015-09-29 22:48:52 +0200144
Victor Stinnerdad20e42015-09-29 22:48:52 +0200145 def find_tests(self, tests):
146 self.tests = tests
147
148 if self.ns.single:
149 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
150 try:
151 with open(self.next_single_filename, 'r') as fp:
152 next_test = fp.read().strip()
153 self.tests = [next_test]
154 except OSError:
155 pass
156
157 if self.ns.fromfile:
158 self.tests = []
159 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
160 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
161 for line in fp:
162 line = count_pat.sub('', line)
163 guts = line.split() # assuming no test has whitespace in its name
164 if guts and not guts[0].startswith('#'):
165 self.tests.extend(guts)
166
167 removepy(self.tests)
168
169 stdtests = STDTESTS[:]
170 nottests = NOTTESTS.copy()
171 if self.ns.exclude:
172 for arg in self.ns.args:
173 if arg in stdtests:
174 stdtests.remove(arg)
175 nottests.add(arg)
176 self.ns.args = []
177
Victor Stinnerdad20e42015-09-29 22:48:52 +0200178 # if testdir is set, then we are not running the python tests suite, so
179 # don't add default tests to be executed or skipped (pass empty values)
180 if self.ns.testdir:
181 alltests = findtests(self.ns.testdir, list(), set())
182 else:
183 alltests = findtests(self.ns.testdir, stdtests, nottests)
184
185 self.selected = self.tests or self.ns.args or alltests
186 if self.ns.single:
187 self.selected = self.selected[:1]
188 try:
189 pos = alltests.index(self.selected[0])
190 self.next_single_test = alltests[pos + 1]
191 except IndexError:
192 pass
193
Victor Stinnerc7eab052015-09-30 00:59:35 +0200194 # Remove all the selected tests that precede start if it's set.
Victor Stinnerdad20e42015-09-29 22:48:52 +0200195 if self.ns.start:
196 try:
197 del self.selected[:self.selected.index(self.ns.start)]
198 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200199 print("Couldn't find starting test (%s), using all tests"
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200200 % self.ns.start, file=sys.stderr)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200201
202 if self.ns.randomize:
203 if self.ns.random_seed is None:
204 self.ns.random_seed = random.randrange(10000000)
205 random.seed(self.ns.random_seed)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200206 random.shuffle(self.selected)
207
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200208 def list_tests(self):
209 for name in self.selected:
210 print(name)
211
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200212 def rerun_failed_tests(self):
213 self.ns.verbose = True
214 self.ns.failfast = False
215 self.ns.verbose3 = False
216 self.ns.match_tests = None
217
218 print("Re-running failed tests in verbose mode")
219 for test in self.bad[:]:
220 print("Re-running test %r in verbose mode" % test, flush=True)
221 try:
222 self.ns.verbose = True
223 ok = runtest(self.ns, test)
224 except KeyboardInterrupt:
225 # print a newline separate from the ^C
226 print()
227 break
228 else:
229 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
230 self.bad.remove(test)
231 else:
232 if self.bad:
233 print(count(len(self.bad), 'test'), "failed again:")
234 printlist(self.bad)
235
Victor Stinnerdad20e42015-09-29 22:48:52 +0200236 def display_result(self):
237 if self.interrupted:
238 # print a newline after ^C
239 print()
240 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200241 executed = set(self.good) | set(self.bad) | set(self.skipped)
242 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200243 print(count(len(omitted), "test"), "omitted:")
244 printlist(omitted)
245
Brett Cannon11faa212015-10-02 16:20:49 -0700246 # If running the test suite for PGO then no one cares about
247 # results.
248 if self.ns.pgo:
249 return
250
Victor Stinnerdad20e42015-09-29 22:48:52 +0200251 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200252 if (not self.bad
253 and not self.skipped
254 and not self.interrupted
255 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200256 print("All", end=' ')
257 print(count(len(self.good), "test"), "OK.")
258
259 if self.ns.print_slow:
260 self.test_times.sort(reverse=True)
261 print("10 slowest tests:")
262 for time, test in self.test_times[:10]:
263 print("%s: %.1fs" % (test, time))
264
265 if self.bad:
266 print(count(len(self.bad), "test"), "failed:")
267 printlist(self.bad)
268
269 if self.environment_changed:
270 print("{} altered the execution environment:".format(
271 count(len(self.environment_changed), "test")))
272 printlist(self.environment_changed)
273
274 if self.skipped and not self.ns.quiet:
275 print(count(len(self.skipped), "test"), "skipped:")
276 printlist(self.skipped)
277
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200278 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200279 if self.ns.trace:
280 import trace
Victor Stinnera53a8182015-10-01 00:53:09 +0200281 self.tracer = trace.Trace(trace=False, count=True)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200282
Victor Stinnerdad20e42015-09-29 22:48:52 +0200283 save_modules = sys.modules.keys()
284
285 for test_index, test in enumerate(self.tests, 1):
286 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200287 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200288 # If we're tracing code coverage, then we don't exit with status
289 # if on a false return value from main.
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200290 cmd = ('result = runtest(self.ns, test); '
291 'self.accumulate_result(test, result)')
Victor Stinnerdad20e42015-09-29 22:48:52 +0200292 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200293 else:
294 try:
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200295 result = runtest(self.ns, test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200296 except KeyboardInterrupt:
Victor Stinner3909e582015-10-11 10:37:25 +0200297 self.accumulate_result(test, (INTERRUPTED, None))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200298 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200299 break
Victor Stinner3909e582015-10-11 10:37:25 +0200300 else:
301 self.accumulate_result(test, result)
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200302
Victor Stinnerdad20e42015-09-29 22:48:52 +0200303 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200304 gc.collect()
305 if gc.garbage:
306 print("Warning: test created", len(gc.garbage), end=' ')
307 print("uncollectable object(s).")
308 # move the uncollectable objects somewhere so we don't see
309 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200310 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200311 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200312
Victor Stinner3844fe52015-09-26 10:38:01 +0200313 # Unload the newly imported modules (best effort finalization)
314 for module in sys.modules.keys():
315 if module not in save_modules and module.startswith("test."):
316 support.unload(module)
317
Victor Stinnerb4084352015-09-30 02:39:22 +0200318 def _test_forever(self, tests):
319 while True:
320 for test in tests:
321 yield test
322 if self.bad:
323 return
Victor Stinner3844fe52015-09-26 10:38:01 +0200324
Victor Stinnerb4084352015-09-30 02:39:22 +0200325 def run_tests(self):
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200326 # For a partial run, we do not need to clutter the output.
327 if (self.ns.verbose
328 or self.ns.header
Brett Cannon11faa212015-10-02 16:20:49 -0700329 or not (self.ns.pgo or self.ns.quiet or self.ns.single
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200330 or self.tests or self.ns.args)):
331 # Print basic platform information
332 print("==", platform.python_implementation(), *sys.version.split())
333 print("== ", platform.platform(aliased=True),
334 "%s-endian" % sys.byteorder)
335 print("== ", "hash algorithm:", sys.hash_info.algorithm,
336 "64bit" if sys.maxsize > 2**32 else "32bit")
337 print("== ", os.getcwd())
338 print("Testing with flags:", sys.flags)
339
340 if self.ns.randomize:
341 print("Using random seed", self.ns.random_seed)
342
Victor Stinnerdad20e42015-09-29 22:48:52 +0200343 if self.ns.forever:
Victor Stinner9a142142015-09-30 13:51:17 +0200344 self.tests = self._test_forever(list(self.selected))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200345 self.test_count = ''
346 self.test_count_width = 3
347 else:
348 self.tests = iter(self.selected)
349 self.test_count = '/{}'.format(len(self.selected))
350 self.test_count_width = len(self.test_count) - 1
351
352 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200353 from test.libregrtest.runtest_mp import run_tests_multiprocess
354 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200355 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200356 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200357
358 def finalize(self):
359 if self.next_single_filename:
360 if self.next_single_test:
361 with open(self.next_single_filename, 'w') as fp:
362 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200363 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200364 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200365
Victor Stinnerc7eab052015-09-30 00:59:35 +0200366 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200367 r = self.tracer.results()
368 r.write_results(show_missing=True, summary=True,
369 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200370
Victor Stinnerdad20e42015-09-29 22:48:52 +0200371 if self.ns.runleaks:
372 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200373
Victor Stinnerdad20e42015-09-29 22:48:52 +0200374 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200375 self.ns = self.parse_args(kwargs)
376
Victor Stinnerdad20e42015-09-29 22:48:52 +0200377 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200378 from test.libregrtest.runtest_mp import run_tests_slave
379 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200380
Victor Stinnerc7eab052015-09-30 00:59:35 +0200381 if self.ns.wait:
382 input("Press any key to continue...")
383
Victor Stinnera2045022015-09-30 02:17:28 +0200384 setup_tests(self.ns)
Victor Stinnerecef6222015-09-30 01:39:28 +0200385
Victor Stinnerdad20e42015-09-29 22:48:52 +0200386 self.find_tests(tests)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200387
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200388 if self.ns.list_tests:
389 self.list_tests()
390 sys.exit(0)
391
392 self.run_tests()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200393 self.display_result()
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200394
395 if self.ns.verbose2 and self.bad:
396 self.rerun_failed_tests()
397
Victor Stinnerdad20e42015-09-29 22:48:52 +0200398 self.finalize()
399 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200400
401
Victor Stinner3844fe52015-09-26 10:38:01 +0200402def removepy(names):
403 if not names:
404 return
405 for idx, name in enumerate(names):
406 basename, ext = os.path.splitext(name)
407 if ext == '.py':
408 names[idx] = basename
409
410
411def count(n, word):
412 if n == 1:
413 return "%d %s" % (n, word)
414 else:
415 return "%d %ss" % (n, word)
416
417
418def printlist(x, width=70, indent=4):
419 """Print the elements of iterable x to stdout.
420
421 Optional arg width (default 70) is the maximum line length.
422 Optional arg indent (default 4) is the number of blanks with which to
423 begin each line.
424 """
425
Victor Stinner3844fe52015-09-26 10:38:01 +0200426 blanks = ' ' * indent
427 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200428 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
429 initial_indent=blanks, subsequent_indent=blanks))
430
431
432def main(tests=None, **kwargs):
433 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200434
435
436def main_in_temp_cwd():
437 """Run main() in a temporary working directory."""
438 if sysconfig.is_python_build():
439 try:
440 os.mkdir(TEMPDIR)
441 except FileExistsError:
442 pass
443
444 # Define a writable temp dir that will be used as cwd while running
445 # the tests. The name of the dir includes the pid to allow parallel
446 # testing (see the -j option).
447 test_cwd = 'test_python_{}'.format(os.getpid())
448 test_cwd = os.path.join(TEMPDIR, test_cwd)
449
450 # Run the tests in a context manager that temporarily changes the CWD to a
451 # temporary and writable directory. If it's not possible to create or
452 # change the CWD, the original CWD will be used. The original CWD is
453 # available from support.SAVEDCWD.
454 with support.temp_cwd(test_cwd, quiet=True):
455 main()