Reorganized the database test settings

Change database test settings from "TEST_"-prefixed entries in the
database settings dictionary to setting in a dictionary that is itself
an entry "TEST" in the database settings.

Refs #21775

Thanks Josh Smeaton for review.
This commit is contained in:
Shai Berger 2014-01-20 02:45:29 +02:00
parent add1584bfa
commit 41afae4ce9
11 changed files with 256 additions and 108 deletions

View File

@ -391,8 +391,8 @@ class BaseDatabaseCreation(object):
_create_test_db() and when no external munging is done with the 'NAME' _create_test_db() and when no external munging is done with the 'NAME'
or 'TEST_NAME' settings. or 'TEST_NAME' settings.
""" """
if self.connection.settings_dict['TEST_NAME']: if self.connection.settings_dict['TEST']['NAME']:
return self.connection.settings_dict['TEST_NAME'] return self.connection.settings_dict['TEST']['NAME']
return TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] return TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME']
def _create_test_db(self, verbosity, autoclobber): def _create_test_db(self, verbosity, autoclobber):

View File

@ -34,10 +34,11 @@ class DatabaseCreation(BaseDatabaseCreation):
def sql_table_creation_suffix(self): def sql_table_creation_suffix(self):
suffix = [] suffix = []
if self.connection.settings_dict['TEST_CHARSET']: test_settings = self.connection.settings_dict['TEST']
suffix.append('CHARACTER SET %s' % self.connection.settings_dict['TEST_CHARSET']) if test_settings['CHARSET']:
if self.connection.settings_dict['TEST_COLLATION']: suffix.append('CHARACTER SET %s' % test_settings['CHARSET'])
suffix.append('COLLATE %s' % self.connection.settings_dict['TEST_COLLATION']) if test_settings['COLLATION']:
suffix.append('COLLATE %s' % test_settings['COLLATION'])
return ' '.join(suffix) return ' '.join(suffix)
def sql_for_inline_foreign_key_references(self, model, field, known_models, style): def sql_for_inline_foreign_key_references(self, model, field, known_models, style):

View File

@ -119,7 +119,9 @@ class DatabaseCreation(BaseDatabaseCreation):
real_settings = settings.DATABASES[self.connection.alias] real_settings = settings.DATABASES[self.connection.alias]
real_settings['SAVED_USER'] = self.connection.settings_dict['SAVED_USER'] = self.connection.settings_dict['USER'] real_settings['SAVED_USER'] = self.connection.settings_dict['SAVED_USER'] = self.connection.settings_dict['USER']
real_settings['SAVED_PASSWORD'] = self.connection.settings_dict['SAVED_PASSWORD'] = self.connection.settings_dict['PASSWORD'] real_settings['SAVED_PASSWORD'] = self.connection.settings_dict['SAVED_PASSWORD'] = self.connection.settings_dict['PASSWORD']
real_settings['TEST_USER'] = real_settings['USER'] = self.connection.settings_dict['TEST_USER'] = self.connection.settings_dict['USER'] = TEST_USER real_test_settings = real_settings['TEST']
test_settings = self.connection.settings_dict['TEST']
real_test_settings['USER'] = real_settings['USER'] = test_settings['USER'] = self.connection.settings_dict['USER'] = TEST_USER
real_settings['PASSWORD'] = self.connection.settings_dict['PASSWORD'] = TEST_PASSWD real_settings['PASSWORD'] = self.connection.settings_dict['PASSWORD'] = TEST_PASSWD
return self.connection.settings_dict['NAME'] return self.connection.settings_dict['NAME']
@ -216,56 +218,40 @@ class DatabaseCreation(BaseDatabaseCreation):
sys.stderr.write("Failed (%s)\n" % (err)) sys.stderr.write("Failed (%s)\n" % (err))
raise raise
def _test_settings_get(self, key, default=None, prefixed=None):
"""
Return a value from the test settings dict,
or a given default,
or a prefixed entry from the main settings dict
"""
settings_dict = self.connection.settings_dict
val = settings_dict['TEST'].get(key, default)
if val is None:
val = TEST_DATABASE_PREFIX + settings_dict[prefixed]
return val
def _test_database_name(self): def _test_database_name(self):
name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] return self._test_settings_get('NAME', prefixed='NAME')
try:
if self.connection.settings_dict['TEST_NAME']:
name = self.connection.settings_dict['TEST_NAME']
except AttributeError:
pass
return name
def _test_database_create(self): def _test_database_create(self):
return self.connection.settings_dict.get('TEST_CREATE', True) return self._test_settings_get('CREATE_DB', default=True)
def _test_user_create(self): def _test_user_create(self):
return self.connection.settings_dict.get('TEST_USER_CREATE', True) return self._test_settings_get('CREATE_USER', default=True)
def _test_database_user(self): def _test_database_user(self):
name = TEST_DATABASE_PREFIX + self.connection.settings_dict['USER'] return self._test_settings_get('USER', prefixed='USER')
try:
if self.connection.settings_dict['TEST_USER']:
name = self.connection.settings_dict['TEST_USER']
except KeyError:
pass
return name
def _test_database_passwd(self): def _test_database_passwd(self):
name = PASSWORD return self._test_settings_get('PASSWORD', default=PASSWORD)
try:
if self.connection.settings_dict['TEST_PASSWD']:
name = self.connection.settings_dict['TEST_PASSWD']
except KeyError:
pass
return name
def _test_database_tblspace(self): def _test_database_tblspace(self):
name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] return self._test_settings_get('TBLSPACE', prefixed='NAME')
try:
if self.connection.settings_dict['TEST_TBLSPACE']:
name = self.connection.settings_dict['TEST_TBLSPACE']
except KeyError:
pass
return name
def _test_database_tblspace_tmp(self): def _test_database_tblspace_tmp(self):
name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] + '_temp' settings_dict = self.connection.settings_dict
try: return settings_dict['TEST'].get('TBLSPACE_TMP',
if self.connection.settings_dict['TEST_TBLSPACE_TMP']: TEST_DATABASE_PREFIX + settings_dict['NAME'] + '_temp')
name = self.connection.settings_dict['TEST_TBLSPACE_TMP']
except KeyError:
pass
return name
def _get_test_db_name(self): def _get_test_db_name(self):
""" """

