diff options
author | David Smith <smithdc@gmail.com> | 2022-03-16 20:47:58 +0000 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-03-17 10:20:13 +0100 |
commit | ba298a32b30eb270ea0bf4f8fc208223d0b40bcd (patch) | |
tree | f31581a19861e6e3c83841d5f6476779b4dbd4d7 | |
parent | 4f92cf87b013801810226928ddd20097f6e4fccf (diff) | |
download | django-ba298a32b30eb270ea0bf4f8fc208223d0b40bcd.tar.gz |
Refs #31169 -- Prevented infinite loop in parallel tests with custom test runner when using spawn.
Regression in 3b3f38b3b09b0f2373e51406ecb8c9c45d36aebc.
Co-Authored-By: Mariusz Felisiak <felisiak.mariusz@gmail.com>
-rw-r--r-- | django/test/runner.py | 3 | ||||
-rw-r--r-- | tests/test_runner/tests.py | 45 |
2 files changed, 46 insertions, 2 deletions
diff --git a/django/test/runner.py b/django/test/runner.py index 89bb6cf1fc..fe30d2289b 100644 --- a/django/test/runner.py +++ b/django/test/runner.py @@ -492,6 +492,7 @@ class ParallelTestSuite(unittest.TestSuite): Even with tblib, errors may still occur for dynamically created exception classes which cannot be unpickled. """ + self.initialize_suite() counter = multiprocessing.Value(ctypes.c_int, 0) pool = multiprocessing.Pool( processes=self.processes, @@ -962,8 +963,6 @@ class DiscoverRunner: def run_suite(self, suite, **kwargs): kwargs = self.get_test_runner_kwargs() runner = self.test_runner(**kwargs) - if hasattr(suite, "initialize_suite"): - suite.initialize_suite() try: return runner.run(suite) finally: diff --git a/tests/test_runner/tests.py b/tests/test_runner/tests.py index c50c54f25c..c022a6fb86 100644 --- a/tests/test_runner/tests.py +++ b/tests/test_runner/tests.py @@ -639,6 +639,51 @@ class CustomTestRunnerOptionsCmdlineTests(AdminScriptTestCase): self.assertNoOutput(out) +class NoInitializeSuiteTestRunnerTests(SimpleTestCase): + @mock.patch.object(multiprocessing, "get_start_method", return_value="spawn") + @mock.patch( + "django.test.runner.ParallelTestSuite.initialize_suite", + side_effect=Exception("initialize_suite() is called."), + ) + def test_no_initialize_suite_test_runner(self, *mocked_objects): + """ + The test suite's initialize_suite() method must always be called when + using spawn. It cannot rely on a test runner implementation. + """ + + class NoInitializeSuiteTestRunner(DiscoverRunner): + def setup_test_environment(self, **kwargs): + return + + def setup_databases(self, **kwargs): + return + + def run_checks(self, databases): + return + + def teardown_databases(self, old_config, **kwargs): + return + + def teardown_test_environment(self, **kwargs): + return + + def run_suite(self, suite, **kwargs): + kwargs = self.get_test_runner_kwargs() + runner = self.test_runner(**kwargs) + return runner.run(suite) + + with self.assertRaisesMessage(Exception, "initialize_suite() is called."): + runner = NoInitializeSuiteTestRunner( + verbosity=0, interactive=False, parallel=2 + ) + runner.run_tests( + [ + "test_runner_apps.sample.tests_sample.TestDjangoTestCase", + "test_runner_apps.simple.tests", + ] + ) + + class Ticket17477RegressionTests(AdminScriptTestCase): def setUp(self): super().setUp() |