blob: fbbfa732af567adaba1cd3bb437414411e8e33d6 [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 Stinner56e05dd2015-09-29 23:15:38 +020010 findtests, runtest,
11 STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED)
Victor Stinner3844fe52015-09-26 10:38:01 +020012from test.libregrtest.cmdline import _parse_args
Victor Stinner234cbef2015-09-30 01:13:53 +020013from test.libregrtest.setup import setup_python
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
211 def display_result(self):
212 if self.interrupted:
213 # print a newline after ^C
214 print()
215 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200216 executed = set(self.good) | set(self.bad) | set(self.skipped)
217 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200218 print(count(len(omitted), "test"), "omitted:")
219 printlist(omitted)
220
221 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200222 if (not self.bad
223 and not self.skipped
224 and not self.interrupted
225 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200226 print("All", end=' ')
227 print(count(len(self.good), "test"), "OK.")
228
229 if self.ns.print_slow:
230 self.test_times.sort(reverse=True)
231 print("10 slowest tests:")
232 for time, test in self.test_times[:10]:
233 print("%s: %.1fs" % (test, time))
234
235 if self.bad:
236 print(count(len(self.bad), "test"), "failed:")
237 printlist(self.bad)
238
239 if self.environment_changed:
240 print("{} altered the execution environment:".format(
241 count(len(self.environment_changed), "test")))
242 printlist(self.environment_changed)
243
244 if self.skipped and not self.ns.quiet:
245 print(count(len(self.skipped), "test"), "skipped:")
246 printlist(self.skipped)
247
248 if self.ns.verbose2 and self.bad:
249 print("Re-running failed tests in verbose mode")
250 for test in self.bad[:]:
Victor Stinnerf33536c2015-09-30 00:48:27 +0200251 print("Re-running test %r in verbose mode" % test, flush=True)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200252 try:
253 self.ns.verbose = True
254 ok = runtest(test, True, self.ns.quiet, self.ns.huntrleaks,
255 timeout=self.ns.timeout)
256 except KeyboardInterrupt:
257 # print a newline separate from the ^C
258 print()
259 break
260 else:
261 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
262 self.bad.remove(test)
263 else:
264 if self.bad:
265 print(count(len(self.bad), 'test'), "failed again:")
266 printlist(self.bad)
267
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200268 def run_test(self, test):
269 result = runtest(test,
270 self.ns.verbose,
271 self.ns.quiet,
272 self.ns.huntrleaks,
273 output_on_failure=self.ns.verbose3,
274 timeout=self.ns.timeout,
275 failfast=self.ns.failfast,
276 match_tests=self.ns.match_tests)
277 self.accumulate_result(test, result)
278
279 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200280 if self.ns.trace:
281 import trace
282 self.tracer = trace.Trace(ignoredirs=[sys.base_prefix,
283 sys.base_exec_prefix,
284 tempfile.gettempdir()],
285 trace=False, count=True)
286
Victor Stinnerdad20e42015-09-29 22:48:52 +0200287 save_modules = sys.modules.keys()
288
289 for test_index, test in enumerate(self.tests, 1):
290 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200291 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200292 # If we're tracing code coverage, then we don't exit with status
293 # if on a false return value from main.
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200294 cmd = 'self.run_test(test)'
Victor Stinnerdad20e42015-09-29 22:48:52 +0200295 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200296 else:
297 try:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200298 self.run_test(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200299 except KeyboardInterrupt:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200300 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200301 break
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 Stinnerdad20e42015-09-29 22:48:52 +0200318 def run_tests(self):
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200319 support.verbose = self.ns.verbose # Tell tests to be moderately quiet
Victor Stinnerdad20e42015-09-29 22:48:52 +0200320 support.use_resources = self.ns.use_resources
Victor Stinner3844fe52015-09-26 10:38:01 +0200321
Victor Stinnerdad20e42015-09-29 22:48:52 +0200322 if self.ns.forever:
323 def test_forever(tests):
324 while True:
325 for test in tests:
326 yield test
327 if self.bad:
328 return
329 self.tests = test_forever(list(self.selected))
330 self.test_count = ''
331 self.test_count_width = 3
332 else:
333 self.tests = iter(self.selected)
334 self.test_count = '/{}'.format(len(self.selected))
335 self.test_count_width = len(self.test_count) - 1
336
337 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200338 from test.libregrtest.runtest_mp import run_tests_multiprocess
339 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200340 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200341 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200342
343 def finalize(self):
344 if self.next_single_filename:
345 if self.next_single_test:
346 with open(self.next_single_filename, 'w') as fp:
347 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200348 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200349 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200350
Victor Stinnerc7eab052015-09-30 00:59:35 +0200351 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200352 r = self.tracer.results()
353 r.write_results(show_missing=True, summary=True,
354 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200355
Victor Stinnerdad20e42015-09-29 22:48:52 +0200356 if self.ns.runleaks:
357 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200358
Victor Stinnerdad20e42015-09-29 22:48:52 +0200359 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200360 self.ns = self.parse_args(kwargs)
361
Victor Stinnerc7eab052015-09-30 00:59:35 +0200362 setup_python(self.ns)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200363
Victor Stinnerdad20e42015-09-29 22:48:52 +0200364 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200365 from test.libregrtest.runtest_mp import run_tests_slave
366 run_tests_slave(self.ns.slaveargs)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200367 if self.ns.wait:
368 input("Press any key to continue...")
369
Victor Stinnerdad20e42015-09-29 22:48:52 +0200370 self.find_tests(tests)
371 self.run_tests()
Victor Stinnerc7eab052015-09-30 00:59:35 +0200372
Victor Stinnerdad20e42015-09-29 22:48:52 +0200373 self.display_result()
374 self.finalize()
375 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200376
377
Victor Stinner3844fe52015-09-26 10:38:01 +0200378def removepy(names):
379 if not names:
380 return
381 for idx, name in enumerate(names):
382 basename, ext = os.path.splitext(name)
383 if ext == '.py':
384 names[idx] = basename
385
386
387def count(n, word):
388 if n == 1:
389 return "%d %s" % (n, word)
390 else:
391 return "%d %ss" % (n, word)
392
393
394def printlist(x, width=70, indent=4):
395 """Print the elements of iterable x to stdout.
396
397 Optional arg width (default 70) is the maximum line length.
398 Optional arg indent (default 4) is the number of blanks with which to
399 begin each line.
400 """
401
Victor Stinner3844fe52015-09-26 10:38:01 +0200402 blanks = ' ' * indent
403 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200404 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
405 initial_indent=blanks, subsequent_indent=blanks))
406
407
408def main(tests=None, **kwargs):
409 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200410
411
412def main_in_temp_cwd():
413 """Run main() in a temporary working directory."""
414 if sysconfig.is_python_build():
415 try:
416 os.mkdir(TEMPDIR)
417 except FileExistsError:
418 pass
419
420 # Define a writable temp dir that will be used as cwd while running
421 # the tests. The name of the dir includes the pid to allow parallel
422 # testing (see the -j option).
423 test_cwd = 'test_python_{}'.format(os.getpid())
424 test_cwd = os.path.join(TEMPDIR, test_cwd)
425
426 # Run the tests in a context manager that temporarily changes the CWD to a
427 # temporary and writable directory. If it's not possible to create or
428 # change the CWD, the original CWD will be used. The original CWD is
429 # available from support.SAVEDCWD.
430 with support.temp_cwd(test_cwd, quiet=True):
431 main()