Fixed #12542 -- Added the TEST_MIRROR setting, allowing testing of read slave databases.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12289 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
739d5aec0f
commit
6755a039eb
|
@ -65,6 +65,7 @@ class ConnectionHandler(object):
|
||||||
conn.setdefault('TEST_CHARSET', None)
|
conn.setdefault('TEST_CHARSET', None)
|
||||||
conn.setdefault('TEST_COLLATION', None)
|
conn.setdefault('TEST_COLLATION', None)
|
||||||
conn.setdefault('TEST_NAME', None)
|
conn.setdefault('TEST_NAME', None)
|
||||||
|
conn.setdefault('TEST_MIRROR', None)
|
||||||
conn.setdefault('TIME_ZONE', settings.TIME_ZONE)
|
conn.setdefault('TIME_ZONE', 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, '')
|
||||||
|
|
|
@ -231,16 +231,30 @@ class DjangoTestSuiteRunner(object):
|
||||||
def setup_databases(self):
|
def setup_databases(self):
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
old_names = []
|
old_names = []
|
||||||
|
mirrors = []
|
||||||
for alias in connections:
|
for alias in connections:
|
||||||
connection = connections[alias]
|
connection = connections[alias]
|
||||||
|
# If the database is a test mirror, redirect it's connection
|
||||||
|
# instead of creating a test database.
|
||||||
|
if connection.settings_dict['TEST_MIRROR']:
|
||||||
|
mirrors.append((alias, connection))
|
||||||
|
mirror_alias = connection.settings_dict['TEST_MIRROR']
|
||||||
|
connections._connections[alias] = connections[mirror_alias]
|
||||||
|
else:
|
||||||
old_names.append((connection, connection.settings_dict['NAME']))
|
old_names.append((connection, connection.settings_dict['NAME']))
|
||||||
connection.creation.create_test_db(self.verbosity, autoclobber=not self.interactive)
|
connection.creation.create_test_db(self.verbosity, autoclobber=not self.interactive)
|
||||||
return old_names
|
return old_names, mirrors
|
||||||
|
|
||||||
def run_suite(self, suite):
|
def run_suite(self, suite):
|
||||||
return DjangoTestRunner(verbosity=self.verbosity, failfast=self.failfast).run(suite)
|
return DjangoTestRunner(verbosity=self.verbosity, failfast=self.failfast).run(suite)
|
||||||
|
|
||||||
def teardown_databases(self, old_names):
|
def teardown_databases(self, old_config):
|
||||||
|
from django.db import connections
|
||||||
|
old_names, mirrors = old_config
|
||||||
|
# Point all the mirrors back to the originals
|
||||||
|
for alias, connection in mirrors:
|
||||||
|
connections._connections[alias] = connection
|
||||||
|
# Destroy all the non-mirror databases
|
||||||
for connection, old_name in old_names:
|
for connection, old_name in old_names:
|
||||||
connection.creation.destroy_test_db(old_name, self.verbosity)
|
connection.creation.destroy_test_db(old_name, self.verbosity)
|
||||||
|
|
||||||
|
@ -273,11 +287,11 @@ class DjangoTestSuiteRunner(object):
|
||||||
|
|
||||||
suite = self.build_suite(test_labels, extra_tests)
|
suite = self.build_suite(test_labels, extra_tests)
|
||||||
|
|
||||||
old_names = self.setup_databases()
|
old_config = self.setup_databases()
|
||||||
|
|
||||||
result = self.run_suite(suite)
|
result = self.run_suite(suite)
|
||||||
|
|
||||||
self.teardown_databases(old_names)
|
self.teardown_databases(old_config)
|
||||||
|
|
||||||
self.teardown_test_environment()
|
self.teardown_test_environment()
|
||||||
|
|
||||||
|
|
|
@ -357,6 +357,21 @@ Only supported for the ``mysql`` backend (see the `MySQL manual`_ for details).
|
||||||
|
|
||||||
.. _MySQL manual: MySQL_
|
.. _MySQL manual: MySQL_
|
||||||
|
|
||||||
|
.. setting:: TEST_MIRROR
|
||||||
|
|
||||||
|
TEST_MIRROR
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
Default: ``None``
|
||||||
|
|
||||||
|
The alias of the database that this database should mirror during
|
||||||
|
testing.
|
||||||
|
|
||||||
|
This setting exists to allow for testing of master/slave
|
||||||
|
configurations of multiple databases. See the documentation on
|
||||||
|
:ref:`testing master/slave configurations
|
||||||
|
<topics-testing-masterslave>` for details.
|
||||||
|
|
||||||
.. setting:: TEST_NAME
|
.. setting:: TEST_NAME
|
||||||
|
|
||||||
TEST_NAME
|
TEST_NAME
|
||||||
|
|
|
@ -301,12 +301,12 @@ Regardless of whether the tests pass or fail, the test databases are destroyed
|
||||||
when all the tests have been executed.
|
when all the tests have been executed.
|
||||||
|
|
||||||
By default the test databases get their names by prepending ``test_``
|
By default the test databases get their names by prepending ``test_``
|
||||||
to the value of the :setting:`NAME`` settings for the databased
|
to the value of the :setting:`NAME` settings for the databases
|
||||||
defined in :setting:`DATABASES`. When using the SQLite database engine
|
defined in :setting:`DATABASES`. When using the SQLite database engine
|
||||||
the tests will by default use an in-memory database (i.e., the
|
the tests will by default use an in-memory database (i.e., the
|
||||||
database will be created in memory, bypassing the filesystem
|
database will be created in memory, bypassing the filesystem
|
||||||
entirely!). If you want to use a different database name, specify
|
entirely!). If you want to use a different database name, specify
|
||||||
``TEST_NAME`` in the dictionary for any given database in
|
:setting:`TEST_NAME` in the dictionary for any given database in
|
||||||
:setting:`DATABASES`.
|
:setting:`DATABASES`.
|
||||||
|
|
||||||
Aside from using a separate database, the test runner will otherwise
|
Aside from using a separate database, the test runner will otherwise
|
||||||
|
@ -325,6 +325,58 @@ control the particular collation used by the test database. See the
|
||||||
:ref:`settings documentation <ref-settings>` for details of these
|
:ref:`settings documentation <ref-settings>` for details of these
|
||||||
advanced settings.
|
advanced settings.
|
||||||
|
|
||||||
|
.. _topics-testing-masterslave:
|
||||||
|
|
||||||
|
Testing master/slave configurations
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
|
If you're testing a multiple database configuration with master/slave
|
||||||
|
replication, this strategy of creating test databases poses a problem.
|
||||||
|
When the test databases are created, there won't be any replication,
|
||||||
|
and as a result, data created on the master won't be seen on the
|
||||||
|
slave.
|
||||||
|
|
||||||
|
To compensate for this, Django allows you to define that a database is
|
||||||
|
a *test mirror*. Consider the following (simplified) example database
|
||||||
|
configuration::
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
|
'NAME': 'myproject',
|
||||||
|
'HOST': 'dbmaster',
|
||||||
|
# ... plus some other settings
|
||||||
|
},
|
||||||
|
'slave': {
|
||||||
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
|
'NAME': 'myproject',
|
||||||
|
'HOST': 'dbslave',
|
||||||
|
'TEST_MIRROR': 'default'
|
||||||
|
# ... plus some other settings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
In this setup, we have two database servers: ``dbmaster``, described
|
||||||
|
by the database alias ``default``, and ``dbslave`` described by the
|
||||||
|
alias ``slave``. As you might expect, ``dbslave`` has been configured
|
||||||
|
by the database administrator as a read slave of ``dbmaster``, so in
|
||||||
|
normal activity, any write to ``default`` will appear on ``slave``.
|
||||||
|
|
||||||
|
If Django created two independent test databases, this would break any
|
||||||
|
tests that expected replication to occur. However, the ``slave``
|
||||||
|
database has been configured as a test mirror (using the
|
||||||
|
:setting:`TEST_MIRROR` setting), indicating that under testing,
|
||||||
|
``slave`` should be treated as a mirror of ``default``.
|
||||||
|
|
||||||
|
When the test environment is configured, a test version of ``slave``
|
||||||
|
will *not* be created. Instead the connection to ``slave``
|
||||||
|
will be redirected to point at ``default``. As a result, writes to
|
||||||
|
``default`` will appear on ``slave`` -- but because they are actually
|
||||||
|
the same database, not because there is data replication between the
|
||||||
|
two databases.
|
||||||
|
|
||||||
Other test conditions
|
Other test conditions
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
@ -1349,7 +1401,9 @@ set up, execute and tear down the test suite.
|
||||||
|
|
||||||
Creates the test databases.
|
Creates the test databases.
|
||||||
|
|
||||||
Returns the list of old database names that will need to be restored
|
Returns a data structure that provides enough detail to undo the changes
|
||||||
|
that have been made. This data will be provided to the ``teardown_databases()``
|
||||||
|
function at the conclusion of testing.
|
||||||
|
|
||||||
.. method:: DjangoTestSuiteRunner.run_suite(suite)
|
.. method:: DjangoTestSuiteRunner.run_suite(suite)
|
||||||
|
|
||||||
|
@ -1357,9 +1411,13 @@ set up, execute and tear down the test suite.
|
||||||
|
|
||||||
Returns the result produced by the running the test suite.
|
Returns the result produced by the running the test suite.
|
||||||
|
|
||||||
.. method:: DjangoTestSuiteRunner.teardown_databases(old_names)
|
.. method:: DjangoTestSuiteRunner.teardown_databases(old_config)
|
||||||
|
|
||||||
Destroys the test databases, restoring the old names.
|
Destroys the test databases, restoring pre-test conditions.
|
||||||
|
|
||||||
|
``old_config`` is a data structure defining the changes in the
|
||||||
|
database configuration that need to be reversed. It is the return
|
||||||
|
value of the ``setup_databases()`` method.
|
||||||
|
|
||||||
.. method:: DjangoTestSuiteRunner.teardown_test_environment()
|
.. method:: DjangoTestSuiteRunner.teardown_test_environment()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue