blob: aa95b2156279560cba6f916e2d048400c82a3187 [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 Stinner3844fe52015-09-26 10:38:01 +020010from test.libregrtest.runtest import (
Victor Stinner6f20a2e2015-09-30 02:32:11 +020011 findtests, runtest,
Victor Stinner56e05dd2015-09-29 23:15:38 +020012 STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED)
Victor Stinner3844fe52015-09-26 10:38:01 +020013from test.libregrtest.cmdline import _parse_args
Victor Stinnera2045022015-09-30 02:17:28 +020014from test.libregrtest.setup import setup_tests
Victor Stinner3844fe52015-09-26 10:38:01 +020015from test import support
16try:
Victor Stinnerdad20e42015-09-29 22:48:52 +020017 import gc
18except ImportError:
19 gc = None
Victor Stinner3844fe52015-09-26 10:38:01 +020020
21
Victor Stinner3844fe52015-09-26 10:38:01 +020022# When tests are run from the Python build directory, it is best practice
23# to keep the test files in a subfolder. This eases the cleanup of leftover
24# files using the "make distclean" command.
25if sysconfig.is_python_build():
26 TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
27else:
28 TEMPDIR = tempfile.gettempdir()
29TEMPDIR = os.path.abspath(TEMPDIR)
30
31
Victor Stinnerdad20e42015-09-29 22:48:52 +020032class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020033 """Execute a test suite.
34
35 This also parses command-line options and modifies its behavior
36 accordingly.
37
38 tests -- a list of strings containing test names (optional)
39 testdir -- the directory in which to look for tests (optional)
40
41 Users other than the Python test suite will certainly want to
42 specify testdir; if it's omitted, the directory containing the
43 Python test suite is searched for.
44
45 If the tests argument is omitted, the tests listed on the
46 command-line will be used. If that's empty, too, then all *.py
47 files beginning with test_ will be used.
48
49 The other default arguments (verbose, quiet, exclude,
50 single, randomize, findleaks, use_resources, trace, coverdir,
51 print_slow, and random_seed) allow programmers calling main()
52 directly to set the values that would normally be set by flags
53 on the command line.
54 """
Victor Stinnerdad20e42015-09-29 22:48:52 +020055 def __init__(self):
56 # Namespace of command line options
57 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +020058
Victor Stinnerdad20e42015-09-29 22:48:52 +020059 # tests
60 self.tests = []
61 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +020062
Victor Stinnerdad20e42015-09-29 22:48:52 +020063 # test results
64 self.good = []
65 self.bad = []
66 self.skipped = []
67 self.resource_denieds = []
68 self.environment_changed = []
69 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +020070
Victor Stinnerdad20e42015-09-29 22:48:52 +020071 # used by --slow
72 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +020073
Victor Stinnerdad20e42015-09-29 22:48:52 +020074 # used by --coverage, trace.Trace instance
75 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +020076
Victor Stinnerdad20e42015-09-29 22:48:52 +020077 # used by --findleaks, store for gc.garbage
78 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +020079
Victor Stinnerdad20e42015-09-29 22:48:52 +020080 # used to display the progress bar "[ 3/100]"
81 self.test_count = ''
82 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +020083
Victor Stinnerdad20e42015-09-29 22:48:52 +020084 # used by --single
85 self.next_single_test = None
86 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +020087
Victor Stinnerdad20e42015-09-29 22:48:52 +020088 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +020089 ok, test_time = result
Victor Stinnerdad20e42015-09-29 22:48:52 +020090 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +020091 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020092 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020093 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020094 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020095 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020096 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020097 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020098 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020099 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200100 self.skipped.append(test)
101 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200102
Victor Stinnerdad20e42015-09-29 22:48:52 +0200103 def display_progress(self, test_index, test):
104 if self.ns.quiet:
105 return
Brett Cannon11faa212015-10-02 16:20:49 -0700106 if self.bad and not self.ns.pgo:
107 fmt = "[{1:{0}}{2}/{3}] {4}"
108 else:
109 fmt = "[{1:{0}}{2}] {4}"
Victor Stinner6448b802015-09-29 23:43:33 +0200110 print(fmt.format(self.test_count_width, test_index,
Victor Stinnerf33536c2015-09-30 00:48:27 +0200111 self.test_count, len(self.bad), test),
112 flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200113
Victor Stinner234cbef2015-09-30 01:13:53 +0200114 def parse_args(self, kwargs):
115 ns = _parse_args(sys.argv[1:], **kwargs)
116
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200117 if ns.timeout and not hasattr(faulthandler, 'dump_traceback_later'):
118 print("Warning: The timeout option requires "
119 "faulthandler.dump_traceback_later", file=sys.stderr)
120 ns.timeout = None
121
Victor Stinner234cbef2015-09-30 01:13:53 +0200122 if ns.threshold is not None and gc is None:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200123 print('No GC available, ignore --threshold.', file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200124 ns.threshold = None
125
126 if ns.findleaks:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200127 if gc is not None:
128 # Uncomment the line below to report garbage that is not
129 # freeable by reference counting alone. By default only
130 # garbage that is not collectable by the GC is reported.
131 pass
132 #gc.set_debug(gc.DEBUG_SAVEALL)
133 else:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200134 print('No GC available, disabling --findleaks',
135 file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200136 ns.findleaks = False
Victor Stinnerdad20e42015-09-29 22:48:52 +0200137
Victor Stinnerdad20e42015-09-29 22:48:52 +0200138 # Strip .py extensions.
Victor Stinner234cbef2015-09-30 01:13:53 +0200139 removepy(ns.args)
140
141 return ns
Victor Stinnerdad20e42015-09-29 22:48:52 +0200142
Victor Stinnerdad20e42015-09-29 22:48:52 +0200143 def find_tests(self, tests):
144 self.tests = tests
145
146 if self.ns.single:
147 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
148 try:
149 with open(self.next_single_filename, 'r') as fp:
150 next_test = fp.read().strip()
151 self.tests = [next_test]
152 except OSError:
153 pass
154
155 if self.ns.fromfile:
156 self.tests = []
157 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
158 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
159 for line in fp:
160 line = count_pat.sub('', line)
161 guts = line.split() # assuming no test has whitespace in its name
162 if guts and not guts[0].startswith('#'):
163 self.tests.extend(guts)
164
165 removepy(self.tests)
166
167 stdtests = STDTESTS[:]
168 nottests = NOTTESTS.copy()
169 if self.ns.exclude:
170 for arg in self.ns.args:
171 if arg in stdtests:
172 stdtests.remove(arg)
173 nottests.add(arg)
174 self.ns.args = []
175
Victor Stinnerdad20e42015-09-29 22:48:52 +0200176 # if testdir is set, then we are not running the python tests suite, so
177 # don't add default tests to be executed or skipped (pass empty values)
178 if self.ns.testdir:
179 alltests = findtests(self.ns.testdir, list(), set())
180 else:
181 alltests = findtests(self.ns.testdir, stdtests, nottests)
182
183 self.selected = self.tests or self.ns.args or alltests
184 if self.ns.single:
185 self.selected = self.selected[:1]
186 try:
187 pos = alltests.index(self.selected[0])
188 self.next_single_test = alltests[pos + 1]
189 except IndexError:
190 pass
191
Victor Stinnerc7eab052015-09-30 00:59:35 +0200192 # Remove all the selected tests that precede start if it's set.
Victor Stinnerdad20e42015-09-29 22:48:52 +0200193 if self.ns.start:
194 try:
195 del self.selected[:self.selected.index(self.ns.start)]
196 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200197 print("Couldn't find starting test (%s), using all tests"
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200198 % self.ns.start, file=sys.stderr)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200199
200 if self.ns.randomize:
201 if self.ns.random_seed is None:
202 self.ns.random_seed = random.randrange(10000000)
203 random.seed(self.ns.random_seed)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200204 random.shuffle(self.selected)
205
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200206 def list_tests(self):
207 for name in self.selected:
208 print(name)
209
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200210 def rerun_failed_tests(self):
211 self.ns.verbose = True
212 self.ns.failfast = False
213 self.ns.verbose3 = False
214 self.ns.match_tests = None
215
216 print("Re-running failed tests in verbose mode")
217 for test in self.bad[:]:
218 print("Re-running test %r in verbose mode" % test, flush=True)
219 try:
220 self.ns.verbose = True
221 ok = runtest(self.ns, test)
222 except KeyboardInterrupt:
223 # print a newline separate from the ^C
224 print()
225 break
226 else:
227 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
228 self.bad.remove(test)
229 else:
230 if self.bad:
231 print(count(len(self.bad), 'test'), "failed again:")
232 printlist(self.bad)
233
Victor Stinnerdad20e42015-09-29 22:48:52 +0200234 def display_result(self):
235 if self.interrupted:
236 # print a newline after ^C
237 print()
238 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200239 executed = set(self.good) | set(self.bad) | set(self.skipped)
240 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200241 print(count(len(omitted), "test"), "omitted:")
242 printlist(omitted)
243
Brett Cannon11faa212015-10-02 16:20:49 -0700244 # If running the test suite for PGO then no one cares about
245 # results.
246 if self.ns.pgo:
247 return
248
Victor Stinnerdad20e42015-09-29 22:48:52 +0200249 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200250 if (not self.bad
251 and not self.skipped
252 and not self.interrupted
253 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200254 print("All", end=' ')
255 print(count(len(self.good), "test"), "OK.")
256
257 if self.ns.print_slow:
258 self.test_times.sort(reverse=True)
259 print("10 slowest tests:")
260 for time, test in self.test_times[:10]:
261 print("%s: %.1fs" % (test, time))
262
263 if self.bad:
264 print(count(len(self.bad), "test"), "failed:")
265 printlist(self.bad)
266
267 if self.environment_changed:
268 print("{} altered the execution environment:".format(
269 count(len(self.environment_changed), "test")))
270 printlist(self.environment_changed)
271
272 if self.skipped and not self.ns.quiet:
273 print(count(len(self.skipped), "test"), "skipped:")
274 printlist(self.skipped)
275
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200276 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200277 if self.ns.trace:
278 import trace
Victor Stinnera53a8182015-10-01 00:53:09 +0200279 self.tracer = trace.Trace(trace=False, count=True)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200280
Victor Stinnerdad20e42015-09-29 22:48:52 +0200281 save_modules = sys.modules.keys()
282
283 for test_index, test in enumerate(self.tests, 1):
284 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200285 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200286 # If we're tracing code coverage, then we don't exit with status
287 # if on a false return value from main.
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200288 cmd = ('result = runtest(self.ns, test); '
289 'self.accumulate_result(test, result)')
Victor Stinnerdad20e42015-09-29 22:48:52 +0200290 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200291 else:
292 try:
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200293 result = runtest(self.ns, test)
294 self.accumulate_result(test, result)
Victor Stinner3844fe52015-09-26 10:38:01 +0200295 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200296 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200297 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200298
Victor Stinnerdad20e42015-09-29 22:48:52 +0200299 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200300 gc.collect()
301 if gc.garbage:
302 print("Warning: test created", len(gc.garbage), end=' ')
303 print("uncollectable object(s).")
304 # move the uncollectable objects somewhere so we don't see
305 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200306 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200307 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200308
Victor Stinner3844fe52015-09-26 10:38:01 +0200309 # Unload the newly imported modules (best effort finalization)
310 for module in sys.modules.keys():
311 if module not in save_modules and module.startswith("test."):
312 support.unload(module)
313
Victor Stinnerb4084352015-09-30 02:39:22 +0200314 def _test_forever(self, tests):
315 while True:
316 for test in tests:
317 yield test
318 if self.bad:
319 return
Victor Stinner3844fe52015-09-26 10:38:01 +0200320
Victor Stinnerb4084352015-09-30 02:39:22 +0200321 def run_tests(self):
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200322 # For a partial run, we do not need to clutter the output.
323 if (self.ns.verbose
324 or self.ns.header
Brett Cannon11faa212015-10-02 16:20:49 -0700325 or not (self.ns.pgo or self.ns.quiet or self.ns.single
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200326 or self.tests or self.ns.args)):
327 # Print basic platform information
328 print("==", platform.python_implementation(), *sys.version.split())
329 print("== ", platform.platform(aliased=True),
330 "%s-endian" % sys.byteorder)
331 print("== ", "hash algorithm:", sys.hash_info.algorithm,
332 "64bit" if sys.maxsize > 2**32 else "32bit")
333 print("== ", os.getcwd())
334 print("Testing with flags:", sys.flags)
335
336 if self.ns.randomize:
337 print("Using random seed", self.ns.random_seed)
338
Victor Stinnerdad20e42015-09-29 22:48:52 +0200339 if self.ns.forever:
Victor Stinner9a142142015-09-30 13:51:17 +0200340 self.tests = self._test_forever(list(self.selected))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200341 self.test_count = ''
342 self.test_count_width = 3
343 else:
344 self.tests = iter(self.selected)
345 self.test_count = '/{}'.format(len(self.selected))
346 self.test_count_width = len(self.test_count) - 1
347
348 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200349 from test.libregrtest.runtest_mp import run_tests_multiprocess
350 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200351 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200352 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200353
354 def finalize(self):
355 if self.next_single_filename:
356 if self.next_single_test:
357 with open(self.next_single_filename, 'w') as fp:
358 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200359 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200360 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200361
Victor Stinnerc7eab052015-09-30 00:59:35 +0200362 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200363 r = self.tracer.results()
364 r.write_results(show_missing=True, summary=True,
365 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200366
Victor Stinnerdad20e42015-09-29 22:48:52 +0200367 if self.ns.runleaks:
368 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200369
Victor Stinnerdad20e42015-09-29 22:48:52 +0200370 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200371 self.ns = self.parse_args(kwargs)
372
Victor Stinnerdad20e42015-09-29 22:48:52 +0200373 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200374 from test.libregrtest.runtest_mp import run_tests_slave
375 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200376
Victor Stinnerc7eab052015-09-30 00:59:35 +0200377 if self.ns.wait:
378 input("Press any key to continue...")
379
Victor Stinnera2045022015-09-30 02:17:28 +0200380 setup_tests(self.ns)
Victor Stinnerecef6222015-09-30 01:39:28 +0200381
Victor Stinnerdad20e42015-09-29 22:48:52 +0200382 self.find_tests(tests)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200383
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200384 if self.ns.list_tests:
385 self.list_tests()
386 sys.exit(0)
387
388 self.run_tests()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200389 self.display_result()
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200390
391 if self.ns.verbose2 and self.bad:
392 self.rerun_failed_tests()
393
Victor Stinnerdad20e42015-09-29 22:48:52 +0200394 self.finalize()
395 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200396
397
Victor Stinner3844fe52015-09-26 10:38:01 +0200398def removepy(names):
399 if not names:
400 return
401 for idx, name in enumerate(names):
402 basename, ext = os.path.splitext(name)
403 if ext == '.py':
404 names[idx] = basename
405
406
407def count(n, word):
408 if n == 1:
409 return "%d %s" % (n, word)
410 else:
411 return "%d %ss" % (n, word)
412
413
414def printlist(x, width=70, indent=4):
415 """Print the elements of iterable x to stdout.
416
417 Optional arg width (default 70) is the maximum line length.
418 Optional arg indent (default 4) is the number of blanks with which to
419 begin each line.
420 """
421
Victor Stinner3844fe52015-09-26 10:38:01 +0200422 blanks = ' ' * indent
423 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200424 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
425 initial_indent=blanks, subsequent_indent=blanks))
426
427
428def main(tests=None, **kwargs):
429 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200430
431
432def main_in_temp_cwd():
433 """Run main() in a temporary working directory."""
434 if sysconfig.is_python_build():
435 try:
436 os.mkdir(TEMPDIR)
437 except FileExistsError:
438 pass
439
440 # Define a writable temp dir that will be used as cwd while running
441 # the tests. The name of the dir includes the pid to allow parallel
442 # testing (see the -j option).
443 test_cwd = 'test_python_{}'.format(os.getpid())
444 test_cwd = os.path.join(TEMPDIR, test_cwd)
445
446 # Run the tests in a context manager that temporarily changes the CWD to a
447 # temporary and writable directory. If it's not possible to create or
448 # change the CWD, the original CWD will be used. The original CWD is
449 # available from support.SAVEDCWD.
450 with support.temp_cwd(test_cwd, quiet=True):
451 main()