From a708b8fcbe49e857d9f900d6375d56f61e22212a Mon Sep 17 00:00:00 2001
From: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Sat, 24 Nov 2012 09:48:21 +0100
Subject: [PATCH] [1.5.x] Fixed #19343 -- Deadlock with TransactionTestCase +
 TEST_MIRROR + multi_db.

Thanks Jeremy Dunck for the review.

Backport of be64dd3 from master.
---
 django/test/testcases.py | 37 ++++++++++++++-----------------------
 1 file changed, 14 insertions(+), 23 deletions(-)

diff --git a/django/test/testcases.py b/django/test/testcases.py
index 0f76e11c1a..3bb40a5838 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -416,6 +416,15 @@ class TransactionTestCase(SimpleTestCase):
         self._urlconf_setup()
         mail.outbox = []
 
+    def _databases_names(self, include_mirrors=True):
+        # If the test case has a multi_db=True flag, act on all databases,
+        # including mirrors or not. Otherwise, just on the default DB.
+        if getattr(self, 'multi_db', False):
+            return [alias for alias in connections
+                    if include_mirrors or not connections[alias].settings_dict['TEST_MIRROR']]
+        else:
+            return [DEFAULT_DB_ALIAS]
+
     def _reset_sequences(self, db_name):
         conn = connections[db_name]
         if conn.features.supports_sequence_reset:
@@ -433,10 +442,7 @@ class TransactionTestCase(SimpleTestCase):
                 transaction.commit_unless_managed(using=db_name)
 
     def _fixture_setup(self):
-        # If the test case has a multi_db=True flag, act on all databases.
-        # Otherwise, just on the default DB.
-        db_names = connections if getattr(self, 'multi_db', False) else [DEFAULT_DB_ALIAS]
-        for db_name in db_names:
+        for db_name in self._databases_names(include_mirrors=False):
             # Reset sequences
             if self.reset_sequences:
                 self._reset_sequences(db_name)
@@ -502,16 +508,12 @@ class TransactionTestCase(SimpleTestCase):
             conn.close()
 
     def _fixture_teardown(self):
-        # If the test case has a multi_db=True flag, flush all databases.
-        # Otherwise, just flush default.
-        databases = connections if getattr(self, 'multi_db', False) else [DEFAULT_DB_ALIAS]
-
         # Roll back any pending transactions in order to avoid a deadlock
         # during flush when TEST_MIRROR is used (#18984).
         for conn in connections.all():
             conn.rollback_unless_managed()
 
-        for db in databases:
+        for db in self._databases_names(include_mirrors=False):
             call_command('flush', verbosity=0, interactive=False, database=db,
                          skip_validation=True, reset_sequences=False)
 
@@ -796,11 +798,7 @@ class TestCase(TransactionTestCase):
 
         assert not self.reset_sequences, 'reset_sequences cannot be used on TestCase instances'
 
-        # If the test case has a multi_db=True flag, setup all databases.
-        # Otherwise, just use default.
-        db_names = connections if getattr(self, 'multi_db', False) else [DEFAULT_DB_ALIAS]
-
-        for db_name in db_names:
+        for db_name in self._databases_names():
             transaction.enter_transaction_management(using=db_name)
             transaction.managed(True, using=db_name)
         disable_transaction_methods()
@@ -808,7 +806,7 @@ class TestCase(TransactionTestCase):
         from django.contrib.sites.models import Site
         Site.objects.clear_cache()
 
-        for db in db_names:
+        for db in self._databases_names(include_mirrors=False):
             if hasattr(self, 'fixtures'):
                 call_command('loaddata', *self.fixtures,
                              **{
@@ -822,15 +820,8 @@ class TestCase(TransactionTestCase):
         if not connections_support_transactions():
             return super(TestCase, self)._fixture_teardown()
 
-        # If the test case has a multi_db=True flag, teardown all databases.
-        # Otherwise, just teardown default.
-        if getattr(self, 'multi_db', False):
-            databases = connections
-        else:
-            databases = [DEFAULT_DB_ALIAS]
-
         restore_transaction_methods()
-        for db in databases:
+        for db in self._databases_names():
             transaction.rollback(using=db)
             transaction.leave_transaction_management(using=db)