Fixed #32446 -- Deprecated SERIALIZE test database setting.
Whether or not the state of a test database should be serialized can be inferred from the set of databases allowed to be access from discovered TestCase/TransactionTestCase enabling the serialized_rollback feature which makes this setting unnecessary. This should make a significant test suite bootstraping time difference on large projects that didn't explicitly disable test database serialization.
This commit is contained in:
parent
af685b5f00
commit
3089018e95
|
@ -682,14 +682,18 @@ class DiscoverRunner:
|
||||||
return len(result.failures) + len(result.errors)
|
return len(result.failures) + len(result.errors)
|
||||||
|
|
||||||
def _get_databases(self, suite):
|
def _get_databases(self, suite):
|
||||||
databases = set()
|
databases = {}
|
||||||
for test in suite:
|
for test in suite:
|
||||||
if isinstance(test, unittest.TestCase):
|
if isinstance(test, unittest.TestCase):
|
||||||
test_databases = getattr(test, 'databases', None)
|
test_databases = getattr(test, 'databases', None)
|
||||||
if test_databases == '__all__':
|
if test_databases == '__all__':
|
||||||
return set(connections)
|
test_databases = connections
|
||||||
if test_databases:
|
if test_databases:
|
||||||
databases.update(test_databases)
|
serialized_rollback = getattr(test, 'serialized_rollback', False)
|
||||||
|
databases.update(
|
||||||
|
(alias, serialized_rollback or databases.get(alias, False))
|
||||||
|
for alias in test_databases
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
databases.update(self._get_databases(test))
|
databases.update(self._get_databases(test))
|
||||||
return databases
|
return databases
|
||||||
|
@ -717,8 +721,15 @@ class DiscoverRunner:
|
||||||
self.setup_test_environment()
|
self.setup_test_environment()
|
||||||
suite = self.build_suite(test_labels, extra_tests)
|
suite = self.build_suite(test_labels, extra_tests)
|
||||||
databases = self.get_databases(suite)
|
databases = self.get_databases(suite)
|
||||||
|
serialized_aliases = set(
|
||||||
|
alias
|
||||||
|
for alias, serialize in databases.items() if serialize
|
||||||
|
)
|
||||||
with self.time_keeper.timed('Total database setup'):
|
with self.time_keeper.timed('Total database setup'):
|
||||||
old_config = self.setup_databases(aliases=databases)
|
old_config = self.setup_databases(
|
||||||
|
aliases=databases,
|
||||||
|
serialized_aliases=serialized_aliases,
|
||||||
|
)
|
||||||
run_failed = False
|
run_failed = False
|
||||||
try:
|
try:
|
||||||
self.run_checks(databases)
|
self.run_checks(databases)
|
||||||
|
|
|
@ -25,6 +25,7 @@ from django.db.models.options import Options
|
||||||
from django.template import Template
|
from django.template import Template
|
||||||
from django.test.signals import setting_changed, template_rendered
|
from django.test.signals import setting_changed, template_rendered
|
||||||
from django.urls import get_script_prefix, set_script_prefix
|
from django.urls import get_script_prefix, set_script_prefix
|
||||||
|
from django.utils.deprecation import RemovedInDjango50Warning
|
||||||
from django.utils.translation import deactivate
|
from django.utils.translation import deactivate
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -156,8 +157,18 @@ def teardown_test_environment():
|
||||||
del mail.outbox
|
del mail.outbox
|
||||||
|
|
||||||
|
|
||||||
def setup_databases(verbosity, interactive, *, time_keeper=None, keepdb=False, debug_sql=False, parallel=0,
|
def setup_databases(
|
||||||
aliases=None, **kwargs):
|
verbosity,
|
||||||
|
interactive,
|
||||||
|
*,
|
||||||
|
time_keeper=None,
|
||||||
|
keepdb=False,
|
||||||
|
debug_sql=False,
|
||||||
|
parallel=0,
|
||||||
|
aliases=None,
|
||||||
|
serialized_aliases=None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
"""Create the test databases."""
|
"""Create the test databases."""
|
||||||
if time_keeper is None:
|
if time_keeper is None:
|
||||||
time_keeper = NullTimeKeeper()
|
time_keeper = NullTimeKeeper()
|
||||||
|
@ -176,11 +187,29 @@ def setup_databases(verbosity, interactive, *, time_keeper=None, keepdb=False, d
|
||||||
if first_alias is None:
|
if first_alias is None:
|
||||||
first_alias = alias
|
first_alias = alias
|
||||||
with time_keeper.timed(" Creating '%s'" % alias):
|
with time_keeper.timed(" Creating '%s'" % alias):
|
||||||
|
# RemovedInDjango50Warning: when the deprecation ends,
|
||||||
|
# replace with:
|
||||||
|
# serialize_alias = serialized_aliases is None or alias in serialized_aliases
|
||||||
|
try:
|
||||||
|
serialize_alias = connection.settings_dict['TEST']['SERIALIZE']
|
||||||
|
except KeyError:
|
||||||
|
serialize_alias = (
|
||||||
|
serialized_aliases is None or
|
||||||
|
alias in serialized_aliases
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
warnings.warn(
|
||||||
|
'The SERIALIZE test database setting is '
|
||||||
|
'deprecated as it can be inferred from the '
|
||||||
|
'TestCase/TransactionTestCase.databases that '
|
||||||
|
'enable the serialized_rollback feature.',
|
||||||
|
category=RemovedInDjango50Warning,
|
||||||
|
)
|
||||||
connection.creation.create_test_db(
|
connection.creation.create_test_db(
|
||||||
verbosity=verbosity,
|
verbosity=verbosity,
|
||||||
autoclobber=not interactive,
|
autoclobber=not interactive,
|
||||||
keepdb=keepdb,
|
keepdb=keepdb,
|
||||||
serialize=connection.settings_dict['TEST'].get('SERIALIZE', True),
|
serialize=serialize_alias,
|
||||||
)
|
)
|
||||||
if parallel > 1:
|
if parallel > 1:
|
||||||
for index in range(parallel):
|
for index in range(parallel):
|
||||||
|
|
|
@ -15,6 +15,8 @@ about each item can often be found in the release notes of two versions prior.
|
||||||
See the :ref:`Django 4.0 release notes <deprecated-features-4.0>` for more
|
See the :ref:`Django 4.0 release notes <deprecated-features-4.0>` for more
|
||||||
details on these changes.
|
details on these changes.
|
||||||
|
|
||||||
|
* The ``SERIALIZE`` test setting will be removed.
|
||||||
|
|
||||||
.. _deprecation-removed-in-4.1:
|
.. _deprecation-removed-in-4.1:
|
||||||
|
|
||||||
4.1
|
4.1
|
||||||
|
|
|
@ -821,6 +821,12 @@ 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
|
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>`.
|
with :ref:`serialized_rollback=True <test-case-serialized-rollback>`.
|
||||||
|
|
||||||
|
.. deprecated:: 4.0
|
||||||
|
|
||||||
|
This setting is deprecated as it can be inferred from the
|
||||||
|
:attr:`~django.test.TestCase.databases` with the
|
||||||
|
:ref:`serialized_rollback <test-case-serialized-rollback>` option enabled.
|
||||||
|
|
||||||
.. setting:: TEST_TEMPLATE
|
.. setting:: TEST_TEMPLATE
|
||||||
|
|
||||||
``TEMPLATE``
|
``TEMPLATE``
|
||||||
|
|
|
@ -248,7 +248,11 @@ Templates
|
||||||
Tests
|
Tests
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
* ...
|
* The new ``serialized_aliases`` argument of
|
||||||
|
:func:`django.test.utils.setup_databases` determines which
|
||||||
|
:setting:`DATABASES` aliases test databases should have their state
|
||||||
|
serialized to allow usage of the
|
||||||
|
:ref:`serialized_rollback <test-case-serialized-rollback>` feature.
|
||||||
|
|
||||||
URLs
|
URLs
|
||||||
~~~~
|
~~~~
|
||||||
|
@ -313,7 +317,9 @@ Features deprecated in 4.0
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
* ...
|
* ``SERIALIZE`` test setting is deprecated as it can be inferred from the
|
||||||
|
:attr:`~django.test.TestCase.databases` with the
|
||||||
|
:ref:`serialized_rollback <test-case-serialized-rollback>` option enabled.
|
||||||
|
|
||||||
Features removed in 4.0
|
Features removed in 4.0
|
||||||
=======================
|
=======================
|
||||||
|
|
|
@ -718,7 +718,7 @@ utility methods in the ``django.test.utils`` module.
|
||||||
Performs global post-test teardown, such as removing instrumentation from
|
Performs global post-test teardown, such as removing instrumentation from
|
||||||
the template system and restoring normal email services.
|
the template system and restoring normal email services.
|
||||||
|
|
||||||
.. function:: setup_databases(verbosity, interactive, *, time_keeper=None, keepdb=False, debug_sql=False, parallel=0, aliases=None, **kwargs)
|
.. function:: setup_databases(verbosity, interactive, *, time_keeper=None, keepdb=False, debug_sql=False, parallel=0, aliases=None, serialized_aliases=None, **kwargs)
|
||||||
|
|
||||||
Creates the test databases.
|
Creates the test databases.
|
||||||
|
|
||||||
|
@ -730,11 +730,20 @@ utility methods in the ``django.test.utils`` module.
|
||||||
databases should be setup for. If it's not provided, it defaults to all of
|
databases should be setup for. If it's not provided, it defaults to all of
|
||||||
:setting:`DATABASES` aliases.
|
:setting:`DATABASES` aliases.
|
||||||
|
|
||||||
|
The ``serialized_aliases`` argument determines what subset of ``aliases``
|
||||||
|
test databases should have their state serialized to allow usage of the
|
||||||
|
:ref:`serialized_rollback <test-case-serialized-rollback>` feature. If
|
||||||
|
it's not provided, it defaults to ``aliases``.
|
||||||
|
|
||||||
.. versionchanged:: 3.2
|
.. versionchanged:: 3.2
|
||||||
|
|
||||||
The ``time_keeper`` kwarg was added, and all kwargs were made
|
The ``time_keeper`` kwarg was added, and all kwargs were made
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|
||||||
|
.. versionchanged:: 4.0
|
||||||
|
|
||||||
|
The ``serialized_aliases`` kwarg was added.
|
||||||
|
|
||||||
.. function:: teardown_databases(old_config, parallel=0, keepdb=False)
|
.. function:: teardown_databases(old_config, parallel=0, keepdb=False)
|
||||||
|
|
||||||
Destroys the test databases, restoring pre-test conditions.
|
Destroys the test databases, restoring pre-test conditions.
|
||||||
|
|
|
@ -354,7 +354,7 @@ class DiscoverRunnerGetDatabasesTests(SimpleTestCase):
|
||||||
def assertSkippedDatabases(self, test_labels, expected_databases):
|
def assertSkippedDatabases(self, test_labels, expected_databases):
|
||||||
databases, output = self.get_databases(test_labels)
|
databases, output = self.get_databases(test_labels)
|
||||||
self.assertEqual(databases, expected_databases)
|
self.assertEqual(databases, expected_databases)
|
||||||
skipped_databases = set(connections) - expected_databases
|
skipped_databases = set(connections) - set(expected_databases)
|
||||||
if skipped_databases:
|
if skipped_databases:
|
||||||
self.assertIn(self.skip_msg + ', '.join(sorted(skipped_databases)), output)
|
self.assertIn(self.skip_msg + ', '.join(sorted(skipped_databases)), output)
|
||||||
else:
|
else:
|
||||||
|
@ -362,31 +362,37 @@ class DiscoverRunnerGetDatabasesTests(SimpleTestCase):
|
||||||
|
|
||||||
def test_mixed(self):
|
def test_mixed(self):
|
||||||
databases, output = self.get_databases(['test_runner_apps.databases.tests'])
|
databases, output = self.get_databases(['test_runner_apps.databases.tests'])
|
||||||
self.assertEqual(databases, set(connections))
|
self.assertEqual(databases, {'default': True, 'other': False})
|
||||||
self.assertNotIn(self.skip_msg, output)
|
self.assertNotIn(self.skip_msg, output)
|
||||||
|
|
||||||
def test_all(self):
|
def test_all(self):
|
||||||
databases, output = self.get_databases(['test_runner_apps.databases.tests.AllDatabasesTests'])
|
databases, output = self.get_databases(['test_runner_apps.databases.tests.AllDatabasesTests'])
|
||||||
self.assertEqual(databases, set(connections))
|
self.assertEqual(databases, {alias: False for alias in connections})
|
||||||
self.assertNotIn(self.skip_msg, output)
|
self.assertNotIn(self.skip_msg, output)
|
||||||
|
|
||||||
def test_default_and_other(self):
|
def test_default_and_other(self):
|
||||||
self.assertSkippedDatabases([
|
self.assertSkippedDatabases([
|
||||||
'test_runner_apps.databases.tests.DefaultDatabaseTests',
|
'test_runner_apps.databases.tests.DefaultDatabaseTests',
|
||||||
'test_runner_apps.databases.tests.OtherDatabaseTests',
|
'test_runner_apps.databases.tests.OtherDatabaseTests',
|
||||||
], {'default', 'other'})
|
], {'default': False, 'other': False})
|
||||||
|
|
||||||
def test_default_only(self):
|
def test_default_only(self):
|
||||||
self.assertSkippedDatabases([
|
self.assertSkippedDatabases([
|
||||||
'test_runner_apps.databases.tests.DefaultDatabaseTests',
|
'test_runner_apps.databases.tests.DefaultDatabaseTests',
|
||||||
], {'default'})
|
], {'default': False})
|
||||||
|
|
||||||
def test_other_only(self):
|
def test_other_only(self):
|
||||||
self.assertSkippedDatabases([
|
self.assertSkippedDatabases([
|
||||||
'test_runner_apps.databases.tests.OtherDatabaseTests'
|
'test_runner_apps.databases.tests.OtherDatabaseTests'
|
||||||
], {'other'})
|
], {'other': False})
|
||||||
|
|
||||||
def test_no_databases_required(self):
|
def test_no_databases_required(self):
|
||||||
self.assertSkippedDatabases([
|
self.assertSkippedDatabases([
|
||||||
'test_runner_apps.databases.tests.NoDatabaseTests'
|
'test_runner_apps.databases.tests.NoDatabaseTests'
|
||||||
], set())
|
], {})
|
||||||
|
|
||||||
|
def test_serialize(self):
|
||||||
|
databases, _ = self.get_databases([
|
||||||
|
'test_runner_apps.databases.tests.DefaultDatabaseSerializedTests'
|
||||||
|
])
|
||||||
|
self.assertEqual(databases, {'default': True})
|
||||||
|
|
|
@ -11,12 +11,15 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.core.management.base import SystemCheckError
|
from django.core.management.base import SystemCheckError
|
||||||
from django.test import TransactionTestCase, skipUnlessDBFeature
|
from django.test import (
|
||||||
|
SimpleTestCase, TransactionTestCase, skipUnlessDBFeature,
|
||||||
|
)
|
||||||
from django.test.runner import DiscoverRunner
|
from django.test.runner import DiscoverRunner
|
||||||
from django.test.testcases import connections_support_transactions
|
from django.test.testcases import connections_support_transactions
|
||||||
from django.test.utils import (
|
from django.test.utils import (
|
||||||
captured_stderr, dependency_ordered, get_unique_databases_and_mirrors,
|
captured_stderr, dependency_ordered, get_unique_databases_and_mirrors,
|
||||||
)
|
)
|
||||||
|
from django.utils.deprecation import RemovedInDjango50Warning
|
||||||
|
|
||||||
from .models import B, Person, Through
|
from .models import B, Person, Through
|
||||||
|
|
||||||
|
@ -315,7 +318,7 @@ class AliasedDefaultTestSetupTest(unittest.TestCase):
|
||||||
runner_instance.teardown_databases(old_config)
|
runner_instance.teardown_databases(old_config)
|
||||||
|
|
||||||
|
|
||||||
class SetupDatabasesTests(unittest.TestCase):
|
class SetupDatabasesTests(SimpleTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.runner_instance = DiscoverRunner(verbosity=0)
|
self.runner_instance = DiscoverRunner(verbosity=0)
|
||||||
|
@ -398,8 +401,14 @@ class SetupDatabasesTests(unittest.TestCase):
|
||||||
'TEST': {'SERIALIZE': False},
|
'TEST': {'SERIALIZE': False},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
msg = (
|
||||||
|
'The SERIALIZE test database setting is deprecated as it can be '
|
||||||
|
'inferred from the TestCase/TransactionTestCase.databases that '
|
||||||
|
'enable the serialized_rollback feature.'
|
||||||
|
)
|
||||||
with mock.patch('django.db.backends.dummy.base.DatabaseWrapper.creation_class') as mocked_db_creation:
|
with mock.patch('django.db.backends.dummy.base.DatabaseWrapper.creation_class') as mocked_db_creation:
|
||||||
with mock.patch('django.test.utils.connections', new=tested_connections):
|
with mock.patch('django.test.utils.connections', new=tested_connections):
|
||||||
|
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||||
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, serialize=False, keepdb=False
|
||||||
|
|
|
@ -10,6 +10,11 @@ class DefaultDatabaseTests(NoDatabaseTests):
|
||||||
databases = {'default'}
|
databases = {'default'}
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultDatabaseSerializedTests(NoDatabaseTests):
|
||||||
|
databases = {'default'}
|
||||||
|
serialized_rollback = True
|
||||||
|
|
||||||
|
|
||||||
class OtherDatabaseTests(NoDatabaseTests):
|
class OtherDatabaseTests(NoDatabaseTests):
|
||||||
databases = {'other'}
|
databases = {'other'}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue