1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +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
parent e9becbe303
commit 825aea26b2
No known key found for this signature in database
8 changed files with 89 additions and 17 deletions

View File

@ -41,7 +41,8 @@ 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 RemovedInDjango61Warning
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
@ -30,7 +32,7 @@ class BaseDatabaseCreation:
sys.stderr.write(msg + os.linesep) sys.stderr.write(msg + os.linesep)
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 +92,19 @@ 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 setup instead if you need fixtures persistence "
"between tests.",
stacklevel=2,
category=RemovedInDjango61Warning,
)
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

@ -22,6 +22,9 @@ details on these changes.
``django.contrib.auth.login()`` and ``django.contrib.auth.alogin()`` will be ``django.contrib.auth.login()`` and ``django.contrib.auth.alogin()`` will be
removed. removed.
* The ``serialize`` keyword argument of ``BaseDatabaseCreation.create_test_db``
will be removed.
.. _deprecation-removed-in-6.0: .. _deprecation-removed-in-6.0:
6.0 6.0

View File

@ -414,6 +414,9 @@ backends.
* ``BaseDatabaseOperations.adapt_decimalfield_value()`` is now a no-op, simply * ``BaseDatabaseOperations.adapt_decimalfield_value()`` is now a no-op, simply
returning the given value. returning the given value.
* ``BaseDatabaseCreation.create_test_db(serialize)`` is deprecated. Use
``serialize_db_to_string`` instead.
:mod:`django.contrib.gis` :mod:`django.contrib.gis`
------------------------- -------------------------

View File

@ -805,7 +805,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.
@ -821,12 +821,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``,
@ -851,6 +845,25 @@ can be useful during testing.
If the ``keepdb`` argument is ``True``, then the connection to the If the ``keepdb`` argument is ``True``, then the connection to the
database will be closed, but the database will not be destroyed. database will be closed, but the database will not be destroyed.
.. function: serialize_db_to_string()
Serializes the database into an in-memory JSON string that can be used to
restore the database state between tests if the backend doesn't support
transactions or if your suite contains test classes with
:ref:`serialized_rollback=True <test-case-serialized-rollback>` enabled.
This function should only be called once all test databases have been
created as the serialization process could result in queries against
non-test databases depending on your
:ref:`routing configuration <topics-db-multi-db-routing>`.
.. versionchanged:: 5.2
The ``create_test_db`` function use to accept a ``serialize``
parameter that would automatically call ``serialize_db_to_string`` but
it was deprecated as it could result in queries against non-test databases
during serialization.
.. _topics-testing-code-coverage: .. _topics-testing-code-coverage:
Integration with ``coverage.py`` Integration with ``coverage.py``

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 RemovedInDjango61Warning
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 setup instead if you need fixtures persistence between tests."
)
try:
with (
self.assertWarnsMessage(RemovedInDjango61Warning, 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(RemovedInDjango61Warning, 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

@ -946,7 +946,7 @@ class SetupDatabasesTests(unittest.TestCase):
): ):
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()