Code

Ticket #9479: 9479-r10858.diff

File 9479-r10858.diff, 3.3 KB (added by russellm, 5 years ago)

Test case demonstrating problem

Line 
1diff --git a/tests/regressiontests/delete_regress/__init__.py b/tests/regressiontests/delete_regress/__init__.py
2new file mode 100644
3index 0000000..8b13789
4--- /dev/null
5+++ b/tests/regressiontests/delete_regress/__init__.py
6@@ -0,0 +1 @@
7+
8diff --git a/tests/regressiontests/delete_regress/models.py b/tests/regressiontests/delete_regress/models.py
9new file mode 100644
10index 0000000..20d41ac
11--- /dev/null
12+++ b/tests/regressiontests/delete_regress/models.py
13@@ -0,0 +1,78 @@
14+from django.conf import settings
15+from django.db import models, backend, connection, transaction
16+from django.test import TransactionTestCase
17+
18+class Child(models.Model):
19+    data = models.IntegerField()
20+
21+class Parent(models.Model):
22+    ref = models.ForeignKey(Child)
23+
24+if settings.DATABASE_ENGINE != 'sqlite3':
25+    class DeleteLockingTest(TransactionTestCase):
26+        def setUp(self):
27+            # Create a second connection to the database
28+            self.conn2 = backend.DatabaseWrapper({
29+                'DATABASE_HOST': settings.DATABASE_HOST,
30+                'DATABASE_NAME': settings.DATABASE_NAME,
31+                'DATABASE_OPTIONS': settings.DATABASE_OPTIONS,
32+                'DATABASE_PASSWORD': settings.DATABASE_PASSWORD,
33+                'DATABASE_PORT': settings.DATABASE_PORT,
34+                'DATABASE_USER': settings.DATABASE_USER,
35+                'TIME_ZONE': settings.TIME_ZONE,
36+            })
37+
38+            # Put both DB connections into managed transaction mode
39+            transaction.enter_transaction_management(True)
40+            self.conn2._enter_transaction_management(True)
41+
42+        def tearDown(self):
43+            # Close down the second connection.
44+            self.conn2.close()
45+
46+        def test_concurrent_delete(self):
47+            "Deletes on concurrent transactions don't collide and lock the database"
48+
49+            # Create some dummy data
50+            c1 = Child(id=1, data=1)
51+            c2 = Child(id=2, data=2)
52+            c1.save()
53+            c2.save()
54+
55+            p1 = Parent(id=1)
56+            p2 = Parent(id=2)
57+
58+            p1.ref = c1
59+            p2.ref = c2
60+
61+            p1.save()
62+            p2.save()
63+            transaction.commit()
64+
65+            self.assertEquals(2, Child.objects.count())
66+            self.assertEquals(2, Parent.objects.count())
67+
68+            # Now with connection 1 committed, delete something using connection 2
69+            # ... but don't commit the deletion.
70+
71+            cursor2 = self.conn2.cursor()
72+
73+            cursor2.execute('DELETE from delete_regress_parent WHERE id=1')
74+            cursor2.execute('DELETE from delete_regress_child WHERE id=1')
75+
76+            # NOTE! If you uncomment this line, the test will pass.
77+            # However, the test _should_ pass without the need for this commit
78+            # self.conn2._commit()
79+
80+            # Back on connection 1, try to delete some objects that will result
81+            # in the bulk deletion collect operation finding the same objects
82+            # that have just been deleted in the second connection.
83+
84+            # This command will not return lock
85+            Child.objects.filter(pk=1).delete()
86+
87+            self.conn2._commit()
88+            transaction.commit()
89+
90+            self.assertEquals(1, Child.objects.count())
91+            self.assertEquals(1, Parent.objects.count())
92\ No newline at end of file