summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/test/testcases.py6
-rw-r--r--docs/releases/1.8.4.txt3
-rw-r--r--tests/test_utils/tests.py33
3 files changed, 41 insertions, 1 deletions
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 6e16cfb247..eed67e9cda 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -1017,7 +1017,11 @@ class TestCase(TransactionTestCase):
except Exception:
cls._rollback_atomics(cls.cls_atomics)
raise
- cls.setUpTestData()
+ try:
+ cls.setUpTestData()
+ except Exception:
+ cls._rollback_atomics(cls.cls_atomics)
+ raise
@classmethod
def tearDownClass(cls):
diff --git a/docs/releases/1.8.4.txt b/docs/releases/1.8.4.txt
index 81b00c1800..53c58e6a90 100644
--- a/docs/releases/1.8.4.txt
+++ b/docs/releases/1.8.4.txt
@@ -18,3 +18,6 @@ Bugfixes
* Fixed ``QuerySet.raw()`` so ``InvalidQuery`` is not raised when using the
``db_column`` name of a ``ForeignKey`` field with ``primary_key=True``
(:ticket:`12768`).
+
+* Prevented an exception in ``TestCase.setUpTestData()`` from leaking the
+ transaction (:ticket:`25176`).
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index a02bfb6397..d7f12d76ba 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -944,6 +944,39 @@ class OverrideSettingsTests(SimpleTestCase):
self.assertIn(expected_location, finder.locations)
+class TestBadSetUpTestData(TestCase):
+ """
+ An exception in setUpTestData() shouldn't leak a transaction which would
+ cascade across the rest of the test suite.
+ """
+ class MyException(Exception):
+ pass
+
+ @classmethod
+ def setUpClass(cls):
+ try:
+ super(TestBadSetupTestData, cls).setUpClass()
+ except cls.MyException:
+ cls._in_atomic_block = connection.in_atomic_block
+
+ @classmethod
+ def tearDownClass(Cls):
+ # override to avoid a second cls._rollback_atomics() which would fail.
+ # Normal setUpClass() methods won't have exception handling so this
+ # method wouldn't typically be run.
+ pass
+
+ @classmethod
+ def setUpTestData(cls):
+ # Simulate a broken setUpTestData() method.
+ raise cls.MyException()
+
+ def test_failure_in_setUpTestData_should_rollback_transaction(self):
+ # setUpTestData() should call _rollback_atomics() so that the
+ # transaction doesn't leak.
+ self.assertFalse(self._in_atomic_block)
+
+
class DisallowedDatabaseQueriesTests(SimpleTestCase):
def test_disallowed_database_queries(self):
expected_message = (