blob: 30d8a59478be68cb69ce8babc0ae2e4244d9f6fc [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
106 fmt = "[{1:{0}}{2}/{3}] {4}" if self.bad else "[{1:{0}}{2}] {4}"
Victor Stinner6448b802015-09-29 23:43:33 +0200107 print(fmt.format(self.test_count_width, test_index,
Victor Stinnerf33536c2015-09-30 00:48:27 +0200108 self.test_count, len(self.bad), test),
109 flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200110
Victor Stinner234cbef2015-09-30 01:13:53 +0200111 def parse_args(self, kwargs):
112 ns = _parse_args(sys.argv[1:], **kwargs)
113
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200114 if ns.timeout and not hasattr(faulthandler, 'dump_traceback_later'):
115 print("Warning: The timeout option requires "
116 "faulthandler.dump_traceback_later", file=sys.stderr)
117 ns.timeout = None
118
Victor Stinner234cbef2015-09-30 01:13:53 +0200119 if ns.threshold is not None and gc is None:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200120 print('No GC available, ignore --threshold.', file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200121 ns.threshold = None
122
123 if ns.findleaks:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200124 if gc is not None:
125 # Uncomment the line below to report garbage that is not
126 # freeable by reference counting alone. By default only
127 # garbage that is not collectable by the GC is reported.
128 pass
129 #gc.set_debug(gc.DEBUG_SAVEALL)
130 else:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200131 print('No GC available, disabling --findleaks',
132 file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200133 ns.findleaks = False
Victor Stinnerdad20e42015-09-29 22:48:52 +0200134
Victor Stinnerdad20e42015-09-29 22:48:52 +0200135 # Strip .py extensions.
Victor Stinner234cbef2015-09-30 01:13:53 +0200136 removepy(ns.args)
137
138 return ns
Victor Stinnerdad20e42015-09-29 22:48:52 +0200139
Victor Stinnerdad20e42015-09-29 22:48:52 +0200140 def find_tests(self, tests):
141 self.tests = tests
142
143 if self.ns.single:
144 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
145 try:
146 with open(self.next_single_filename, 'r') as fp:
147 next_test = fp.read().strip()
148 self.tests = [next_test]
149 except OSError:
150 pass
151
152 if self.ns.fromfile:
153 self.tests = []
154 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
155 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
156 for line in fp:
157 line = count_pat.sub('', line)
158 guts = line.split() # assuming no test has whitespace in its name
159 if guts and not guts[0].startswith('#'):
160 self.tests.extend(guts)
161
162 removepy(self.tests)
163
164 stdtests = STDTESTS[:]
165 nottests = NOTTESTS.copy()
166 if self.ns.exclude:
167 for arg in self.ns.args:
168 if arg in stdtests:
169 stdtests.remove(arg)
170 nottests.add(arg)
171 self.ns.args = []
172
Victor Stinnerdad20e42015-09-29 22:48:52 +0200173 # if testdir is set, then we are not running the python tests suite, so
174 # don't add default tests to be executed or skipped (pass empty values)
175 if self.ns.testdir:
176 alltests = findtests(self.ns.testdir, list(), set())
177 else:
178 alltests = findtests(self.ns.testdir, stdtests, nottests)
179
180 self.selected = self.tests or self.ns.args or alltests
181 if self.ns.single:
182 self.selected = self.selected[:1]
183 try:
184 pos = alltests.index(self.selected[0])
185 self.next_single_test = alltests[pos + 1]
186 except IndexError:
187 pass
188
Victor Stinnerc7eab052015-09-30 00:59:35 +0200189 # Remove all the selected tests that precede start if it's set.
Victor Stinnerdad20e42015-09-29 22:48:52 +0200190 if self.ns.start:
191 try:
192 del self.selected[:self.selected.index(self.ns.start)]
193 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200194 print("Couldn't find starting test (%s), using all tests"
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200195 % self.ns.start, file=sys.stderr)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200196
197 if self.ns.randomize:
198 if self.ns.random_seed is None:
199 self.ns.random_seed = random.randrange(10000000)
200 random.seed(self.ns.random_seed)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200201 random.shuffle(self.selected)
202
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200203 def list_tests(self):
204 for name in self.selected:
205 print(name)
206
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200207 def rerun_failed_tests(self):
208 self.ns.verbose = True
209 self.ns.failfast = False
210 self.ns.verbose3 = False
211 self.ns.match_tests = None
212
213 print("Re-running failed tests in verbose mode")
214 for test in self.bad[:]:
215 print("Re-running test %r in verbose mode" % test, flush=True)
216 try:
217 self.ns.verbose = True
218 ok = runtest(self.ns, test)
219 except KeyboardInterrupt:
220 # print a newline separate from the ^C
221 print()
222 break
223 else:
224 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
225 self.bad.remove(test)
226 else:
227 if self.bad:
228 print(count(len(self.bad), 'test'), "failed again:")
229 printlist(self.bad)
230
Victor Stinnerdad20e42015-09-29 22:48:52 +0200231 def display_result(self):
232 if self.interrupted:
233 # print a newline after ^C
234 print()
235 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200236 executed = set(self.good) | set(self.bad) | set(self.skipped)
237 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200238 print(count(len(omitted), "test"), "omitted:")
239 printlist(omitted)
240
241 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200242 if (not self.bad
243 and not self.skipped
244 and not self.interrupted
245 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200246 print("All", end=' ')
247 print(count(len(self.good), "test"), "OK.")
248
249 if self.ns.print_slow:
250 self.test_times.sort(reverse=True)
251 print("10 slowest tests:")
252 for time, test in self.test_times[:10]:
253 print("%s: %.1fs" % (test, time))
254
255 if self.bad:
256 print(count(len(self.bad), "test"), "failed:")
257 printlist(self.bad)
258
259 if self.environment_changed:
260 print("{} altered the execution environment:".format(
261 count(len(self.environment_changed), "test")))
262 printlist(self.environment_changed)
263
264 if self.skipped and not self.ns.quiet:
265 print(count(len(self.skipped), "test"), "skipped:")
266 printlist(self.skipped)
267
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200268 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200269 if self.ns.trace:
270 import trace
Victor Stinnera53a8182015-10-01 00:53:09 +0200271 self.tracer = trace.Trace(trace=False, count=True)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200272
Victor Stinnerdad20e42015-09-29 22:48:52 +0200273 save_modules = sys.modules.keys()
274
275 for test_index, test in enumerate(self.tests, 1):
276 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200277 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200278 # If we're tracing code coverage, then we don't exit with status
279 # if on a false return value from main.
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200280 cmd = ('result = runtest(self.ns, test); '
281 'self.accumulate_result(test, result)')
Victor Stinnerdad20e42015-09-29 22:48:52 +0200282 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200283 else:
284 try:
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200285 result = runtest(self.ns, test)
286 self.accumulate_result(test, result)
Victor Stinner3844fe52015-09-26 10:38:01 +0200287 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200288 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200289 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200290
Victor Stinnerdad20e42015-09-29 22:48:52 +0200291 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200292 gc.collect()
293 if gc.garbage:
294 print("Warning: test created", len(gc.garbage), end=' ')
295 print("uncollectable object(s).")
296 # move the uncollectable objects somewhere so we don't see
297 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200298 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200299 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200300
Victor Stinner3844fe52015-09-26 10:38:01 +0200301 # Unload the newly imported modules (best effort finalization)
302 for module in sys.modules.keys():
303 if module not in save_modules and module.startswith("test."):
304 support.unload(module)
305
Victor Stinnerb4084352015-09-30 02:39:22 +0200306 def _test_forever(self, tests):
307 while True:
308 for test in tests:
309 yield test
310 if self.bad:
311 return
Victor Stinner3844fe52015-09-26 10:38:01 +0200312
Victor Stinnerb4084352015-09-30 02:39:22 +0200313 def run_tests(self):
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200314 # For a partial run, we do not need to clutter the output.
315 if (self.ns.verbose
316 or self.ns.header
317 or not (self.ns.quiet or self.ns.single
318 or self.tests or self.ns.args)):
319 # Print basic platform information
320 print("==", platform.python_implementation(), *sys.version.split())
321 print("== ", platform.platform(aliased=True),
322 "%s-endian" % sys.byteorder)
323 print("== ", "hash algorithm:", sys.hash_info.algorithm,
324 "64bit" if sys.maxsize > 2**32 else "32bit")
325 print("== ", os.getcwd())
326 print("Testing with flags:", sys.flags)
327
328 if self.ns.randomize:
329 print("Using random seed", self.ns.random_seed)
330
Victor Stinnerdad20e42015-09-29 22:48:52 +0200331 if self.ns.forever:
Victor Stinner9a142142015-09-30 13:51:17 +0200332 self.tests = self._test_forever(list(self.selected))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200333 self.test_count = ''
334 self.test_count_width = 3
335 else:
336 self.tests = iter(self.selected)
337 self.test_count = '/{}'.format(len(self.selected))
338 self.test_count_width = len(self.test_count) - 1
339
340 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200341 from test.libregrtest.runtest_mp import run_tests_multiprocess
342 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200343 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200344 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200345
346 def finalize(self):
347 if self.next_single_filename:
348 if self.next_single_test:
349 with open(self.next_single_filename, 'w') as fp:
350 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200351 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200352 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200353
Victor Stinnerc7eab052015-09-30 00:59:35 +0200354 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200355 r = self.tracer.results()
356 r.write_results(show_missing=True, summary=True,
357 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200358
Victor Stinnerdad20e42015-09-29 22:48:52 +0200359 if self.ns.runleaks:
360 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200361
Victor Stinnerdad20e42015-09-29 22:48:52 +0200362 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200363 self.ns = self.parse_args(kwargs)
364
Victor Stinnerdad20e42015-09-29 22:48:52 +0200365 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200366 from test.libregrtest.runtest_mp import run_tests_slave
367 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200368
Victor Stinnerc7eab052015-09-30 00:59:35 +0200369 if self.ns.wait:
370 input("Press any key to continue...")
371
Victor Stinnera2045022015-09-30 02:17:28 +0200372 setup_tests(self.ns)
Victor Stinnerecef6222015-09-30 01:39:28 +0200373
Victor Stinnerdad20e42015-09-29 22:48:52 +0200374 self.find_tests(tests)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200375
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200376 if self.ns.list_tests:
377 self.list_tests()
378 sys.exit(0)
379
380 self.run_tests()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200381 self.display_result()
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200382
383 if self.ns.verbose2 and self.bad:
384 self.rerun_failed_tests()
385
Victor Stinnerdad20e42015-09-29 22:48:52 +0200386 self.finalize()
387 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200388
389
Victor Stinner3844fe52015-09-26 10:38:01 +0200390def removepy(names):
391 if not names:
392 return
393 for idx, name in enumerate(names):
394 basename, ext = os.path.splitext(name)
395 if ext == '.py':
396 names[idx] = basename
397
398
399def count(n, word):
400 if n == 1:
401 return "%d %s" % (n, word)
402 else:
403 return "%d %ss" % (n, word)
404
405
406def printlist(x, width=70, indent=4):
407 """Print the elements of iterable x to stdout.
408
409 Optional arg width (default 70) is the maximum line length.
410 Optional arg indent (default 4) is the number of blanks with which to
411 begin each line.
412 """
413
Victor Stinner3844fe52015-09-26 10:38:01 +0200414 blanks = ' ' * indent
415 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200416 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
417 initial_indent=blanks, subsequent_indent=blanks))
418
419
420def main(tests=None, **kwargs):
421 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200422
423
424def main_in_temp_cwd():
425 """Run main() in a temporary working directory."""
426 if sysconfig.is_python_build():
427 try:
428 os.mkdir(TEMPDIR)
429 except FileExistsError:
430 pass
431
432 # Define a writable temp dir that will be used as cwd while running
433 # the tests. The name of the dir includes the pid to allow parallel
434 # testing (see the -j option).
435 test_cwd = 'test_python_{}'.format(os.getpid())
436 test_cwd = os.path.join(TEMPDIR, test_cwd)
437
438 # Run the tests in a context manager that temporarily changes the CWD to a
439 # temporary and writable directory. If it's not possible to create or
440 # change the CWD, the original CWD will be used. The original CWD is
441 # available from support.SAVEDCWD.
442 with support.temp_cwd(test_cwd, quiet=True):
443 main()