Fixed multiple database tests that broke foreign keys constraints. Refs #17055.
The problem was masked by the rollback at the end of each transactional test on backends that deferred constraints checks; it appeared only on MySQL + InnoDB. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16995 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
03316579f4
commit
8fb7a90026
|
@ -6,6 +6,7 @@ from StringIO import StringIO
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core import management
|
from django.core import management
|
||||||
from django.db import connections, router, DEFAULT_DB_ALIAS
|
from django.db import connections, router, DEFAULT_DB_ALIAS
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
|
@ -14,6 +15,16 @@ from django.test import TestCase
|
||||||
from .models import Book, Person, Pet, Review, UserProfile
|
from .models import Book, Person, Pet, Review, UserProfile
|
||||||
|
|
||||||
|
|
||||||
|
def copy_content_types_from_default_to_other():
|
||||||
|
# On post_syncdb, content types are created in the 'default' database.
|
||||||
|
# However, tests of generic foreign keys require them in 'other' too.
|
||||||
|
# The problem is masked on backends that defer constraints checks: at the
|
||||||
|
# end of each test, there's a rollback, and constraints are never checked.
|
||||||
|
# It only appears on MySQL + InnoDB.
|
||||||
|
for ct in ContentType.objects.using('default').all():
|
||||||
|
ct.save(using='other')
|
||||||
|
|
||||||
|
|
||||||
class QueryTestCase(TestCase):
|
class QueryTestCase(TestCase):
|
||||||
multi_db = True
|
multi_db = True
|
||||||
|
|
||||||
|
@ -692,6 +703,8 @@ class QueryTestCase(TestCase):
|
||||||
|
|
||||||
def test_generic_key_separation(self):
|
def test_generic_key_separation(self):
|
||||||
"Generic fields are constrained to a single database"
|
"Generic fields are constrained to a single database"
|
||||||
|
copy_content_types_from_default_to_other()
|
||||||
|
|
||||||
# Create a book and author on the default database
|
# Create a book and author on the default database
|
||||||
pro = Book.objects.create(title="Pro Django",
|
pro = Book.objects.create(title="Pro Django",
|
||||||
published=datetime.date(2008, 12, 16))
|
published=datetime.date(2008, 12, 16))
|
||||||
|
@ -719,6 +732,8 @@ class QueryTestCase(TestCase):
|
||||||
|
|
||||||
def test_generic_key_reverse_operations(self):
|
def test_generic_key_reverse_operations(self):
|
||||||
"Generic reverse manipulations are all constrained to a single DB"
|
"Generic reverse manipulations are all constrained to a single DB"
|
||||||
|
copy_content_types_from_default_to_other()
|
||||||
|
|
||||||
dive = Book.objects.using('other').create(title="Dive into Python",
|
dive = Book.objects.using('other').create(title="Dive into Python",
|
||||||
published=datetime.date(2009, 5, 4))
|
published=datetime.date(2009, 5, 4))
|
||||||
|
|
||||||
|
@ -763,6 +778,8 @@ class QueryTestCase(TestCase):
|
||||||
|
|
||||||
def test_generic_key_cross_database_protection(self):
|
def test_generic_key_cross_database_protection(self):
|
||||||
"Operations that involve sharing generic key objects across databases raise an error"
|
"Operations that involve sharing generic key objects across databases raise an error"
|
||||||
|
copy_content_types_from_default_to_other()
|
||||||
|
|
||||||
# Create a book and author on the default database
|
# Create a book and author on the default database
|
||||||
pro = Book.objects.create(title="Pro Django",
|
pro = Book.objects.create(title="Pro Django",
|
||||||
published=datetime.date(2008, 12, 16))
|
published=datetime.date(2008, 12, 16))
|
||||||
|
@ -814,6 +831,8 @@ class QueryTestCase(TestCase):
|
||||||
|
|
||||||
def test_generic_key_deletion(self):
|
def test_generic_key_deletion(self):
|
||||||
"Cascaded deletions of Generic Key relations issue queries on the right database"
|
"Cascaded deletions of Generic Key relations issue queries on the right database"
|
||||||
|
copy_content_types_from_default_to_other()
|
||||||
|
|
||||||
dive = Book.objects.using('other').create(title="Dive into Python",
|
dive = Book.objects.using('other').create(title="Dive into Python",
|
||||||
published=datetime.date(2009, 5, 4))
|
published=datetime.date(2009, 5, 4))
|
||||||
review = Review.objects.using('other').create(source="Python Weekly", content_object=dive)
|
review = Review.objects.using('other').create(source="Python Weekly", content_object=dive)
|
||||||
|
@ -1217,6 +1236,15 @@ class RouterTestCase(TestCase):
|
||||||
water = Book(title="Dive into Water", published=datetime.date(2001, 1, 1), editor=mark)
|
water = Book(title="Dive into Water", published=datetime.date(2001, 1, 1), editor=mark)
|
||||||
self.assertEqual(water._state.db, 'default')
|
self.assertEqual(water._state.db, 'default')
|
||||||
|
|
||||||
|
# For the remainder of this test, create a copy of 'mark' in the
|
||||||
|
# 'default' database to prevent integrity errors on backends that
|
||||||
|
# don't defer constraints checks until the end of the transaction
|
||||||
|
mark.save(using='default')
|
||||||
|
|
||||||
|
# This moved 'mark' in the 'default' database, move it back in 'other'
|
||||||
|
mark.save(using='other')
|
||||||
|
self.assertEqual(mark._state.db, 'other')
|
||||||
|
|
||||||
# If you create an object through a FK relation, it will be
|
# If you create an object through a FK relation, it will be
|
||||||
# written to the write database, even if the original object
|
# written to the write database, even if the original object
|
||||||
# was on the read database
|
# was on the read database
|
||||||
|
@ -1372,6 +1400,8 @@ class RouterTestCase(TestCase):
|
||||||
|
|
||||||
def test_generic_key_cross_database_protection(self):
|
def test_generic_key_cross_database_protection(self):
|
||||||
"Generic Key operations can span databases if they share a source"
|
"Generic Key operations can span databases if they share a source"
|
||||||
|
copy_content_types_from_default_to_other()
|
||||||
|
|
||||||
# Create a book and author on the default database
|
# Create a book and author on the default database
|
||||||
pro = Book.objects.using('default'
|
pro = Book.objects.using('default'
|
||||||
).create(title="Pro Django", published=datetime.date(2008, 12, 16))
|
).create(title="Pro Django", published=datetime.date(2008, 12, 16))
|
||||||
|
@ -1459,7 +1489,8 @@ class RouterTestCase(TestCase):
|
||||||
published=datetime.date(2008, 12, 16))
|
published=datetime.date(2008, 12, 16))
|
||||||
|
|
||||||
marty = Person.objects.using('other').create(pk=1, name="Marty Alchin")
|
marty = Person.objects.using('other').create(pk=1, name="Marty Alchin")
|
||||||
pro.authors = [marty]
|
pro_authors = pro.authors.using('other')
|
||||||
|
authors = [marty]
|
||||||
|
|
||||||
self.assertEqual(pro.authors.db, 'other')
|
self.assertEqual(pro.authors.db, 'other')
|
||||||
self.assertEqual(pro.authors.db_manager('default').db, 'default')
|
self.assertEqual(pro.authors.db_manager('default').db, 'default')
|
||||||
|
@ -1482,6 +1513,8 @@ class RouterTestCase(TestCase):
|
||||||
|
|
||||||
def test_generic_key_managers(self):
|
def test_generic_key_managers(self):
|
||||||
"Generic key relations are represented by managers, and can be controlled like managers"
|
"Generic key relations are represented by managers, and can be controlled like managers"
|
||||||
|
copy_content_types_from_default_to_other()
|
||||||
|
|
||||||
pro = Book.objects.using('other').create(title="Pro Django",
|
pro = Book.objects.using('other').create(title="Pro Django",
|
||||||
published=datetime.date(2008, 12, 16))
|
published=datetime.date(2008, 12, 16))
|
||||||
|
|
||||||
|
@ -1745,14 +1778,20 @@ class SignalTests(TestCase):
|
||||||
"""
|
"""
|
||||||
# Make a receiver
|
# Make a receiver
|
||||||
receiver = DatabaseReceiver()
|
receiver = DatabaseReceiver()
|
||||||
# Connect it, and make the models
|
# Connect it
|
||||||
signals.m2m_changed.connect(receiver=receiver)
|
signals.m2m_changed.connect(receiver=receiver)
|
||||||
|
|
||||||
|
# Create the models that will be used for the tests
|
||||||
b = Book.objects.create(title="Pro Django",
|
b = Book.objects.create(title="Pro Django",
|
||||||
published=datetime.date(2008, 12, 16))
|
published=datetime.date(2008, 12, 16))
|
||||||
|
|
||||||
p = Person.objects.create(name="Marty Alchin")
|
p = Person.objects.create(name="Marty Alchin")
|
||||||
|
|
||||||
|
# Create a copy of the models on the 'other' database to prevent
|
||||||
|
# integrity errors on backends that don't defer constraints checks
|
||||||
|
Book.objects.using('other').create(pk=b.pk, title=b.title,
|
||||||
|
published=b.published)
|
||||||
|
Person.objects.using('other').create(pk=p.pk, name=p.name)
|
||||||
|
|
||||||
# Test addition
|
# Test addition
|
||||||
b.authors.add(p)
|
b.authors.add(p)
|
||||||
self.assertEqual(receiver._database, DEFAULT_DB_ALIAS)
|
self.assertEqual(receiver._database, DEFAULT_DB_ALIAS)
|
||||||
|
|
Loading…
Reference in New Issue