View File

@ -39,9 +39,10 @@ class DatabaseCreation(BaseDatabaseCreation):
} }
def sql_table_creation_suffix(self): def sql_table_creation_suffix(self):
assert self.connection.settings_dict['TEST_COLLATION'] is None, "PostgreSQL does not support collation setting at database creation time." test_settings = self.connection.settings_dict['TEST']
if self.connection.settings_dict['TEST_CHARSET']: assert test_settings['COLLATION'] is None, "PostgreSQL does not support collation setting at database creation time."
return "WITH ENCODING '%s'" % self.connection.settings_dict['TEST_CHARSET'] if test_settings['CHARSET']:
return "WITH ENCODING '%s'" % test_settings['CHARSET']
return '' return ''
def sql_indexes_for_field(self, model, f, style): def sql_indexes_for_field(self, model, f, style):

View File

@ -47,7 +47,7 @@ class DatabaseCreation(BaseDatabaseCreation):
return [] return []
def _get_test_db_name(self): def _get_test_db_name(self):
test_database_name = self.connection.settings_dict['TEST_NAME'] test_database_name = self.connection.settings_dict['TEST']['NAME']
if test_database_name and test_database_name != ':memory:': if test_database_name and test_database_name != ':memory:':
return test_database_name return test_database_name
return ':memory:' return ':memory:'
@ -83,7 +83,7 @@ class DatabaseCreation(BaseDatabaseCreation):
This takes into account the special cases of ":memory:" and "" for This takes into account the special cases of ":memory:" and "" for
SQLite since the databases will be distinct despite having the same SQLite since the databases will be distinct despite having the same
TEST_NAME. See http://www.sqlite.org/inmemorydb.html TEST NAME. See http://www.sqlite.org/inmemorydb.html
""" """
test_dbname = self._get_test_db_name() test_dbname = self._get_test_db_name()
sig = [self.connection.settings_dict['NAME']] sig = [self.connection.settings_dict['NAME']]

View File

