0
0
mirror of https://github.com/django/django.git synced 2024-12-01 15:42:04 +01:00

Fixed #27061 -- Added a TEST['TEMPLATE'] setting for PostgreSQL.

This commit is contained in:
Chris Jerdonek 2016-08-15 07:10:40 -07:00 committed by Tim Graham
parent bc1e2d8e8e
commit a3db480393
5 changed files with 98 additions and 10 deletions

View File

@ -5,28 +5,42 @@ from django.db.backends.base.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
def _quote_name(self, name):
return self.connection.ops.quote_name(name)
def _get_database_create_suffix(self, encoding=None, template=None):
suffix = ""
if encoding:
suffix += " ENCODING '{}'".format(encoding)
if template:
suffix += " TEMPLATE {}".format(self._quote_name(template))
if suffix:
suffix = "WITH" + suffix
return suffix
def sql_table_creation_suffix(self):
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 ''
return self._get_database_create_suffix(
encoding=test_settings['CHARSET'],
template=test_settings.get('TEMPLATE'),
)
def _clone_test_db(self, number, verbosity, keepdb=False):
# CREATE DATABASE ... WITH TEMPLATE ... requires closing connections
# to the template database.
self.connection.close()
qn = self.connection.ops.quote_name
source_database_name = self.connection.settings_dict['NAME']
target_database_name = self.get_test_db_clone_settings(number)['NAME']
suffix = self._get_database_create_suffix(template=source_database_name)
creation_sql = "CREATE DATABASE {} {}".format(self._quote_name(target_database_name), suffix)
with self._nodb_connection.cursor() as cursor:
try:
cursor.execute("CREATE DATABASE %s WITH TEMPLATE %s" % (
qn(target_database_name), qn(source_database_name)))
cursor.execute(creation_sql)
except Exception as e:
if keepdb:
return
@ -35,9 +49,8 @@ class DatabaseCreation(BaseDatabaseCreation):
print("Destroying old test database for alias %s..." % (
self._get_database_display_str(verbosity, target_database_name),
))
cursor.execute("DROP DATABASE %s" % qn(target_database_name))
cursor.execute("CREATE DATABASE %s WITH TEMPLATE %s" % (
qn(target_database_name), qn(source_database_name)))
cursor.execute("DROP DATABASE %s" % self._quote_name(target_database_name))
cursor.execute(creation_sql)
except Exception as e:
sys.stderr.write("Got an error cloning the test database: %s\n" % e)
sys.exit(2)

View File

@ -164,6 +164,16 @@ lookups that use the ``LIKE`` operator in their SQL, as is done with the
.. _PostgreSQL operator class: http://www.postgresql.org/docs/current/static/indexes-opclass.html
Test database templates
-----------------------
.. versionadded:: 1.11
You can use the :setting:`TEST['TEMPLATE'] <TEST_TEMPLATE>` setting to specify
a `template`_ (e.g. ``'template0'``) from which to create a test database.
.. _template: https://www.postgresql.org/docs/current/static/sql-createdatabase.html
Speeding up test execution with non-durable settings
----------------------------------------------------

View File

@ -738,6 +738,20 @@ 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>`.
.. setting:: TEST_TEMPLATE
``TEMPLATE``
^^^^^^^^^^^^
.. versionadded:: 1.11
This is a PostgreSQL-specific setting.
The name of a `template`_ (e.g. ``'template0'``) from which to create the test
database.
.. _template: https://www.postgresql.org/docs/current/static/sql-createdatabase.html
.. setting:: TEST_CREATE
``CREATE_DB``

View File

@ -159,6 +159,9 @@ Database backends
on PostgreSQL 9.5+ and Oracle to execute queries with
``FOR UPDATE SKIP LOCKED``.
* Added the :setting:`TEST['TEMPLATE'] <TEST_TEMPLATE>` setting to let
PostgreSQL users specify a template for creating the test database.
Email
~~~~~

View File

@ -1,9 +1,12 @@
import copy
import unittest
from contextlib import contextmanager
from django.db import DEFAULT_DB_ALIAS, connections
from django.db import DEFAULT_DB_ALIAS, connection, connections
from django.db.backends.base.creation import (
TEST_DATABASE_PREFIX, BaseDatabaseCreation,
)
from django.db.backends.postgresql.creation import DatabaseCreation
from django.test import SimpleTestCase
@ -40,3 +43,48 @@ class TestDbSignatureTests(SimpleTestCase):
test_connection.settings_dict['TEST'] = {'NAME': test_name}
signature = BaseDatabaseCreation(test_connection).test_db_signature()
self.assertEqual(signature[3], test_name)
@unittest.skipUnless(connection.vendor == 'postgresql', "PostgreSQL-specific tests")
class PostgreSQLDatabaseCreationTests(SimpleTestCase):
@contextmanager
def changed_test_settings(self, **kwargs):
settings = connection.settings_dict['TEST']
saved_values = {}
for name in kwargs:
if name in settings:
saved_values[name] = settings[name]
for name, value in kwargs.items():
settings[name] = value
try:
yield
finally:
for name, value in kwargs.items():
if name in saved_values:
settings[name] = saved_values[name]
else:
del settings[name]
def check_sql_table_creation_suffix(self, settings, expected):
with self.changed_test_settings(**settings):
creation = DatabaseCreation(connection)
suffix = creation.sql_table_creation_suffix()
self.assertEqual(suffix, expected)
def test_sql_table_creation_suffix_with_none_settings(self):
settings = dict(CHARSET=None, TEMPLATE=None)
self.check_sql_table_creation_suffix(settings, "")
def test_sql_table_creation_suffix_with_encoding(self):
settings = dict(CHARSET='UTF8')
self.check_sql_table_creation_suffix(settings, "WITH ENCODING 'UTF8'")
def test_sql_table_creation_suffix_with_template(self):
settings = dict(TEMPLATE='template0')
self.check_sql_table_creation_suffix(settings, 'WITH TEMPLATE "template0"')
def test_sql_table_creation_suffix_with_encoding_and_template(self):
settings = dict(CHARSET='UTF8', TEMPLATE='template0')
self.check_sql_table_creation_suffix(settings, '''WITH ENCODING 'UTF8' TEMPLATE "template0"''')