blob: e1a99fb50b0a0874161e3689ec09f3127c566517 [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
275 self.tracer = trace.Trace(ignoredirs=[sys.base_prefix,
276 sys.base_exec_prefix,
277 tempfile.gettempdir()],
278 trace=False, count=True)
279
Victor Stinnerdad20e42015-09-29 22:48:52 +0200280 save_modules = sys.modules.keys()
281
282 for test_index, test in enumerate(self.tests, 1):
283 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200284 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200285 # If we're tracing code coverage, then we don't exit with status
286 # if on a false return value from main.
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200287 cmd = ('result = runtest(self.ns, test); '
288 'self.accumulate_result(test, result)')
Victor Stinnerdad20e42015-09-29 22:48:52 +0200289 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200290 else:
291 try:
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200292 result = runtest(self.ns, test)
293 self.accumulate_result(test, result)
Victor Stinner3844fe52015-09-26 10:38:01 +0200294 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200295 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200296 break
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200297
Victor Stinnerdad20e42015-09-29 22:48:52 +0200298 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200299 gc.collect()
300 if gc.garbage:
301 print("Warning: test created", len(gc.garbage), end=' ')
302 print("uncollectable object(s).")
303 # move the uncollectable objects somewhere so we don't see
304 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200305 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200306 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200307
Victor Stinner3844fe52015-09-26 10:38:01 +0200308 # Unload the newly imported modules (best effort finalization)
309 for module in sys.modules.keys():
310 if module not in save_modules and module.startswith("test."):
311 support.unload(module)
312
Victor Stinnerb4084352015-09-30 02:39:22 +0200313 def _test_forever(self, tests):
314 while True:
315 for test in tests:
316 yield test
317 if self.bad:
318 return
Victor Stinner3844fe52015-09-26 10:38:01 +0200319
Victor Stinnerb4084352015-09-30 02:39:22 +0200320 def run_tests(self):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200321 if self.ns.forever:
Victor Stinner9a142142015-09-30 13:51:17 +0200322 self.tests = self._test_forever(list(self.selected))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200323 self.test_count = ''
324 self.test_count_width = 3
325 else:
326 self.tests = iter(self.selected)
327 self.test_count = '/{}'.format(len(self.selected))
328 self.test_count_width = len(self.test_count) - 1
329
330 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200331 from test.libregrtest.runtest_mp import run_tests_multiprocess
332 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200333 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200334 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200335
336 def finalize(self):
337 if self.next_single_filename:
338 if self.next_single_test:
339 with open(self.next_single_filename, 'w') as fp:
340 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200341 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200342 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200343
Victor Stinnerc7eab052015-09-30 00:59:35 +0200344 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200345 r = self.tracer.results()
346 r.write_results(show_missing=True, summary=True,
347 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200348
Victor Stinnerdad20e42015-09-29 22:48:52 +0200349 if self.ns.runleaks:
350 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200351
Victor Stinnerdad20e42015-09-29 22:48:52 +0200352 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200353 self.ns = self.parse_args(kwargs)
354
Victor Stinnerdad20e42015-09-29 22:48:52 +0200355 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200356 from test.libregrtest.runtest_mp import run_tests_slave
357 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200358
Victor Stinnerc7eab052015-09-30 00:59:35 +0200359 if self.ns.wait:
360 input("Press any key to continue...")
361
Victor Stinnera2045022015-09-30 02:17:28 +0200362 setup_tests(self.ns)
Victor Stinnerecef6222015-09-30 01:39:28 +0200363
Victor Stinnerdad20e42015-09-29 22:48:52 +0200364 self.find_tests(tests)
365 self.run_tests()
Victor Stinnerc7eab052015-09-30 00:59:35 +0200366
Victor Stinnerdad20e42015-09-29 22:48:52 +0200367 self.display_result()
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200368
369 if self.ns.verbose2 and self.bad:
370 self.rerun_failed_tests()
371
Victor Stinnerdad20e42015-09-29 22:48:52 +0200372 self.finalize()
373 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200374
375
Victor Stinner3844fe52015-09-26 10:38:01 +0200376def removepy(names):
377 if not names:
378 return
379 for idx, name in enumerate(names):
380 basename, ext = os.path.splitext(name)
381 if ext == '.py':
382 names[idx] = basename
383
384
385def count(n, word):
386 if n == 1:
387 return "%d %s" % (n, word)
388 else:
389 return "%d %ss" % (n, word)
390
391
392def printlist(x, width=70, indent=4):
393 """Print the elements of iterable x to stdout.
394
395 Optional arg width (default 70) is the maximum line length.
396 Optional arg indent (default 4) is the number of blanks with which to
397 begin each line.
398 """
399
Victor Stinner3844fe52015-09-26 10:38:01 +0200400 blanks = ' ' * indent
401 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200402 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
403 initial_indent=blanks, subsequent_indent=blanks))
404
405
406def main(tests=None, **kwargs):
407 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200408
409
410def main_in_temp_cwd():
411 """Run main() in a temporary working directory."""
412 if sysconfig.is_python_build():
413 try:
414 os.mkdir(TEMPDIR)
415 except FileExistsError:
416 pass
417
418 # Define a writable temp dir that will be used as cwd while running
419 # the tests. The name of the dir includes the pid to allow parallel
420 # testing (see the -j option).
421 test_cwd = 'test_python_{}'.format(os.getpid())
422 test_cwd = os.path.join(TEMPDIR, test_cwd)
423
424 # Run the tests in a context manager that temporarily changes the CWD to a
425 # temporary and writable directory. If it's not possible to create or
426 # change the CWD, the original CWD will be used. The original CWD is
427 # available from support.SAVEDCWD.
428 with support.temp_cwd(test_cwd, quiet=True):
429 main()