@ -181,14 +181,48 @@ class ConnectionHandler(object):
conn.setdefault('TIME_ZONE', 'UTC' if settings.USE_TZ else settings.TIME_ZONE) conn.setdefault('TIME_ZONE', 'UTC' if settings.USE_TZ else settings.TIME_ZONE)
for setting in ['NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']: for setting in ['NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']:
conn.setdefault(setting, '') conn.setdefault(setting, '')
for setting in ['TEST_CHARSET', 'TEST_COLLATION', 'TEST_NAME', 'TEST_MIRROR']:
conn.setdefault(setting, None) TEST_SETTING_RENAMES = {
'CREATE': 'CREATE_DB',
'USER_CREATE': 'CREATE_USER',
'PASSWD': 'PASSWORD',
}
def prepare_test_settings(self, alias):
"""
Makes sure the test settings are available in the 'TEST' sub-dictionary.
"""
try:
conn = self.databases[alias]
except KeyError:
raise ConnectionDoesNotExist("The connection %s doesn't exist" % alias)
test_settings = conn.setdefault('TEST', {})
for key, value in six.iteritems(conn):
if key.startswith('TEST_'):
new_key = key[5:]
new_key = self.TEST_SETTING_RENAMES.get(new_key, new_key)
if new_key in test_settings:
raise ImproperlyConfigured("Connection %s has both %s and TEST[%s] specified." %
(alias, key, new_key))
warnings.warn("In Django 1.9 the %s connection setting will be moved "
"to a %s entry in the TEST setting" % (key, new_key),
RemovedInDjango19Warning, stacklevel=2)
test_settings[new_key] = value
# Check that they didn't just use the old name with 'TEST_' removed
for key, new_key in six.iteritems(self.TEST_SETTING_RENAMES):
if key in test_settings:
warnings.warn("Test setting %s was renamed to %s; specified value (%s) ignored" %
(key, new_key, test_settings[key]), stacklevel=2)
for key in ['CHARSET', 'COLLATION', 'NAME', 'MIRROR']:
test_settings.setdefault(key, None)
def __getitem__(self, alias): def __getitem__(self, alias):
if hasattr(self._connections, alias): if hasattr(self._connections, alias):
return getattr(self._connections, alias) return getattr(self._connections, alias)
self.ensure_defaults(alias) self.ensure_defaults(alias)
self.prepare_test_settings(alias)
db = self.databases[alias] db = self.databases[alias]
backend = load_backend(db['ENGINE']) backend = load_backend(db['ENGINE'])
conn = backend.DatabaseWrapper(db, alias) conn = backend.DatabaseWrapper(db, alias)

View File

@ -170,7 +170,7 @@ def is_discoverable(label):
def dependency_ordered(test_databases, dependencies): def dependency_ordered(test_databases, dependencies):
""" """
Reorder test_databases into an order that honors the dependencies Reorder test_databases into an order that honors the dependencies
described in TEST_DEPENDENCIES. described in TEST[DEPENDENCIES].
""" """
ordered_test_databases = [] ordered_test_databases = []
resolved_databases = set() resolved_databases = set()
@ -204,7 +204,7 @@ def dependency_ordered(test_databases, dependencies):
if not changed: if not changed:
raise ImproperlyConfigured( raise ImproperlyConfigured(
"Circular dependency in TEST_DEPENDENCIES") "Circular dependency in TEST[DEPENDENCIES]")
test_databases = deferred test_databases = deferred
return ordered_test_databases return ordered_test_databases
@ -261,11 +261,11 @@ def setup_databases(verbosity, interactive, **kwargs):
default_sig = connections[DEFAULT_DB_ALIAS].creation.test_db_signature() default_sig = connections[DEFAULT_DB_ALIAS].creation.test_db_signature()
for alias in connections: for alias in connections:
connection = connections[alias] connection = connections[alias]
if connection.settings_dict['TEST_MIRROR']: test_settings = connection.settings_dict['TEST']
if test_settings['MIRROR']:
# If the database is marked as a test mirror, save # If the database is marked as a test mirror, save
# the alias. # the alias.
mirrored_aliases[alias] = ( mirrored_aliases[alias] = test_settings['MIRROR']
connection.settings_dict['TEST_MIRROR'])
else: else:
# Store a tuple with DB parameters that uniquely identify it. # Store a tuple with DB parameters that uniquely identify it.
# If we have two aliases with the same values for that tuple, # If we have two aliases with the same values for that tuple,
@ -276,13 +276,11 @@ def setup_databases(verbosity, interactive, **kwargs):
) )
item[1].add(alias) item[1].add(alias)
if 'TEST_DEPENDENCIES' in connection.settings_dict: if 'DEPENDENCIES' in test_settings:
dependencies[alias] = ( dependencies[alias] = test_settings['DEPENDENCIES']
connection.settings_dict['TEST_DEPENDENCIES'])
else: else:
if alias != DEFAULT_DB_ALIAS and connection.creation.test_db_signature() != default_sig: if alias != DEFAULT_DB_ALIAS and connection.creation.test_db_signature() != default_sig:
dependencies[alias] = connection.settings_dict.get( dependencies[alias] = test_settings.get('DEPENDENCIES', [DEFAULT_DB_ALIAS])
'TEST_DEPENDENCIES', [DEFAULT_DB_ALIAS])
# Second pass -- actually create the databases. # Second pass -- actually create the databases.
old_names = [] old_names = []

View File

