1
0
mirror of https://github.com/django/django.git synced 2025-06-05 03:29:12 +00:00

Refs #35967 -- Deprecated BaseDatabaseCreation.create_test_db(serialize).

Given there are no longer any internal usages of serialize=True and it
poses a risk to non-test databases integrity it seems appropriate to
deprecate it.
This commit is contained in:
Simon Charette 2024-12-17 23:38:23 -05:00 committed by Mariusz Felisiak
parent 99ac8e2589
commit 2d34ebe49a
8 changed files with 78 additions and 19 deletions

View File

@ -41,7 +41,7 @@ class Command(BaseCommand):
# Create a test database. # Create a test database.
db_name = connection.creation.create_test_db( db_name = connection.creation.create_test_db(
verbosity=verbosity, autoclobber=not interactive, serialize=False verbosity=verbosity, autoclobber=not interactive
) )
# Import the fixture data into the test database. # Import the fixture data into the test database.

View File

@ -1,5 +1,6 @@
import os import os
import sys import sys
import warnings
from io import StringIO from io import StringIO
from django.apps import apps from django.apps import apps
@ -7,6 +8,7 @@ from django.conf import settings
from django.core import serializers from django.core import serializers
from django.db import router from django.db import router
from django.db.transaction import atomic from django.db.transaction import atomic
from django.utils.deprecation import RemovedInDjango70Warning
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
# The prefix to put on the default database name when creating # The prefix to put on the default database name when creating
@ -29,8 +31,10 @@ class BaseDatabaseCreation:
def log(self, msg): def log(self, msg):
sys.stderr.write(msg + os.linesep) sys.stderr.write(msg + os.linesep)
# RemovedInDjango70Warning: When the deprecation ends, replace with:
# def create_test_db(self, verbosity=1, autoclobber=False, keepdb=False):
def create_test_db( def create_test_db(
self, verbosity=1, autoclobber=False, serialize=True, keepdb=False self, verbosity=1, autoclobber=False, serialize=None, keepdb=False
): ):
""" """
Create a test database, prompting the user for confirmation if the Create a test database, prompting the user for confirmation if the
@ -90,8 +94,18 @@ class BaseDatabaseCreation:
# 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
# who are testing on databases without transactions or who are using # who are testing on databases without transactions or who are using
# a TransactionTestCase still get a clean database on every test run. # a TransactionTestCase still get a clean database on every test run.
if serialize: if serialize is not None:
self.connection._test_serialized_contents = self.serialize_db_to_string() warnings.warn(
"DatabaseCreation.create_test_db(serialize) is deprecated. Call "
"DatabaseCreation.serialize_test_db() once all test databases are set "
"up instead if you need fixtures persistence between tests.",
stacklevel=2,
category=RemovedInDjango70Warning,
)
if serialize:
self.connection._test_serialized_contents = (
self.serialize_db_to_string()
)
call_command("createcachetable", database=self.connection.alias) call_command("createcachetable", database=self.connection.alias)

View File

@ -205,7 +205,6 @@ def setup_databases(
verbosity=verbosity, verbosity=verbosity,
autoclobber=not interactive, autoclobber=not interactive,
keepdb=keepdb, keepdb=keepdb,
serialize=False,
) )
if serialized_aliases is None or alias in serialized_aliases: if serialized_aliases is None or alias in serialized_aliases:
serialize_connections.append(connection) serialize_connections.append(connection)

View File

@ -15,6 +15,9 @@ about each item can often be found in the release notes of two versions prior.
See the :ref:`Django 6.0 release notes <deprecated-features-6.0>` for more See the :ref:`Django 6.0 release notes <deprecated-features-6.0>` for more
details on these changes. details on these changes.
* The ``serialize`` keyword argument of
``BaseDatabaseCreation.create_test_db()`` will be removed.
.. _deprecation-removed-in-6.1: .. _deprecation-removed-in-6.1:
6.1 6.1

View File

@ -235,7 +235,8 @@ Database backend API
This section describes changes that may be needed in third-party database This section describes changes that may be needed in third-party database
backends. backends.
* ... * ``BaseDatabaseCreation.create_test_db(serialize)`` is deprecated. Use
``serialize_db_to_string()`` instead.
Dropped support for MariaDB 10.5 Dropped support for MariaDB 10.5
-------------------------------- --------------------------------
@ -278,7 +279,8 @@ Features deprecated in 6.0
Miscellaneous Miscellaneous
------------- -------------
* ... * ``BaseDatabaseCreation.create_test_db(serialize)`` is deprecated. Use
``serialize_db_to_string()`` instead.
Features removed in 6.0 Features removed in 6.0
======================= =======================

View File

