mirror of https://github.com/django/django.git
[3.1.x] Fixed #32012 -- Made test database creation sync apps models when migrations are disabled.
Thanks Jaap Roes for the report.
Backport of 77caeaea88
from master
This commit is contained in:
parent
2c629b37d5
commit
fbb7881956
|
@ -58,7 +58,14 @@ class BaseDatabaseCreation:
|
||||||
settings.DATABASES[self.connection.alias]["NAME"] = test_database_name
|
settings.DATABASES[self.connection.alias]["NAME"] = test_database_name
|
||||||
self.connection.settings_dict["NAME"] = test_database_name
|
self.connection.settings_dict["NAME"] = test_database_name
|
||||||
|
|
||||||
if self.connection.settings_dict['TEST']['MIGRATE']:
|
try:
|
||||||
|
if self.connection.settings_dict['TEST']['MIGRATE'] is False:
|
||||||
|
# Disable migrations for all apps.
|
||||||
|
old_migration_modules = settings.MIGRATION_MODULES
|
||||||
|
settings.MIGRATION_MODULES = {
|
||||||
|
app.label: None
|
||||||
|
for app in apps.get_app_configs()
|
||||||
|
}
|
||||||
# We report migrate messages at one level lower than that
|
# We report migrate messages at one level lower than that
|
||||||
# requested. This ensures we don't get flooded with messages during
|
# requested. This ensures we don't get flooded with messages during
|
||||||
# testing (unless you really ask to be flooded).
|
# testing (unless you really ask to be flooded).
|
||||||
|
@ -69,6 +76,9 @@ class BaseDatabaseCreation:
|
||||||
database=self.connection.alias,
|
database=self.connection.alias,
|
||||||
run_syncdb=True,
|
run_syncdb=True,
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
if self.connection.settings_dict['TEST']['MIGRATE'] is False:
|
||||||
|
settings.MIGRATION_MODULES = old_migration_modules
|
||||||
|
|
||||||
# We then serialize the current state of the database into a string
|
# We then serialize the current state of the database into a string
|
||||||
# and store it on the connection. This slightly horrific process is so people
|
# and store it on the connection. This slightly horrific process is so people
|
||||||
|
|
|
@ -787,6 +787,8 @@ on :ref:`controlling the creation order of test databases
|
||||||
Default: ``True``
|
Default: ``True``
|
||||||
|
|
||||||
When set to ``False``, migrations won't run when creating the test database.
|
When set to ``False``, migrations won't run when creating the test database.
|
||||||
|
This is similar to setting ``None`` as a value in :setting:`MIGRATION_MODULES`,
|
||||||
|
but for all apps.
|
||||||
|
|
||||||
.. setting:: TEST_MIRROR
|
.. setting:: TEST_MIRROR
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a regression in Django 3.1 where a queryset would crash if it contained
|
* Fixed a regression in Django 3.1 where a queryset would crash if it contained
|
||||||
an aggregation and a ``Q`` object annotation (:ticket:`32007`).
|
an aggregation and a ``Q`` object annotation (:ticket:`32007`).
|
||||||
|
|
||||||
|
* Fixed a bug in Django 3.1 where a test database was not synced during
|
||||||
|
creation when using the :setting:`MIGRATE <TEST_MIGRATE>` test database
|
||||||
|
setting (:ticket:`32012`).
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Foo',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Foo(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'app_unmigrated'
|
|
@ -6,6 +6,7 @@ from django.db.backends.base.creation import (
|
||||||
TEST_DATABASE_PREFIX, BaseDatabaseCreation,
|
TEST_DATABASE_PREFIX, BaseDatabaseCreation,
|
||||||
)
|
)
|
||||||
from django.test import SimpleTestCase, TransactionTestCase
|
from django.test import SimpleTestCase, TransactionTestCase
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from ..models import (
|
from ..models import (
|
||||||
CircularA, CircularB, Object, ObjectReference, ObjectSelfReference,
|
CircularA, CircularB, Object, ObjectReference, ObjectSelfReference,
|
||||||
|
@ -49,31 +50,57 @@ class TestDbSignatureTests(SimpleTestCase):
|
||||||
self.assertEqual(signature[3], test_name)
|
self.assertEqual(signature[3], test_name)
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(INSTALLED_APPS=['backends.base.app_unmigrated'])
|
||||||
@mock.patch.object(connection, 'ensure_connection')
|
@mock.patch.object(connection, 'ensure_connection')
|
||||||
@mock.patch('django.core.management.commands.migrate.Command.handle', return_value=None)
|
@mock.patch.object(connection, 'prepare_database')
|
||||||
|
@mock.patch('django.db.migrations.recorder.MigrationRecorder.has_table', return_value=False)
|
||||||
|
@mock.patch('django.db.migrations.executor.MigrationExecutor.migrate')
|
||||||
|
@mock.patch('django.core.management.commands.migrate.Command.sync_apps')
|
||||||
class TestDbCreationTests(SimpleTestCase):
|
class TestDbCreationTests(SimpleTestCase):
|
||||||
def test_migrate_test_setting_false(self, mocked_migrate, mocked_ensure_connection):
|
available_apps = ['backends.base.app_unmigrated']
|
||||||
|
|
||||||
|
def test_migrate_test_setting_false(self, mocked_sync_apps, mocked_migrate, *mocked_objects):
|
||||||
test_connection = get_connection_copy()
|
test_connection = get_connection_copy()
|
||||||
test_connection.settings_dict['TEST']['MIGRATE'] = False
|
test_connection.settings_dict['TEST']['MIGRATE'] = False
|
||||||
creation = test_connection.creation_class(test_connection)
|
creation = test_connection.creation_class(test_connection)
|
||||||
|
if connection.vendor == 'oracle':
|
||||||
|
# Don't close connection on Oracle.
|
||||||
|
creation.connection.close = mock.Mock()
|
||||||
old_database_name = test_connection.settings_dict['NAME']
|
old_database_name = test_connection.settings_dict['NAME']
|
||||||
try:
|
try:
|
||||||
with mock.patch.object(creation, '_create_test_db'):
|
with mock.patch.object(creation, '_create_test_db'):
|
||||||
creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
|
creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
|
||||||
mocked_migrate.assert_not_called()
|
# Migrations don't run.
|
||||||
|
mocked_migrate.assert_called()
|
||||||
|
args, kwargs = mocked_migrate.call_args
|
||||||
|
self.assertEqual(args, ([],))
|
||||||
|
self.assertEqual(kwargs['plan'], [])
|
||||||
|
# App is synced.
|
||||||
|
mocked_sync_apps.assert_called()
|
||||||
|
mocked_args, _ = mocked_sync_apps.call_args
|
||||||
|
self.assertEqual(mocked_args[1], {'app_unmigrated'})
|
||||||
finally:
|
finally:
|
||||||
with mock.patch.object(creation, '_destroy_test_db'):
|
with mock.patch.object(creation, '_destroy_test_db'):
|
||||||
creation.destroy_test_db(old_database_name, verbosity=0)
|
creation.destroy_test_db(old_database_name, verbosity=0)
|
||||||
|
|
||||||
def test_migrate_test_setting_true(self, mocked_migrate, mocked_ensure_connection):
|
def test_migrate_test_setting_true(self, mocked_sync_apps, mocked_migrate, *mocked_objects):
|
||||||
test_connection = get_connection_copy()
|
test_connection = get_connection_copy()
|
||||||
test_connection.settings_dict['TEST']['MIGRATE'] = True
|
test_connection.settings_dict['TEST']['MIGRATE'] = True
|
||||||
creation = test_connection.creation_class(test_connection)
|
creation = test_connection.creation_class(test_connection)
|
||||||
|
if connection.vendor == 'oracle':
|
||||||
|
# Don't close connection on Oracle.
|
||||||
|
creation.connection.close = mock.Mock()
|
||||||
old_database_name = test_connection.settings_dict['NAME']
|
old_database_name = test_connection.settings_dict['NAME']
|
||||||
try:
|
try:
|
||||||
with mock.patch.object(creation, '_create_test_db'):
|
with mock.patch.object(creation, '_create_test_db'):
|
||||||
creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
|
creation.create_test_db(verbosity=0, autoclobber=True, serialize=False)
|
||||||
mocked_migrate.assert_called_once()
|
# Migrations run.
|
||||||
|
mocked_migrate.assert_called()
|
||||||
|
args, kwargs = mocked_migrate.call_args
|
||||||
|
self.assertEqual(args, ([('app_unmigrated', '0001_initial')],))
|
||||||
|
self.assertEqual(len(kwargs['plan']), 1)
|
||||||
|
# App is not synced.
|
||||||
|
mocked_sync_apps.assert_not_called()
|
||||||
finally:
|
finally:
|
||||||
with mock.patch.object(creation, '_destroy_test_db'):
|
with mock.patch.object(creation, '_destroy_test_db'):
|
||||||
creation.destroy_test_db(old_database_name, verbosity=0)
|
creation.destroy_test_db(old_database_name, verbosity=0)
|
||||||
|
|
Loading…
Reference in New Issue