summaryrefslogtreecommitdiff
path: root/tests/transactions
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2014-03-23 20:45:22 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2014-03-23 20:45:22 +0100
commit58161e4e93d1fc796fc804c943028d4433f4813c (patch)
treebb45945369200e84f6008519a77bcf19723626b8 /tests/transactions
parenta6fc18594ebf3e4268df701de5180c126ae2ca5e (diff)
downloaddjango-58161e4e93d1fc796fc804c943028d4433f4813c.tar.gz
Fixed #22291 -- Avoided shadowing deadlock exceptions on MySQL.
Thanks err for the report.
Diffstat (limited to 'tests/transactions')
-rw-r--r--tests/transactions/tests.py47
1 files changed, 46 insertions, 1 deletions
diff --git a/tests/transactions/tests.py b/tests/transactions/tests.py
index 8b2e67a3cb..3ca6a22ecf 100644
--- a/tests/transactions/tests.py
+++ b/tests/transactions/tests.py
@@ -1,9 +1,15 @@
from __future__ import unicode_literals
import sys
+try:
+ import threading
+except ImportError:
+ threading = None
+import time
from unittest import skipIf, skipUnless
-from django.db import connection, transaction, DatabaseError, IntegrityError
+from django.db import (connection, transaction,
+ DatabaseError, IntegrityError, OperationalError)
from django.test import TransactionTestCase, skipIfDBFeature
from django.utils import six
@@ -333,6 +339,45 @@ class AtomicErrorsTests(TransactionTestCase):
self.assertEqual(Reporter.objects.get(pk=r1.pk).last_name, "Calculus")
+@skipUnless(connection.vendor == 'mysql', "MySQL-specific behaviors")
+class AtomicMySQLTests(TransactionTestCase):
+
+ available_apps = ['transactions']
+
+ @skipIf(threading is None, "Test requires threading")
+ def test_implicit_savepoint_rollback(self):
+ """MySQL implicitly rolls back savepoints when it deadlocks (#22291)."""
+
+ other_thread_ready = threading.Event()
+
+ def other_thread():
+ try:
+ with transaction.atomic():
+ Reporter.objects.create(id=1, first_name="Tintin")
+ other_thread_ready.set()
+ # We cannot synchronize the two threads with an event here
+ # because the main thread locks. Sleep for a little while.
+ time.sleep(1)
+ # 2) ... and this line deadlocks. (see below for 1)
+ Reporter.objects.exclude(id=1).update(id=2)
+ finally:
+ # This is the thread-local connection, not the main connection.
+ connection.close()
+
+ other_thread = threading.Thread(target=other_thread)
+ other_thread.start()
+ other_thread_ready.wait()
+
+ with six.assertRaisesRegex(self, OperationalError, 'Deadlock found'):
+ # Double atomic to enter a transaction and create a savepoint.
+ with transaction.atomic():
+ with transaction.atomic():
+ # 1) This line locks... (see above for 2)
+ Reporter.objects.create(id=1, first_name="Tintin")
+
+ other_thread.join()
+
+
class AtomicMiscTests(TransactionTestCase):
available_apps = []