Author: russellm
Date: 2010-01-25 06:05:38 -0600 (Mon, 25 Jan 2010)
New Revision: 12289

Modified:
   django/trunk/django/db/utils.py
   django/trunk/django/test/simple.py
   django/trunk/docs/ref/settings.txt
   django/trunk/docs/topics/testing.txt
Log:
Fixed #12542 -- Added the TEST_MIRROR setting, allowing testing of read slave 
databases.

Modified: django/trunk/django/db/utils.py
===================================================================
--- django/trunk/django/db/utils.py     2010-01-24 00:10:30 UTC (rev 12288)
+++ django/trunk/django/db/utils.py     2010-01-25 12:05:38 UTC (rev 12289)
@@ -65,6 +65,7 @@
         conn.setdefault('TEST_CHARSET', None)
         conn.setdefault('TEST_COLLATION', None)
         conn.setdefault('TEST_NAME', None)
+        conn.setdefault('TEST_MIRROR', None)
         conn.setdefault('TIME_ZONE', settings.TIME_ZONE)
         for setting in ('NAME', 'USER', 'PASSWORD', 'HOST', 'PORT'):
             conn.setdefault(setting, '')

Modified: django/trunk/django/test/simple.py
===================================================================
--- django/trunk/django/test/simple.py  2010-01-24 00:10:30 UTC (rev 12288)
+++ django/trunk/django/test/simple.py  2010-01-25 12:05:38 UTC (rev 12289)
@@ -231,16 +231,30 @@
     def setup_databases(self):
         from django.db import connections
         old_names = []
+        mirrors = []
         for alias in connections:
             connection = connections[alias]
-            old_names.append((connection, connection.settings_dict['NAME']))
-            connection.creation.create_test_db(self.verbosity, autoclobber=not 
self.interactive)
-        return old_names
+            # 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']))
+                connection.creation.create_test_db(self.verbosity, 
autoclobber=not self.interactive)
+        return old_names, mirrors
 
     def run_suite(self, 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:
             connection.creation.destroy_test_db(old_name, self.verbosity)
 
@@ -273,11 +287,11 @@
 
         suite = self.build_suite(test_labels, extra_tests)
 
-        old_names = self.setup_databases()
+        old_config = self.setup_databases()
 
         result = self.run_suite(suite)
 
-        self.teardown_databases(old_names)
+        self.teardown_databases(old_config)
 
         self.teardown_test_environment()
 

Modified: django/trunk/docs/ref/settings.txt
===================================================================
--- django/trunk/docs/ref/settings.txt  2010-01-24 00:10:30 UTC (rev 12288)
+++ django/trunk/docs/ref/settings.txt  2010-01-25 12:05:38 UTC (rev 12289)
@@ -357,6 +357,21 @@
 
 .. _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
 
 TEST_NAME

Modified: django/trunk/docs/topics/testing.txt
===================================================================
--- django/trunk/docs/topics/testing.txt        2010-01-24 00:10:30 UTC (rev 
12288)
+++ django/trunk/docs/topics/testing.txt        2010-01-25 12:05:38 UTC (rev 
12289)
@@ -301,12 +301,12 @@
 when all the tests have been executed.
 
 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
 the tests will by default use an in-memory database (i.e., the
 database will be created in memory, bypassing the filesystem
 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`.
 
 Aside from using a separate database, the test runner will otherwise
@@ -325,6 +325,58 @@
 :ref:`settings documentation <ref-settings>` for details of these
 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
 ---------------------
 
@@ -1349,7 +1401,9 @@
 
     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)
 
@@ -1357,10 +1411,14 @@
 
     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()
 
     Restores the pre-test environment.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to