diff options
| author | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-11-26 10:00:38 -0500 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-12-03 16:04:22 -0500 |
| commit | bd4a562a8849147d4aa4bd42f7fdb1b51f89bb84 (patch) | |
| tree | c68ca990737cbe8c17b4954efc62414ceb7fc10b | |
| parent | 93540b34d4ef46f68df2c8bfe90447d0f649a852 (diff) | |
Closed pool when parallel test runner encounters unpicklable exceptions.
| -rw-r--r-- | django/test/runner.py | 55 | ||||
| -rw-r--r-- | tests/test_runner/test_parallel.py | 5 |
2 files changed, 29 insertions, 31 deletions
diff --git a/django/test/runner.py b/django/test/runner.py index ecae164d7f..5cd72119f5 100644 --- a/django/test/runner.py +++ b/django/test/runner.py @@ -567,7 +567,14 @@ class ParallelTestSuite(unittest.TestSuite): """ self.initialize_suite() counter = multiprocessing.Value(ctypes.c_int, 0) - pool = multiprocessing.Pool( + args = [ + (self.runner_class, index, subsuite, self.failfast, self.buffer) + for index, subsuite in enumerate(self.subsuites) + ] + # Don't buffer in the main process to avoid error propagation issues. + result.buffer = False + + with multiprocessing.Pool( processes=self.processes, initializer=functools.partial(_safe_init_worker, self.init_worker.__func__), initargs=[ @@ -579,38 +586,30 @@ class ParallelTestSuite(unittest.TestSuite): self.debug_mode, self.used_aliases, ], - ) - args = [ - (self.runner_class, index, subsuite, self.failfast, self.buffer) - for index, subsuite in enumerate(self.subsuites) - ] - # Don't buffer in the main process to avoid error propagation issues. - result.buffer = False + ) as pool: + test_results = pool.imap_unordered(self.run_subsuite.__func__, args) - test_results = pool.imap_unordered(self.run_subsuite.__func__, args) + while True: + if result.shouldStop: + pool.terminate() + break - while True: - if result.shouldStop: - pool.terminate() - break - - try: - subsuite_index, events = test_results.next(timeout=0.1) - except multiprocessing.TimeoutError as err: - if counter.value < 0: - err.add_note("ERROR: _init_worker failed, see prior traceback") + try: + subsuite_index, events = test_results.next(timeout=0.1) + except multiprocessing.TimeoutError as err: + if counter.value < 0: + err.add_note("ERROR: _init_worker failed, see prior traceback") + raise + continue + except StopIteration: pool.close() - raise - continue - except StopIteration: - pool.close() - break + break - tests = list(self.subsuites[subsuite_index]) - for event in events: - self.handle_event(result, tests, event) + tests = list(self.subsuites[subsuite_index]) + for event in events: + self.handle_event(result, tests, event) - pool.join() + pool.join() return result diff --git a/tests/test_runner/test_parallel.py b/tests/test_runner/test_parallel.py index 32cc971d30..193afea1cc 100644 --- a/tests/test_runner/test_parallel.py +++ b/tests/test_runner/test_parallel.py @@ -309,9 +309,8 @@ class ParallelTestSuiteTest(SimpleTestCase): test_result.shouldStop = True return (0, remote_result.events) - mock_pool.return_value.imap_unordered.return_value = unittest.mock.Mock( - next=fake_next - ) + mock_imap = mock_pool.return_value.__enter__.return_value.imap_unordered + mock_imap.return_value = unittest.mock.Mock(next=fake_next) pts.run(test_result) self.assertIn("ValueError: woops", test_result.errors[0][1]) |
