blob: c1ce3b179f777a8166511b0f9f3165230fd24f8f [file] [log] [blame]
Victor Stinner3844fe52015-09-26 10:38:01 +02001import os
Victor Stinner3844fe52015-09-26 10:38:01 +02002import platform
Victor Stinnerdad20e42015-09-29 22:48:52 +02003import random
4import re
Victor Stinnerdad20e42015-09-29 22:48:52 +02005import sys
6import sysconfig
7import tempfile
8import textwrap
Victor Stinner3844fe52015-09-26 10:38:01 +02009from test.libregrtest.runtest import (
Victor Stinner6f20a2e2015-09-30 02:32:11 +020010 findtests, runtest,
Victor Stinner56e05dd2015-09-29 23:15:38 +020011 STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED)
Victor Stinner3844fe52015-09-26 10:38:01 +020012from test.libregrtest.cmdline import _parse_args
Victor Stinnera2045022015-09-30 02:17:28 +020013from test.libregrtest.setup import setup_tests
Victor Stinner3844fe52015-09-26 10:38:01 +020014from test import support
15try:
Victor Stinnerdad20e42015-09-29 22:48:52 +020016 import gc
17except ImportError:
18 gc = None
Victor Stinner3844fe52015-09-26 10:38:01 +020019
20
Victor Stinner3844fe52015-09-26 10:38:01 +020021# When tests are run from the Python build directory, it is best practice
22# to keep the test files in a subfolder. This eases the cleanup of leftover
23# files using the "make distclean" command.
24if sysconfig.is_python_build():
25 TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
26else:
27 TEMPDIR = tempfile.gettempdir()
28TEMPDIR = os.path.abspath(TEMPDIR)
29
30
Victor Stinnerdad20e42015-09-29 22:48:52 +020031class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020032 """Execute a test suite.
33
34 This also parses command-line options and modifies its behavior
35 accordingly.
36
37 tests -- a list of strings containing test names (optional)
38 testdir -- the directory in which to look for tests (optional)
39
40 Users other than the Python test suite will certainly want to
41 specify testdir; if it's omitted, the directory containing the
42 Python test suite is searched for.
43
44 If the tests argument is omitted, the tests listed on the
45 command-line will be used. If that's empty, too, then all *.py
46 files beginning with test_ will be used.
47
48 The other default arguments (verbose, quiet, exclude,
49 single, randomize, findleaks, use_resources, trace, coverdir,
50 print_slow, and random_seed) allow programmers calling main()
51 directly to set the values that would normally be set by flags
52 on the command line.
53 """
Victor Stinnerdad20e42015-09-29 22:48:52 +020054 def __init__(self):
55 # Namespace of command line options
56 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +020057
Victor Stinnerdad20e42015-09-29 22:48:52 +020058 # tests
59 self.tests = []
60 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +020061
Victor Stinnerdad20e42015-09-29 22:48:52 +020062 # test results
63 self.good = []
64 self.bad = []
65 self.skipped = []
66 self.resource_denieds = []
67 self.environment_changed = []
68 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +020069
Victor Stinnerdad20e42015-09-29 22:48:52 +020070 # used by --slow
71 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +020072
Victor Stinnerdad20e42015-09-29 22:48:52 +020073 # used by --coverage, trace.Trace instance
74 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +020075
Victor Stinnerdad20e42015-09-29 22:48:52 +020076 # used by --findleaks, store for gc.garbage
77 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +020078
Victor Stinnerdad20e42015-09-29 22:48:52 +020079 # used to display the progress bar "[ 3/100]"
80 self.test_count = ''
81 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +020082
Victor Stinnerdad20e42015-09-29 22:48:52 +020083 # used by --single
84 self.next_single_test = None
85 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +020086
Victor Stinnerdad20e42015-09-29 22:48:52 +020087 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +020088 ok, test_time = result
Victor Stinnerdad20e42015-09-29 22:48:52 +020089 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +020090 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020091 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020092 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020093 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020094 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020095 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020096 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020097 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020098 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020099 self.skipped.append(test)
100 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200101
Victor Stinnerdad20e42015-09-29 22:48:52 +0200102 def display_progress(self, test_index, test):
103 if self.ns.quiet:
104 return
105 fmt = "[{1:{0}}{2}/{3}] {4}" if self.bad else "[{1:{0}}{2}] {4}"
Victor Stinner6448b802015-09-29 23:43:33 +0200106 print(fmt.format(self.test_count_width, test_index,
Victor Stinnerf33536c2015-09-30 00:48:27 +0200107 self.test_count, len(self.bad), test),
108 flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200109
Victor Stinner234cbef2015-09-30 01:13:53 +0200110 def parse_args(self, kwargs):
111 ns = _parse_args(sys.argv[1:], **kwargs)
112
113 if ns.threshold is not None and gc is None:
114 print('No GC available, ignore --threshold.')
115 ns.threshold = None
116
117 if ns.findleaks:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200118 if gc is not None:
119 # Uncomment the line below to report garbage that is not
120 # freeable by reference counting alone. By default only
121 # garbage that is not collectable by the GC is reported.
122 pass
123 #gc.set_debug(gc.DEBUG_SAVEALL)
124 else:
125 print('No GC available, disabling --findleaks')
Victor Stinner234cbef2015-09-30 01:13:53 +0200126 ns.findleaks = False
Victor Stinnerdad20e42015-09-29 22:48:52 +0200127
Victor Stinnerdad20e42015-09-29 22:48:52 +0200128 # Strip .py extensions.
Victor Stinner234cbef2015-09-30 01:13:53 +0200129 removepy(ns.args)
130
131 return ns
Victor Stinnerdad20e42015-09-29 22:48:52 +0200132
Victor Stinnerdad20e42015-09-29 22:48:52 +0200133 def find_tests(self, tests):
134 self.tests = tests
135
136 if self.ns.single:
137 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
138 try:
139 with open(self.next_single_filename, 'r') as fp:
140 next_test = fp.read().strip()
141 self.tests = [next_test]
142 except OSError:
143 pass
144
145 if self.ns.fromfile:
146 self.tests = []
147 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
148 count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
149 for line in fp:
150 line = count_pat.sub('', line)
151 guts = line.split() # assuming no test has whitespace in its name
152 if guts and not guts[0].startswith('#'):
153 self.tests.extend(guts)
154
155 removepy(self.tests)
156
157 stdtests = STDTESTS[:]
158 nottests = NOTTESTS.copy()
159 if self.ns.exclude:
160 for arg in self.ns.args:
161 if arg in stdtests:
162 stdtests.remove(arg)
163 nottests.add(arg)
164 self.ns.args = []
165
166 # For a partial run, we do not need to clutter the output.
Victor Stinner6448b802015-09-29 23:43:33 +0200167 if (self.ns.verbose
168 or self.ns.header
169 or not (self.ns.quiet or self.ns.single
170 or self.tests or self.ns.args)):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200171 # Print basic platform information
172 print("==", platform.python_implementation(), *sys.version.split())
173 print("== ", platform.platform(aliased=True),
174 "%s-endian" % sys.byteorder)
175 print("== ", "hash algorithm:", sys.hash_info.algorithm,
176 "64bit" if sys.maxsize > 2**32 else "32bit")
177 print("== ", os.getcwd())
178 print("Testing with flags:", sys.flags)
179
180 # if testdir is set, then we are not running the python tests suite, so
181 # don't add default tests to be executed or skipped (pass empty values)
182 if self.ns.testdir:
183 alltests = findtests(self.ns.testdir, list(), set())
184 else:
185 alltests = findtests(self.ns.testdir, stdtests, nottests)
186
187 self.selected = self.tests or self.ns.args or alltests
188 if self.ns.single:
189 self.selected = self.selected[:1]
190 try:
191 pos = alltests.index(self.selected[0])
192 self.next_single_test = alltests[pos + 1]
193 except IndexError:
194 pass
195
Victor Stinnerc7eab052015-09-30 00:59:35 +0200196 # Remove all the selected tests that precede start if it's set.
Victor Stinnerdad20e42015-09-29 22:48:52 +0200197 if self.ns.start:
198 try:
199 del self.selected[:self.selected.index(self.ns.start)]
200 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200201 print("Couldn't find starting test (%s), using all tests"
202 % self.ns.start)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200203
204 if self.ns.randomize:
205 if self.ns.random_seed is None:
206 self.ns.random_seed = random.randrange(10000000)
207 random.seed(self.ns.random_seed)
208 print("Using random seed", self.ns.random_seed)
209 random.shuffle(self.selected)
210
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200211 def rerun_failed_tests(self):
212 self.ns.verbose = True
213 self.ns.failfast = False
214 self.ns.verbose3 = False
215 self.ns.match_tests = None
216
217 print("Re-running failed tests in verbose mode")
218 for test in self.bad[:]:
219 print("Re-running test %r in verbose mode" % test, flush=True)
220 try:
221 self.ns.verbose = True
222 ok = runtest(self.ns, test)
223 except KeyboardInterrupt:
224 # print a newline separate from the ^C
225 print()
226 break
227 else:
228 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
229 self.bad.remove(test)
230 else:
231 if self.bad:
232 print(count(len(self.bad), 'test'), "failed again:")
233 printlist(self.bad)
234
Victor Stinnerdad20e42015-09-29 22:48:52 +0200235 def display_result(self):
236 if self.interrupted:
237 # print a newline after ^C
238 print()
239 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200240 executed = set(self.good) | set(self.bad) | set(self.skipped)
241 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200242 print(count(len(omitted), "test"), "omitted:")
243 printlist(omitted)
244
245 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200246 if (not self.bad
247 and not self.skipped
248 and not self.interrupted
249 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200250 print("All", end=' ')
251 print(count(len(self.good), "test"), "OK.")
252
253 if self.ns.print_slow:
254 self.test_times.sort(reverse=True)
255 print("10 slowest tests:")
256 for time, test in self.test_times[:10]:
257 print("%s: %.1fs" % (test, time))
258
259 if self.bad:
260 print(count(len(self.bad), "test"), "failed:")
261 printlist(self.bad)
262
263 if self.environment_changed:
264 print("{} altered the execution environment:".format(
265 count(len(self.environment_changed), "test")))
266 printlist(self.environment_changed)
267
268 if self.skipped and not self.ns.quiet:
269 print(count(len(self.skipped), "test"), "skipped:")
270 printlist(self.skipped)
271
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200272 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200273 if self.ns.trace:
274 import trace
Victor Stinnera53a8182015-10-01 00:53:09 +0200275 self.tracer = trace.Trace(trace=False, count=True)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200276
Victor Stinnerdad20e42015-09-29 22:48:52 +0200277 save_modules = sys.modules.keys()
278
279 for test_index, test in enumerate(self.tests, 1):
280 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200281 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200282 # If we're tracing code coverage, then we don't exit with status
283 # if on a false return value from main.
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200284 cmd = ('result = runtest(self.ns, test); '
285 'self.accumulate_result(test, result)')
Victor Stinnerdad20e42015-09-29 22:48:52 +0200286 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200287 else:
288 try:
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200289 result = runtest(self.ns, test)
290 self.accumulate_result(test, result)
Victor Stinner3844fe52015-09-26 10:38:01 +0200291 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200292 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200293 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200294
Victor Stinnerdad20e42015-09-29 22:48:52 +0200295 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200296 gc.collect()
297 if gc.garbage:
298 print("Warning: test created", len(gc.garbage), end=' ')
299 print("uncollectable object(s).")
300 # move the uncollectable objects somewhere so we don't see
301 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200302 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200303 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200304
Victor Stinner3844fe52015-09-26 10:38:01 +0200305 # Unload the newly imported modules (best effort finalization)
306 for module in sys.modules.keys():
307 if module not in save_modules and module.startswith("test."):
308 support.unload(module)
309
Victor Stinnerb4084352015-09-30 02:39:22 +0200310 def _test_forever(self, tests):
311 while True:
312 for test in tests:
313 yield test
314 if self.bad:
315 return
Victor Stinner3844fe52015-09-26 10:38:01 +0200316
Victor Stinnerb4084352015-09-30 02:39:22 +0200317 def run_tests(self):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200318 if self.ns.forever:
Victor Stinner9a142142015-09-30 13:51:17 +0200319 self.tests = self._test_forever(list(self.selected))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200320 self.test_count = ''
321 self.test_count_width = 3
322 else:
323 self.tests = iter(self.selected)
324 self.test_count = '/{}'.format(len(self.selected))
325 self.test_count_width = len(self.test_count) - 1
326
327 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200328 from test.libregrtest.runtest_mp import run_tests_multiprocess
329 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200330 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200331 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200332
333 def finalize(self):
334 if self.next_single_filename:
335 if self.next_single_test:
336 with open(self.next_single_filename, 'w') as fp:
337 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200338 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200339 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200340
Victor Stinnerc7eab052015-09-30 00:59:35 +0200341 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200342 r = self.tracer.results()
343 r.write_results(show_missing=True, summary=True,
344 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200345
Victor Stinnerdad20e42015-09-29 22:48:52 +0200346 if self.ns.runleaks:
347 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200348
Victor Stinnerdad20e42015-09-29 22:48:52 +0200349 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200350 self.ns = self.parse_args(kwargs)
351
Victor Stinnerdad20e42015-09-29 22:48:52 +0200352 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200353 from test.libregrtest.runtest_mp import run_tests_slave
354 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200355
Victor Stinnerc7eab052015-09-30 00:59:35 +0200356 if self.ns.wait:
357 input("Press any key to continue...")
358
Victor Stinnera2045022015-09-30 02:17:28 +0200359 setup_tests(self.ns)
Victor Stinnerecef6222015-09-30 01:39:28 +0200360
Victor Stinnerdad20e42015-09-29 22:48:52 +0200361 self.find_tests(tests)
362 self.run_tests()
Victor Stinnerc7eab052015-09-30 00:59:35 +0200363
Victor Stinnerdad20e42015-09-29 22:48:52 +0200364 self.display_result()
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200365
366 if self.ns.verbose2 and self.bad:
367 self.rerun_failed_tests()
368
Victor Stinnerdad20e42015-09-29 22:48:52 +0200369 self.finalize()
370 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200371
372
Victor Stinner3844fe52015-09-26 10:38:01 +0200373def removepy(names):
374 if not names:
375 return
376 for idx, name in enumerate(names):
377 basename, ext = os.path.splitext(name)
378 if ext == '.py':
379 names[idx] = basename
380
381
382def count(n, word):
383 if n == 1:
384 return "%d %s" % (n, word)
385 else:
386 return "%d %ss" % (n, word)
387
388
389def printlist(x, width=70, indent=4):
390 """Print the elements of iterable x to stdout.
391
392 Optional arg width (default 70) is the maximum line length.
393 Optional arg indent (default 4) is the number of blanks with which to
394 begin each line.
395 """
396
Victor Stinner3844fe52015-09-26 10:38:01 +0200397 blanks = ' ' * indent
398 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200399 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
400 initial_indent=blanks, subsequent_indent=blanks))
401
402
403def main(tests=None, **kwargs):
404 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200405
406
407def main_in_temp_cwd():
408 """Run main() in a temporary working directory."""
409 if sysconfig.is_python_build():
410 try:
411 os.mkdir(TEMPDIR)
412 except FileExistsError:
413 pass
414
415 # Define a writable temp dir that will be used as cwd while running
416 # the tests. The name of the dir includes the pid to allow parallel
417 # testing (see the -j option).
418 test_cwd = 'test_python_{}'.format(os.getpid())
419 test_cwd = os.path.join(TEMPDIR, test_cwd)
420
421 # Run the tests in a context manager that temporarily changes the CWD to a
422 # temporary and writable directory. If it's not possible to create or
423 # change the CWD, the original CWD will be used. The original CWD is
424 # available from support.SAVEDCWD.
425 with support.temp_cwd(test_cwd, quiet=True):
426 main()