From 41afae4ce906838fc87d63962104cfb47991f68b Mon Sep 17 00:00:00 2001 From: Shai Berger Date: Mon, 20 Jan 2014 02:45:29 +0200 Subject: [PATCH] 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. --- django/db/backends/creation.py | 4 +- django/db/backends/mysql/creation.py | 9 +- django/db/backends/oracle/creation.py | 62 ++---- .../backends/postgresql_psycopg2/creation.py | 7 +- django/db/backends/sqlite3/creation.py | 4 +- django/db/utils.py | 38 +++- django/test/runner.py | 18 +- django/test/testcases.py | 2 +- docs/internals/deprecation.txt | 3 + docs/ref/settings.txt | 208 ++++++++++++++---- docs/releases/1.7.txt | 9 + 11 files changed, 256 insertions(+), 108 deletions(-) diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py index a549c34f17..a2a288a9da 100644 --- a/django/db/backends/creation.py +++ b/django/db/backends/creation.py @@ -391,8 +391,8 @@ class BaseDatabaseCreation(object): _create_test_db() and when no external munging is done with the 'NAME' or 'TEST_NAME' settings. """ - if self.connection.settings_dict['TEST_NAME']: - return self.connection.settings_dict['TEST_NAME'] + if self.connection.settings_dict['TEST']['NAME']: + return self.connection.settings_dict['TEST']['NAME'] return TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] def _create_test_db(self, verbosity, autoclobber): diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index b15c3371fb..565b1fd9a1 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -34,10 +34,11 @@ class DatabaseCreation(BaseDatabaseCreation): def sql_table_creation_suffix(self): suffix = [] - if self.connection.settings_dict['TEST_CHARSET']: - suffix.append('CHARACTER SET %s' % self.connection.settings_dict['TEST_CHARSET']) - if self.connection.settings_dict['TEST_COLLATION']: - suffix.append('COLLATE %s' % self.connection.settings_dict['TEST_COLLATION']) + test_settings = self.connection.settings_dict['TEST'] + if test_settings['CHARSET']: + suffix.append('CHARACTER SET %s' % test_settings['CHARSET']) + if test_settings['COLLATION']: + suffix.append('COLLATE %s' % test_settings['COLLATION']) return ' '.join(suffix) def sql_for_inline_foreign_key_references(self, model, field, known_models, style): diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index 6cb2f1467e..90cc83fd58 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -119,7 +119,9 @@ class DatabaseCreation(BaseDatabaseCreation): 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_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 return self.connection.settings_dict['NAME'] @@ -216,56 +218,40 @@ class DatabaseCreation(BaseDatabaseCreation): sys.stderr.write("Failed (%s)\n" % (err)) 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): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] - try: - if self.connection.settings_dict['TEST_NAME']: - name = self.connection.settings_dict['TEST_NAME'] - except AttributeError: - pass - return name + return self._test_settings_get('NAME', prefixed='NAME') 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): - return self.connection.settings_dict.get('TEST_USER_CREATE', True) + return self._test_settings_get('CREATE_USER', default=True) def _test_database_user(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['USER'] - try: - if self.connection.settings_dict['TEST_USER']: - name = self.connection.settings_dict['TEST_USER'] - except KeyError: - pass - return name + return self._test_settings_get('USER', prefixed='USER') def _test_database_passwd(self): - name = PASSWORD - try: - if self.connection.settings_dict['TEST_PASSWD']: - name = self.connection.settings_dict['TEST_PASSWD'] - except KeyError: - pass - return name + return self._test_settings_get('PASSWORD', default=PASSWORD) def _test_database_tblspace(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] - try: - if self.connection.settings_dict['TEST_TBLSPACE']: - name = self.connection.settings_dict['TEST_TBLSPACE'] - except KeyError: - pass - return name + return self._test_settings_get('TBLSPACE', prefixed='NAME') def _test_database_tblspace_tmp(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] + '_temp' - try: - if self.connection.settings_dict['TEST_TBLSPACE_TMP']: - name = self.connection.settings_dict['TEST_TBLSPACE_TMP'] - except KeyError: - pass - return name + settings_dict = self.connection.settings_dict + return settings_dict['TEST'].get('TBLSPACE_TMP', + TEST_DATABASE_PREFIX + settings_dict['NAME'] + '_temp') def _get_test_db_name(self): """ diff --git a/django/db/backends/postgresql_psycopg2/creation.py b/django/db/backends/postgresql_psycopg2/creation.py index c66b6c6f55..2594ba1d5f 100644 --- a/django/db/backends/postgresql_psycopg2/creation.py +++ b/django/db/backends/postgresql_psycopg2/creation.py @@ -39,9 +39,10 @@ class DatabaseCreation(BaseDatabaseCreation): } 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." - if self.connection.settings_dict['TEST_CHARSET']: - return "WITH ENCODING '%s'" % self.connection.settings_dict['TEST_CHARSET'] + test_settings = self.connection.settings_dict['TEST'] + assert test_settings['COLLATION'] is None, "PostgreSQL does not support collation setting at database creation time." + if test_settings['CHARSET']: + return "WITH ENCODING '%s'" % test_settings['CHARSET'] return '' def sql_indexes_for_field(self, model, f, style): diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index bdd4560516..abcd068952 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -47,7 +47,7 @@ class DatabaseCreation(BaseDatabaseCreation): return [] 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:': return test_database_name return ':memory:' @@ -83,7 +83,7 @@ class DatabaseCreation(BaseDatabaseCreation): This takes into account the special cases of ":memory:" and "" for 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() sig = [self.connection.settings_dict['NAME']] diff --git a/django/db/utils.py b/django/db/utils.py index f0811f1b05..b114577a7f 100644 --- a/django/db/utils.py +++ b/django/db/utils.py @@ -181,14 +181,48 @@ class ConnectionHandler(object): conn.setdefault('TIME_ZONE', 'UTC' if settings.USE_TZ else settings.TIME_ZONE) for setting in ['NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']: 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): if hasattr(self._connections, alias): return getattr(self._connections, alias) self.ensure_defaults(alias) + self.prepare_test_settings(alias) db = self.databases[alias] backend = load_backend(db['ENGINE']) conn = backend.DatabaseWrapper(db, alias) diff --git a/django/test/runner.py b/django/test/runner.py index d3c53ffc44..ef899d6d0d 100644 --- a/django/test/runner.py +++ b/django/test/runner.py @@ -170,7 +170,7 @@ def is_discoverable(label): def dependency_ordered(test_databases, dependencies): """ Reorder test_databases into an order that honors the dependencies - described in TEST_DEPENDENCIES. + described in TEST[DEPENDENCIES]. """ ordered_test_databases = [] resolved_databases = set() @@ -204,7 +204,7 @@ def dependency_ordered(test_databases, dependencies): if not changed: raise ImproperlyConfigured( - "Circular dependency in TEST_DEPENDENCIES") + "Circular dependency in TEST[DEPENDENCIES]") test_databases = deferred return ordered_test_databases @@ -261,11 +261,11 @@ def setup_databases(verbosity, interactive, **kwargs): default_sig = connections[DEFAULT_DB_ALIAS].creation.test_db_signature() for alias in connections: 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 # the alias. - mirrored_aliases[alias] = ( - connection.settings_dict['TEST_MIRROR']) + mirrored_aliases[alias] = test_settings['MIRROR'] else: # Store a tuple with DB parameters that uniquely identify it. # 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) - if 'TEST_DEPENDENCIES' in connection.settings_dict: - dependencies[alias] = ( - connection.settings_dict['TEST_DEPENDENCIES']) + if 'DEPENDENCIES' in test_settings: + dependencies[alias] = test_settings['DEPENDENCIES'] else: if alias != DEFAULT_DB_ALIAS and connection.creation.test_db_signature() != default_sig: - dependencies[alias] = connection.settings_dict.get( - 'TEST_DEPENDENCIES', [DEFAULT_DB_ALIAS]) + dependencies[alias] = test_settings.get('DEPENDENCIES', [DEFAULT_DB_ALIAS]) # Second pass -- actually create the databases. old_names = [] diff --git a/django/test/testcases.py b/django/test/testcases.py index e4aaac3d42..5b5555bfce 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -762,7 +762,7 @@ class TransactionTestCase(SimpleTestCase): # including mirrors or not. Otherwise, just on the default DB. if getattr(self, 'multi_db', False): 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: return [DEFAULT_DB_ALIAS] diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 36bc2ee533..3a4c100730 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -121,6 +121,9 @@ details on these changes. * ``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: 1.8 diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 9d133b73eb..d7b87c0bd7 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -605,10 +605,29 @@ Default: ``''`` (Empty string) The username to use when connecting to the database. Not used with SQLite. +.. setting:: DATABASE-TEST + +TEST +~~~~ + +.. versionchanged:: 1.7 + + All :setting:`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 -TEST_CHARSET -~~~~~~~~~~~~ +CHARSET +^^^^^^^ Default: ``None`` @@ -624,8 +643,8 @@ backends. .. setting:: TEST_COLLATION -TEST_COLLATION -~~~~~~~~~~~~~~ +COLLATION +^^^^^^^^^ Default: ``None`` @@ -638,8 +657,8 @@ Only supported for the ``mysql`` backend (see the `MySQL manual`_ for details). .. setting:: TEST_DEPENDENCIES -TEST_DEPENDENCIES -~~~~~~~~~~~~~~~~~ +DEPENDENCIES +^^^^^^^^^^^^ Default: ``['default']``, for all databases other than ``default``, which has no dependencies. @@ -650,8 +669,8 @@ on :ref:`controlling the creation order of test databases .. setting:: TEST_MIRROR -TEST_MIRROR -~~~~~~~~~~~ +MIRROR +^^^^^^ Default: ``None`` @@ -665,8 +684,8 @@ configurations of multiple databases. See the documentation on .. setting:: TEST_NAME -TEST_NAME -~~~~~~~~~ +NAME +^^^^ Default: ``None`` @@ -680,8 +699,8 @@ See :ref:`the-test-database`. .. setting:: TEST_CREATE -TEST_CREATE -~~~~~~~~~~~ +CREATE_DB +^^^^^^^^^ 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 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 -TEST_USER_CREATE -~~~~~~~~~~~~~~~~ +CREATE_USER +^^^^^^^^^^^ 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 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 -TEST_PASSWD -~~~~~~~~~~~ +PASSWORD +^^^^^^^^ Default: ``None`` @@ -728,8 +747,8 @@ when running tests. If not provided, Django will use a hardcoded default value. .. setting:: TEST_TBLSPACE -TEST_TBLSPACE -~~~~~~~~~~~~~ +TBLSPACE +^^^^^^^^ Default: ``None`` @@ -740,8 +759,8 @@ provided, Django will use ``'test_' + NAME``. .. setting:: TEST_TBLSPACE_TMP -TEST_TBLSPACE_TMP -~~~~~~~~~~~~~~~~~ +TBLSPACE_TMP +^^^^^^^^^^^^ 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 not provided, Django will use ``'test_' + NAME + '_temp'``. +.. setting:: OLD_TEST_CHARSET + +TEST_CHARSET +~~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`CHARSET ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_COLLATION + +TEST_COLLATION +~~~~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`COLLATION ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_DEPENDENCIES + +TEST_DEPENDENCIES +~~~~~~~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`DEPENDENCIES ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_MIRROR + +TEST_MIRROR +~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`MIRROR ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_NAME + +TEST_NAME +~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`NAME ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_CREATE + +TEST_CREATE +~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`CREATE_DB ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_USER + +TEST_USER +~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`USER ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_USER_CREATE + +TEST_USER_CREATE +~~~~~~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`CREATE_USER ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_PASSWD + +TEST_PASSWD +~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`PASSWORD ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_TBLSPACE + +TEST_TBLSPACE +~~~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`TBLSPACE ` entry in the + :setting:`TEST ` dictionary. + +.. setting:: OLD_TEST_TBLSPACE_TMP + +TEST_TBLSPACE_TMP +~~~~~~~~~~~~~~~~~ + +.. deprecated:: 1.7 + + Use the :setting:`TBLSPACE_TMP ` entry in the + :setting:`TEST ` dictionary. + .. setting:: DATABASE_ROUTERS DATABASE_ROUTERS @@ -2960,20 +3089,7 @@ Templates Testing ------- -* Database - - * :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` - +* Database: :setting:`TEST ` * :setting:`TEST_RUNNER` URLs diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index fd1f44eb0d..52007c98aa 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -785,6 +785,9 @@ Tests * The ``WSGIRequest`` instance generated by the test handler is now attached to the :attr:`django.test.Response.wsgi_request` attribute. +* The database settings for testing have been collected into a dictionary + named :setting:`TEST `. + Validators ^^^^^^^^^^ @@ -1459,3 +1462,9 @@ a risk of introducing XSS vulnerabilities. Along with ``fix_ampersands``, ``fix_ampersands``. As this is an accelerated deprecation, ``fix_ampersands`` and ``clean_html`` 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 ` dictionary in the database +settings. The old settings will be supported until Django 1.9.