blob: e68597038e1702f3dc02913fc960920305353f0a [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 Stinner8bb19f02015-09-30 01:32:39 +020010 findtests, runtest_ns,
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 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
Victor Stinner8bb19f02015-09-30 01:32:39 +0200254 ok = runtest_ns(test, True, self.ns)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200255 except KeyboardInterrupt:
256 # print a newline separate from the ^C
257 print()
258 break
259 else:
260 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
261 self.bad.remove(test)
262 else:
263 if self.bad:
264 print(count(len(self.bad), 'test'), "failed again:")
265 printlist(self.bad)
266
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200267 def run_test(self, test):
Victor Stinner8bb19f02015-09-30 01:32:39 +0200268 result = runtest_ns(test, self.ns.verbose, self.ns,
269 output_on_failure=self.ns.verbose3,
270 failfast=self.ns.failfast,
271 match_tests=self.ns.match_tests)
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200272 self.accumulate_result(test, result)
273
274 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200275 if self.ns.trace:
276 import trace
277 self.tracer = trace.Trace(ignoredirs=[sys.base_prefix,
278 sys.base_exec_prefix,
279 tempfile.gettempdir()],
280 trace=False, count=True)
281
Victor Stinnerdad20e42015-09-29 22:48:52 +0200282 save_modules = sys.modules.keys()
283
284 for test_index, test in enumerate(self.tests, 1):
285 self.display_progress(test_index, test)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200286 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200287 # If we're tracing code coverage, then we don't exit with status
288 # if on a false return value from main.
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200289 cmd = 'self.run_test(test)'
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 Stinnerbd1a72c2015-09-29 23:36:27 +0200293 self.run_test(test)
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 Stinnerdad20e42015-09-29 22:48:52 +0200313 def run_tests(self):
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200314 support.verbose = self.ns.verbose # Tell tests to be moderately quiet
Victor Stinnerdad20e42015-09-29 22:48:52 +0200315 support.use_resources = self.ns.use_resources
Victor Stinner3844fe52015-09-26 10:38:01 +0200316
Victor Stinnerdad20e42015-09-29 22:48:52 +0200317 if self.ns.forever:
318 def test_forever(tests):
319 while True:
320 for test in tests:
321 yield test
322 if self.bad:
323 return
324 self.tests = test_forever(list(self.selected))
325 self.test_count = ''
326 self.test_count_width = 3
327 else:
328 self.tests = iter(self.selected)
329 self.test_count = '/{}'.format(len(self.selected))
330 self.test_count_width = len(self.test_count) - 1
331
332 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200333 from test.libregrtest.runtest_mp import run_tests_multiprocess
334 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200335 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200336 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200337
338 def finalize(self):
339 if self.next_single_filename:
340 if self.next_single_test:
341 with open(self.next_single_filename, 'w') as fp:
342 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200343 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200344 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200345
Victor Stinnerc7eab052015-09-30 00:59:35 +0200346 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200347 r = self.tracer.results()
348 r.write_results(show_missing=True, summary=True,
349 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200350
Victor Stinnerdad20e42015-09-29 22:48:52 +0200351 if self.ns.runleaks:
352 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200353
Victor Stinnerdad20e42015-09-29 22:48:52 +0200354 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200355 self.ns = self.parse_args(kwargs)
356
Victor Stinnerdad20e42015-09-29 22:48:52 +0200357 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200358 from test.libregrtest.runtest_mp import run_tests_slave
359 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200360
Victor Stinnerc7eab052015-09-30 00:59:35 +0200361 if self.ns.wait:
362 input("Press any key to continue...")
363
Victor Stinnerecef6222015-09-30 01:39:28 +0200364 setup_python(self.ns)
365
Victor Stinnerdad20e42015-09-29 22:48:52 +0200366 self.find_tests(tests)
367 self.run_tests()
Victor Stinnerc7eab052015-09-30 00:59:35 +0200368
Victor Stinnerdad20e42015-09-29 22:48:52 +0200369 self.display_result()
370 self.finalize()
371 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200372
373
Victor Stinner3844fe52015-09-26 10:38:01 +0200374def removepy(names):
375 if not names:
376 return
377 for idx, name in enumerate(names):
378 basename, ext = os.path.splitext(name)
379 if ext == '.py':
380 names[idx] = basename
381
382
383def count(n, word):
384 if n == 1:
385 return "%d %s" % (n, word)
386 else:
387 return "%d %ss" % (n, word)
388
389
390def printlist(x, width=70, indent=4):
391 """Print the elements of iterable x to stdout.
392
393 Optional arg width (default 70) is the maximum line length.
394 Optional arg indent (default 4) is the number of blanks with which to
395 begin each line.
396 """
397
Victor Stinner3844fe52015-09-26 10:38:01 +0200398 blanks = ' ' * indent
399 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200400 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
401 initial_indent=blanks, subsequent_indent=blanks))
402
403
404def main(tests=None, **kwargs):
405 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200406
407
408def main_in_temp_cwd():
409 """Run main() in a temporary working directory."""
410 if sysconfig.is_python_build():
411 try:
412 os.mkdir(TEMPDIR)
413 except FileExistsError:
414 pass
415
416 # Define a writable temp dir that will be used as cwd while running
417 # the tests. The name of the dir includes the pid to allow parallel
418 # testing (see the -j option).
419 test_cwd = 'test_python_{}'.format(os.getpid())
420 test_cwd = os.path.join(TEMPDIR, test_cwd)
421
422 # Run the tests in a context manager that temporarily changes the CWD to a
423 # temporary and writable directory. If it's not possible to create or
424 # change the CWD, the original CWD will be used. The original CWD is
425 # available from support.SAVEDCWD.
426 with support.temp_cwd(test_cwd, quiet=True):
427 main()