diff options
author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2014-03-23 20:45:22 +0100 |
---|---|---|
committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2014-03-23 20:45:22 +0100 |
commit | 58161e4e93d1fc796fc804c943028d4433f4813c (patch) | |
tree | bb45945369200e84f6008519a77bcf19723626b8 /tests/transactions | |
parent | a6fc18594ebf3e4268df701de5180c126ae2ca5e (diff) | |
download | django-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.py | 47 |
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 = [] |