@ -762,7 +762,7 @@ class TransactionTestCase(SimpleTestCase):
# including mirrors or not. Otherwise, just on the default DB. # including mirrors or not. Otherwise, just on the default DB.
if getattr(self, 'multi_db', False): if getattr(self, 'multi_db', False):
return [alias for alias in connections return [alias for alias in connections
if include_mirrors or not connections[alias].settings_dict['TEST_MIRROR']] if include_mirrors or not connections[alias].settings_dict['TEST']['MIRROR']]
else: else:
return [DEFAULT_DB_ALIAS] return [DEFAULT_DB_ALIAS]

View File

@ -121,6 +121,9 @@ details on these changes.
* ``django.utils.text.javascript_quote`` will be removed. * ``django.utils.text.javascript_quote`` will be removed.
* Database test settings as independent entries in the database settings,
prefixed by ``TEST_``, will no longer be supported.
.. _deprecation-removed-in-1.8: .. _deprecation-removed-in-1.8:
1.8 1.8

View File

@ -605,10 +605,29 @@ Default: ``''`` (Empty string)
The username to use when connecting to the database. Not used with SQLite. The username to use when connecting to the database. Not used with SQLite.
.. setting:: DATABASE-TEST
TEST
~~~~
.. versionchanged:: 1.7
All :setting:`TEST <DATABASE-TEST>` sub-entries used to be independent
entries in the database settings dictionary, with a ``TEST_`` prefix.
Further, ``TEST_CREATE``, ``TEST_USER_CREATE`` and ``TEST_PASSWD``
were changed to ``CREATE_DB``, ``CREATE_USER`` and ``PASSWORD``
respectively.
Default: ``{}``
A dictionary of settings for test databases; for more details about the
creation and use of test databases, see :ref:`the-test-database`. The
following entries are available:
.. setting:: TEST_CHARSET .. setting:: TEST_CHARSET
TEST_CHARSET CHARSET
~~~~~~~~~~~~ ^^^^^^^
Default: ``None`` Default: ``None``
@ -624,8 +643,8 @@ backends.
.. setting:: TEST_COLLATION .. setting:: TEST_COLLATION
TEST_COLLATION COLLATION
~~~~~~~~~~~~~~ ^^^^^^^^^
Default: ``None`` Default: ``None``
@ -638,8 +657,8 @@ Only supported for the ``mysql`` backend (see the `MySQL manual`_ for details).
.. setting:: TEST_DEPENDENCIES .. setting:: TEST_DEPENDENCIES
TEST_DEPENDENCIES DEPENDENCIES
~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^
Default: ``['default']``, for all databases other than ``default``, Default: ``['default']``, for all databases other than ``default``,
which has no dependencies. which has no dependencies.
@ -650,8 +669,8 @@ on :ref:`controlling the creation order of test databases
.. setting:: TEST_MIRROR .. setting:: TEST_MIRROR
TEST_MIRROR MIRROR
~~~~~~~~~~~ ^^^^^^
Default: ``None`` Default: ``None``
@ -665,8 +684,8 @@ configurations of multiple databases. See the documentation on
.. setting:: TEST_NAME .. setting:: TEST_NAME
TEST_NAME NAME
~~~~~~~~~ ^^^^
Default: ``None`` Default: ``None``
@ -680,8 +699,8 @@ See :ref:`the-test-database`.
.. setting:: TEST_CREATE .. setting:: TEST_CREATE
TEST_CREATE CREATE_DB
~~~~~~~~~~~ ^^^^^^^^^
Default: ``True`` Default: ``True``
@ -690,22 +709,10 @@ This is an Oracle-specific setting.
If it is set to ``False``, the test tablespaces won't be automatically created If it is set to ``False``, the test tablespaces won't be automatically created
at the beginning of the tests and dropped at the end. at the beginning of the tests and dropped at the end.
.. setting:: TEST_USER
TEST_USER
~~~~~~~~~
Default: ``None``
This is an Oracle-specific setting.
The username to use when connecting to the Oracle database that will be used
when running tests. If not provided, Django will use ``'test_' + USER``.
.. setting:: TEST_USER_CREATE .. setting:: TEST_USER_CREATE
TEST_USER_CREATE CREATE_USER
~~~~~~~~~~~~~~~~ ^^^^^^^^^^^
Default: ``True`` Default: ``True``
@ -714,10 +721,22 @@ This is an Oracle-specific setting.
If it is set to ``False``, the test user won't be automatically created at the If it is set to ``False``, the test user won't be automatically created at the
beginning of the tests and dropped at the end. beginning of the tests and dropped at the end.
.. setting:: TEST_USER
USER
^^^^
Default: ``None``
This is an Oracle-specific setting.
The username to use when connecting to the Oracle database that will be used
when running tests. If not provided, Django will use ``'test_' + USER``.
.. setting:: TEST_PASSWD .. setting:: TEST_PASSWD
TEST_PASSWD PASSWORD
~~~~~~~~~~~ ^^^^^^^^
Default: ``None`` Default: ``None``
@ -728,8 +747,8 @@ when running tests. If not provided, Django will use a hardcoded default value.
.. setting:: TEST_TBLSPACE .. setting:: TEST_TBLSPACE
TEST_TBLSPACE TBLSPACE
~~~~~~~~~~~~~ ^^^^^^^^
Default: ``None`` Default: ``None``
@ -740,8 +759,8 @@ provided, Django will use ``'test_' + NAME``.
.. setting:: TEST_TBLSPACE_TMP .. setting:: TEST_TBLSPACE_TMP
TEST_TBLSPACE_TMP TBLSPACE_TMP
~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^
Default: ``None`` Default: ``None``
@ -750,6 +769,116 @@ This is an Oracle-specific setting.
The name of the temporary tablespace that will be used when running tests. If The name of the temporary tablespace that will be used when running tests. If
not provided, Django will use ``'test_' + NAME + '_temp'``. not provided, Django will use ``'test_' + NAME + '_temp'``.
.. setting:: OLD_TEST_CHARSET
TEST_CHARSET
~~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`CHARSET <TEST_CHARSET>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_COLLATION
TEST_COLLATION
~~~~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`COLLATION <TEST_COLLATION>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_DEPENDENCIES
TEST_DEPENDENCIES
~~~~~~~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`DEPENDENCIES <TEST_DEPENDENCIES>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_MIRROR
TEST_MIRROR
~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`MIRROR <TEST_MIRROR>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_NAME
TEST_NAME
~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`NAME <TEST_NAME>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_CREATE
TEST_CREATE
~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`CREATE_DB <TEST_CREATE>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_USER
TEST_USER
~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`USER <TEST_USER>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_USER_CREATE
TEST_USER_CREATE
~~~~~~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`CREATE_USER <TEST_USER_CREATE>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_PASSWD
TEST_PASSWD
~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`PASSWORD <TEST_PASSWD>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_TBLSPACE
TEST_TBLSPACE
~~~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`TBLSPACE <TEST_TBLSPACE>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: OLD_TEST_TBLSPACE_TMP
TEST_TBLSPACE_TMP
~~~~~~~~~~~~~~~~~
.. deprecated:: 1.7
Use the :setting:`TBLSPACE_TMP <TEST_TBLSPACE_TMP>` entry in the
:setting:`TEST <DATABASE-TEST>` dictionary.
.. setting:: DATABASE_ROUTERS .. setting:: DATABASE_ROUTERS
DATABASE_ROUTERS DATABASE_ROUTERS
@ -2960,20 +3089,7 @@ Templates
Testing Testing
------- -------
* Database * Database: :setting:`TEST <DATABASE-TEST>`
* :setting:`TEST_CHARSET`
* :setting:`TEST_COLLATION`
* :setting:`TEST_DEPENDENCIES`
* :setting:`TEST_MIRROR`
* :setting:`TEST_NAME`
* :setting:`TEST_CREATE`
* :setting:`TEST_USER`
* :setting:`TEST_USER_CREATE`
* :setting:`TEST_PASSWD`
* :setting:`TEST_TBLSPACE`
* :setting:`TEST_TBLSPACE_TMP`
* :setting:`TEST_RUNNER` * :setting:`TEST_RUNNER`
URLs URLs

View File

@ -785,6 +785,9 @@ Tests
* The ``WSGIRequest`` instance generated by the test handler is now attached to * The ``WSGIRequest`` instance generated by the test handler is now attached to
the :attr:`django.test.Response.wsgi_request` attribute. the :attr:`django.test.Response.wsgi_request` attribute.
* The database settings for testing have been collected into a dictionary
named :setting:`TEST <DATABASE-TEST>`.
Validators Validators
^^^^^^^^^^ ^^^^^^^^^^
@ -1459,3 +1462,9 @@ a risk of introducing XSS vulnerabilities. Along with ``fix_ampersands``,
``fix_ampersands``. ``fix_ampersands``.
As this is an accelerated deprecation, ``fix_ampersands`` and ``clean_html`` As this is an accelerated deprecation, ``fix_ampersands`` and ``clean_html``
will be removed in Django 1.8. will be removed in Django 1.8.
Reorganization of database test settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All database settings with a `TEST_` prefix have been deprecated in favor of
entries in a :setting:`TEST <DATABASE-TEST>` dictionary in the database
settings. The old settings will be supported until Django 1.9.