@ -796,7 +796,7 @@ utility methods in the ``django.test.utils`` module.
The creation module of the database backend also provides some utilities that The creation module of the database backend also provides some utilities that
can be useful during testing. can be useful during testing.
.. function:: create_test_db(verbosity=1, autoclobber=False, serialize=True, keepdb=False) .. function:: create_test_db(verbosity=1, autoclobber=False, keepdb=False)
Creates a new test database and runs ``migrate`` against it. Creates a new test database and runs ``migrate`` against it.
@ -812,12 +812,6 @@ can be useful during testing.
* If ``autoclobber`` is ``True``, the database will be destroyed * If ``autoclobber`` is ``True``, the database will be destroyed
without consulting the user. without consulting the user.
``serialize`` determines if Django serializes the database into an
in-memory JSON string before running tests (used to restore the database
state between tests if you don't have transactions). You can set this to
``False`` to speed up creation time if you don't have any test classes
with :ref:`serialized_rollback=True <test-case-serialized-rollback>`.
``keepdb`` determines if the test run should use an existing ``keepdb`` determines if the test run should use an existing
database, or create a new one. If ``True``, the existing database, or create a new one. If ``True``, the existing
database will be used, or created if not present. If ``False``, database will be used, or created if not present. If ``False``,
@ -830,6 +824,13 @@ can be useful during testing.
:setting:`NAME` in :setting:`DATABASES` to match the name of the test :setting:`NAME` in :setting:`DATABASES` to match the name of the test
database. database.
.. deprecated:: 6.0
The ``serialize`` keyword argument is deprecated. Passing
``serialize=True`` would automatically call
:func:`serialize_db_to_string` but it was deprecated as it could result
in queries against non-test databases during serialization.
.. function:: destroy_test_db(old_database_name, verbosity=1, keepdb=False) .. function:: destroy_test_db(old_database_name, verbosity=1, keepdb=False)
Destroys the database whose name is the value of :setting:`NAME` in Destroys the database whose name is the value of :setting:`NAME` in

View File

@ -7,6 +7,7 @@ from django.db import DEFAULT_DB_ALIAS, connection, connections
from django.db.backends.base.creation import TEST_DATABASE_PREFIX, BaseDatabaseCreation from django.db.backends.base.creation import TEST_DATABASE_PREFIX, BaseDatabaseCreation
from django.test import SimpleTestCase, TransactionTestCase from django.test import SimpleTestCase, TransactionTestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils.deprecation import RemovedInDjango70Warning
from ..models import ( from ..models import (
CircularA, CircularA,
@ -79,7 +80,7 @@ class TestDbCreationTests(SimpleTestCase):
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)
# Migrations don't run. # Migrations don't run.
mocked_migrate.assert_called() mocked_migrate.assert_called()
args, kwargs = mocked_migrate.call_args args, kwargs = mocked_migrate.call_args
@ -109,7 +110,7 @@ class TestDbCreationTests(SimpleTestCase):
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)
# The django_migrations table is not created. # The django_migrations table is not created.
mocked_ensure_schema.assert_not_called() mocked_ensure_schema.assert_not_called()
# App is synced. # App is synced.
@ -133,7 +134,7 @@ class TestDbCreationTests(SimpleTestCase):
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)
# Migrations run. # Migrations run.
mocked_migrate.assert_called() mocked_migrate.assert_called()
args, kwargs = mocked_migrate.call_args args, kwargs = mocked_migrate.call_args
@ -163,12 +164,51 @@ class TestDbCreationTests(SimpleTestCase):
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)
self.assertIs(mark_expected_failures_and_skips.called, False) self.assertIs(mark_expected_failures_and_skips.called, False)
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)
@mock.patch("django.db.migrations.executor.MigrationExecutor.migrate")
@mock.patch.object(BaseDatabaseCreation, "serialize_db_to_string")
def test_serialize_deprecation(self, serialize_db_to_string, *mocked_objects):
test_connection = get_connection_copy()
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"]
msg = (
"DatabaseCreation.create_test_db(serialize) is deprecated. Call "
"DatabaseCreation.serialize_test_db() once all test databases are set up "
"instead if you need fixtures persistence between tests."
)
try:
with (
self.assertWarnsMessage(RemovedInDjango70Warning, msg) as ctx,
mock.patch.object(creation, "_create_test_db"),
):
creation.create_test_db(verbosity=0, serialize=True)
self.assertEqual(ctx.filename, __file__)
serialize_db_to_string.assert_called_once_with()
finally:
with mock.patch.object(creation, "_destroy_test_db"):
creation.destroy_test_db(old_database_name, verbosity=0)
# Now with `serialize` False.
serialize_db_to_string.reset_mock()
try:
with (
self.assertWarnsMessage(RemovedInDjango70Warning, msg) as ctx,
mock.patch.object(creation, "_create_test_db"),
):
creation.create_test_db(verbosity=0, serialize=False)
self.assertEqual(ctx.filename, __file__)
serialize_db_to_string.assert_not_called()
finally:
with mock.patch.object(creation, "_destroy_test_db"):
creation.destroy_test_db(old_database_name, verbosity=0)
class TestDeserializeDbFromString(TransactionTestCase): class TestDeserializeDbFromString(TransactionTestCase):
available_apps = ["backends"] available_apps = ["backends"]

View File

@ -931,7 +931,7 @@ class SetupDatabasesTests(unittest.TestCase):
with mock.patch("django.test.utils.connections", new=tested_connections): with mock.patch("django.test.utils.connections", new=tested_connections):
self.runner_instance.setup_databases() self.runner_instance.setup_databases()
mocked_db_creation.return_value.create_test_db.assert_called_once_with( mocked_db_creation.return_value.create_test_db.assert_called_once_with(
verbosity=0, autoclobber=False, serialize=False, keepdb=False verbosity=0, autoclobber=False, keepdb=False
) )
mocked_db_creation.return_value.serialize_db_to_string.assert_called_once_with() mocked_db_creation.return_value.serialize_db_to_string.assert_called_once_with()