Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 1 | import faulthandler |
| 2 | import importlib |
| 3 | import io |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 4 | import os |
| 5 | import sys |
| 6 | import time |
| 7 | import traceback |
| 8 | import unittest |
| 9 | from test import support |
Serhiy Storchaka | 8391026 | 2016-11-11 11:46:44 +0200 | [diff] [blame] | 10 | from test.libregrtest.refleak import dash_R, clear_caches |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 11 | from test.libregrtest.save_env import saved_test_environment |
| 12 | |
| 13 | |
| 14 | # Test result constants. |
| 15 | PASSED = 1 |
| 16 | FAILED = 0 |
| 17 | ENV_CHANGED = -1 |
| 18 | SKIPPED = -2 |
| 19 | RESOURCE_DENIED = -3 |
| 20 | INTERRUPTED = -4 |
| 21 | CHILD_ERROR = -5 # error in a child process |
| 22 | |
Victor Stinner | 1b8b423 | 2016-05-20 13:37:40 +0200 | [diff] [blame] | 23 | _FORMAT_TEST_RESULT = { |
| 24 | PASSED: '%s passed', |
| 25 | FAILED: '%s failed', |
| 26 | ENV_CHANGED: '%s failed (env changed)', |
| 27 | SKIPPED: '%s skipped', |
| 28 | RESOURCE_DENIED: '%s skipped (resource denied)', |
| 29 | INTERRUPTED: '%s interrupted', |
| 30 | CHILD_ERROR: '%s crashed', |
| 31 | } |
| 32 | |
Victor Stinner | 69649f2 | 2016-03-23 12:14:10 +0100 | [diff] [blame] | 33 | # Minimum duration of a test to display its duration or to mention that |
| 34 | # the test is running in background |
| 35 | PROGRESS_MIN_TIME = 30.0 # seconds |
| 36 | |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 37 | # small set of tests to determine if we have a basically functioning interpreter |
| 38 | # (i.e. if any of these fail, then anything else is likely to follow) |
| 39 | STDTESTS = [ |
| 40 | 'test_grammar', |
| 41 | 'test_opcodes', |
| 42 | 'test_dict', |
| 43 | 'test_builtin', |
| 44 | 'test_exceptions', |
| 45 | 'test_types', |
| 46 | 'test_unittest', |
| 47 | 'test_doctest', |
| 48 | 'test_doctest2', |
| 49 | 'test_support' |
| 50 | ] |
| 51 | |
| 52 | # set of tests that we don't want to be executed when using regrtest |
| 53 | NOTTESTS = set() |
| 54 | |
| 55 | |
Victor Stinner | 1b8b423 | 2016-05-20 13:37:40 +0200 | [diff] [blame] | 56 | def format_test_result(test_name, result): |
| 57 | fmt = _FORMAT_TEST_RESULT.get(result, "%s") |
| 58 | return fmt % test_name |
| 59 | |
| 60 | |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 61 | def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): |
| 62 | """Return a list of all applicable test modules.""" |
| 63 | testdir = findtestdir(testdir) |
| 64 | names = os.listdir(testdir) |
| 65 | tests = [] |
| 66 | others = set(stdtests) | nottests |
| 67 | for name in names: |
| 68 | mod, ext = os.path.splitext(name) |
| 69 | if mod[:5] == "test_" and ext in (".py", "") and mod not in others: |
| 70 | tests.append(mod) |
| 71 | return stdtests + sorted(tests) |
| 72 | |
| 73 | |
mlouielu | a49c935 | 2017-06-16 17:36:19 +0800 | [diff] [blame] | 74 | def get_abs_module(ns, test): |
| 75 | if test.startswith('test.') or ns.testdir: |
| 76 | return test |
| 77 | else: |
| 78 | # Always import it from the test package |
| 79 | return 'test.' + test |
| 80 | |
| 81 | |
Victor Stinner | 6f20a2e | 2015-09-30 02:32:11 +0200 | [diff] [blame] | 82 | def runtest(ns, test): |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 83 | """Run a single test. |
| 84 | |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 85 | ns -- regrtest namespace of options |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 86 | test -- the name of the test |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 87 | |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 88 | Returns the tuple (result, test_time), where result is one of the |
| 89 | constants: |
| 90 | |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 91 | INTERRUPTED KeyboardInterrupt when run under -j |
| 92 | RESOURCE_DENIED test skipped because resource denied |
| 93 | SKIPPED test skipped for some other reason |
| 94 | ENV_CHANGED test failed because it changed the execution environment |
| 95 | FAILED test failed |
| 96 | PASSED test passed |
| 97 | """ |
| 98 | |
Victor Stinner | 6f20a2e | 2015-09-30 02:32:11 +0200 | [diff] [blame] | 99 | output_on_failure = ns.verbose3 |
Victor Stinner | 6f20a2e | 2015-09-30 02:32:11 +0200 | [diff] [blame] | 100 | |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 101 | use_timeout = (ns.timeout is not None) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 102 | if use_timeout: |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 103 | faulthandler.dump_traceback_later(ns.timeout, exit=True) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 104 | try: |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 105 | support.match_tests = ns.match_tests |
Victor Stinner | 21a0a6c | 2017-06-30 10:59:52 +0200 | [diff] [blame] | 106 | # reset the environment_altered flag to detect if a test altered |
| 107 | # the environment |
| 108 | support.environment_altered = False |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 109 | if ns.failfast: |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 110 | support.failfast = True |
| 111 | if output_on_failure: |
| 112 | support.verbose = True |
| 113 | |
| 114 | # Reuse the same instance to all calls to runtest(). Some |
| 115 | # tests keep a reference to sys.stdout or sys.stderr |
| 116 | # (eg. test_argparse). |
| 117 | if runtest.stringio is None: |
| 118 | stream = io.StringIO() |
| 119 | runtest.stringio = stream |
| 120 | else: |
| 121 | stream = runtest.stringio |
| 122 | stream.seek(0) |
| 123 | stream.truncate() |
| 124 | |
| 125 | orig_stdout = sys.stdout |
| 126 | orig_stderr = sys.stderr |
| 127 | try: |
| 128 | sys.stdout = stream |
| 129 | sys.stderr = stream |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 130 | result = runtest_inner(ns, test, display_failure=False) |
Victor Stinner | 21c8c92 | 2016-09-23 11:15:50 +0200 | [diff] [blame] | 131 | if result[0] != PASSED: |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 132 | output = stream.getvalue() |
| 133 | orig_stderr.write(output) |
| 134 | orig_stderr.flush() |
| 135 | finally: |
| 136 | sys.stdout = orig_stdout |
| 137 | sys.stderr = orig_stderr |
| 138 | else: |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 139 | support.verbose = ns.verbose # Tell tests to be moderately quiet |
| 140 | result = runtest_inner(ns, test, display_failure=not ns.verbose) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 141 | return result |
| 142 | finally: |
| 143 | if use_timeout: |
| 144 | faulthandler.cancel_dump_traceback_later() |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 145 | cleanup_test_droppings(test, ns.verbose) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 146 | runtest.stringio = None |
| 147 | |
| 148 | |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 149 | def runtest_inner(ns, test, display_failure=True): |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 150 | support.unload(test) |
| 151 | |
| 152 | test_time = 0.0 |
| 153 | refleak = False # True if the test leaked references. |
| 154 | try: |
mlouielu | a49c935 | 2017-06-16 17:36:19 +0800 | [diff] [blame] | 155 | abstest = get_abs_module(ns, test) |
Serhiy Storchaka | 8391026 | 2016-11-11 11:46:44 +0200 | [diff] [blame] | 156 | clear_caches() |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 157 | with saved_test_environment(test, ns.verbose, ns.quiet, pgo=ns.pgo) as environment: |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 158 | start_time = time.time() |
| 159 | the_module = importlib.import_module(abstest) |
| 160 | # If the test has a test_main, that will run the appropriate |
| 161 | # tests. If not, use normal unittest test loading. |
| 162 | test_runner = getattr(the_module, "test_main", None) |
| 163 | if test_runner is None: |
| 164 | def test_runner(): |
| 165 | loader = unittest.TestLoader() |
| 166 | tests = loader.loadTestsFromModule(the_module) |
| 167 | for error in loader.errors: |
| 168 | print(error, file=sys.stderr) |
| 169 | if loader.errors: |
| 170 | raise Exception("errors while loading tests") |
| 171 | support.run_unittest(tests) |
| 172 | test_runner() |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 173 | if ns.huntrleaks: |
| 174 | refleak = dash_R(the_module, test, test_runner, ns.huntrleaks) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 175 | test_time = time.time() - start_time |
| 176 | except support.ResourceDenied as msg: |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 177 | if not ns.quiet and not ns.pgo: |
Victor Stinner | f33536c | 2015-09-30 00:48:27 +0200 | [diff] [blame] | 178 | print(test, "skipped --", msg, flush=True) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 179 | return RESOURCE_DENIED, test_time |
| 180 | except unittest.SkipTest as msg: |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 181 | if not ns.quiet and not ns.pgo: |
Victor Stinner | f33536c | 2015-09-30 00:48:27 +0200 | [diff] [blame] | 182 | print(test, "skipped --", msg, flush=True) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 183 | return SKIPPED, test_time |
| 184 | except KeyboardInterrupt: |
| 185 | raise |
| 186 | except support.TestFailed as msg: |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 187 | if not ns.pgo: |
Brett Cannon | 11faa21 | 2015-10-02 16:20:49 -0700 | [diff] [blame] | 188 | if display_failure: |
| 189 | print("test", test, "failed --", msg, file=sys.stderr, |
| 190 | flush=True) |
| 191 | else: |
| 192 | print("test", test, "failed", file=sys.stderr, flush=True) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 193 | return FAILED, test_time |
| 194 | except: |
| 195 | msg = traceback.format_exc() |
Victor Stinner | ab98367 | 2016-08-22 14:28:52 +0200 | [diff] [blame] | 196 | if not ns.pgo: |
Brett Cannon | 11faa21 | 2015-10-02 16:20:49 -0700 | [diff] [blame] | 197 | print("test", test, "crashed --", msg, file=sys.stderr, |
| 198 | flush=True) |
Victor Stinner | 3844fe5 | 2015-09-26 10:38:01 +0200 | [diff] [blame] | 199 | return FAILED, test_time |
| 200 | else: |
| 201 | if refleak: |
| 202 | return FAILED, test_time |
| 203 | if environment.changed: |
| 204 | return ENV_CHANGED, test_time |
| 205 | return PASSED, test_time |
| 206 | |
| 207 | |
| 208 | def cleanup_test_droppings(testname, verbose): |
| 209 | import shutil |
| 210 | import stat |
| 211 | import gc |
| 212 | |
| 213 | # First kill any dangling references to open files etc. |
| 214 | # This can also issue some ResourceWarnings which would otherwise get |
| 215 | # triggered during the following test run, and possibly produce failures. |
| 216 | gc.collect() |
| 217 | |
| 218 | # Try to clean up junk commonly left behind. While tests shouldn't leave |
| 219 | # any files or directories behind, when a test fails that can be tedious |
| 220 | # for it to arrange. The consequences can be especially nasty on Windows, |
| 221 | # since if a test leaves a file open, it cannot be deleted by name (while |
| 222 | # there's nothing we can do about that here either, we can display the |
| 223 | # name of the offending test, which is a real help). |
| 224 | for name in (support.TESTFN, |
| 225 | "db_home", |
| 226 | ): |
| 227 | if not os.path.exists(name): |
| 228 | continue |
| 229 | |
| 230 | if os.path.isdir(name): |
| 231 | kind, nuker = "directory", shutil.rmtree |
| 232 | elif os.path.isfile(name): |
| 233 | kind, nuker = "file", os.unlink |
| 234 | else: |
| 235 | raise SystemError("os.path says %r exists but is neither " |
| 236 | "directory nor file" % name) |
| 237 | |
| 238 | if verbose: |
| 239 | print("%r left behind %s %r" % (testname, kind, name)) |
| 240 | try: |
| 241 | # if we have chmod, fix possible permissions problems |
| 242 | # that might prevent cleanup |
| 243 | if (hasattr(os, 'chmod')): |
| 244 | os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) |
| 245 | nuker(name) |
| 246 | except Exception as msg: |
| 247 | print(("%r left behind %s %r and it couldn't be " |
| 248 | "removed: %s" % (testname, kind, name, msg)), file=sys.stderr) |
| 249 | |
| 250 | |
| 251 | def findtestdir(path=None): |
| 252 | return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir |