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:
Aymeric Augustin 2011-10-16 11:04:34 +00:00
parent 03316579f4
commit 8fb7a90026
1 changed files with 42 additions and 3 deletions

View File

@ -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)