Fixed #27061 -- Added a TEST['TEMPLATE'] setting for PostgreSQL.
This commit is contained in:
parent
bc1e2d8e8e
commit
a3db480393
|
@ -5,28 +5,42 @@ from django.db.backends.base.creation import BaseDatabaseCreation
|
||||||
|
|
||||||
class DatabaseCreation(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):
|
def sql_table_creation_suffix(self):
|
||||||
test_settings = self.connection.settings_dict['TEST']
|
test_settings = self.connection.settings_dict['TEST']
|
||||||
assert test_settings['COLLATION'] is None, (
|
assert test_settings['COLLATION'] is None, (
|
||||||
"PostgreSQL does not support collation setting at database creation time."
|
"PostgreSQL does not support collation setting at database creation time."
|
||||||
)
|
)
|
||||||
if test_settings['CHARSET']:
|
return self._get_database_create_suffix(
|
||||||
return "WITH ENCODING '%s'" % test_settings['CHARSET']
|
encoding=test_settings['CHARSET'],
|
||||||
return ''
|
template=test_settings.get('TEMPLATE'),
|
||||||
|
)
|
||||||
|
|
||||||
def _clone_test_db(self, number, verbosity, keepdb=False):
|
def _clone_test_db(self, number, verbosity, keepdb=False):
|
||||||
# CREATE DATABASE ... WITH TEMPLATE ... requires closing connections
|
# CREATE DATABASE ... WITH TEMPLATE ... requires closing connections
|
||||||
# to the template database.
|
# to the template database.
|
||||||
self.connection.close()
|
self.connection.close()
|
||||||
|
|
||||||
qn = self.connection.ops.quote_name
|
|
||||||
source_database_name = self.connection.settings_dict['NAME']
|
source_database_name = self.connection.settings_dict['NAME']
|
||||||
target_database_name = self.get_test_db_clone_settings(number)['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:
|
with self._nodb_connection.cursor() as cursor:
|
||||||
try:
|
try:
|
||||||
cursor.execute("CREATE DATABASE %s WITH TEMPLATE %s" % (
|
cursor.execute(creation_sql)
|
||||||
qn(target_database_name), qn(source_database_name)))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if keepdb:
|
if keepdb:
|
||||||
return
|
return
|
||||||
|
@ -35,9 +49,8 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
print("Destroying old test database for alias %s..." % (
|
print("Destroying old test database for alias %s..." % (
|
||||||
self._get_database_display_str(verbosity, target_database_name),
|
self._get_database_display_str(verbosity, target_database_name),
|
||||||
))
|
))
|
||||||
cursor.execute("DROP DATABASE %s" % qn(target_database_name))
|
cursor.execute("DROP DATABASE %s" % self._quote_name(target_database_name))
|
||||||
cursor.execute("CREATE DATABASE %s WITH TEMPLATE %s" % (
|
cursor.execute(creation_sql)
|
||||||
qn(target_database_name), qn(source_database_name)))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.stderr.write("Got an error cloning the test database: %s\n" % e)
|
sys.stderr.write("Got an error cloning the test database: %s\n" % e)
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
|
@ -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
|
.. _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
|
Speeding up test execution with non-durable settings
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
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>`.
|
||||||
|
|
||||||
|
.. 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
|
.. setting:: TEST_CREATE
|
||||||
|
|
||||||
``CREATE_DB``
|
``CREATE_DB``
|
||||||
|
|
|
@ -159,6 +159,9 @@ Database backends
|
||||||
on PostgreSQL 9.5+ and Oracle to execute queries with
|
on PostgreSQL 9.5+ and Oracle to execute queries with
|
||||||
``FOR UPDATE SKIP LOCKED``.
|
``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
|
Email
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import copy
|
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 (
|
from django.db.backends.base.creation import (
|
||||||
TEST_DATABASE_PREFIX, BaseDatabaseCreation,
|
TEST_DATABASE_PREFIX, BaseDatabaseCreation,
|
||||||
)
|
)
|
||||||
|
from django.db.backends.postgresql.creation import DatabaseCreation
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,3 +43,48 @@ class TestDbSignatureTests(SimpleTestCase):
|
||||||
test_connection.settings_dict['TEST'] = {'NAME': test_name}
|
test_connection.settings_dict['TEST'] = {'NAME': test_name}
|
||||||
signature = BaseDatabaseCreation(test_connection).test_db_signature()
|
signature = BaseDatabaseCreation(test_connection).test_db_signature()
|
||||||
self.assertEqual(signature[3], test_name)
|
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"''')
|
||||||
|
|
Loading…
Reference in New Issue