jazzband / django-nose

Django test runner using nose
http://pypi.python.org/pypi/django-nose
BSD 3-Clause "New" or "Revised" License
882 stars 234 forks source link

Double renaming test DB #88

Open vstepanov opened 12 years ago

vstepanov commented 12 years ago

In NoseTestSuiteRunner.setup_databases all connections are renamed to test db names (creation._get_test_db_name() returns test_ORIGINAL_DB_NAME) and call setup_databases of DjangoTestSuiteRunner, in which this name was again renamed to test_test_ORIGINAL_DB_NAME .

This problem manifests itself, when there are several connections (aliases) to one database, because DjangoTestSuiteRunner.setup_databases sets connection.settings_dict['NAME'] = test_db_name for aliases which are more than one to one database.

Versions: django==1.4 django_nose==1.1 database - mysql

these changes have fixed the issue.

diff --git a/django_nose/runner.py b/django_nose/runner.py
index 18df494..b03e605 100644
--- a/django_nose/runner.py
+++ b/django_nose/runner.py
@@ -200,7 +200,9 @@ def _skip_create_test_db(self, verbosity=1, autoclobber=False):
         can_rollback = self._rollback_works()
         self.connection.settings_dict['SUPPORTS_TRANSACTIONS'] = can_rollback

-    return self._get_test_db_name()
+    test_db_name = self._get_test_db_name()
+    self.connection.settings_dict['NAME'] = test_db_name
+    return test_db_name

 def _reusing_db():
@@ -277,9 +279,6 @@ class NoseTestSuiteRunner(BasicNoseRunner):
             connection.settings_dict['NAME'] = test_db_name

             if _should_create_database(connection):
-                # We're not using _skip_create_test_db, so put the DB name back:
-                connection.settings_dict['NAME'] = orig_db_name
-
                 # Since we replaced the connection with the test DB, closing
                 # the connection will avoid pooling issues with SQLAlchemy. The
                 # issue is trying to CREATE/DROP the test database using a
@@ -313,6 +312,9 @@ class NoseTestSuiteRunner(BasicNoseRunner):
                 creation.create_test_db = new.instancemethod(
                         _skip_create_test_db, creation, creation.__class__)

+            # Put the DB name back
+            connection.settings_dict['NAME'] = orig_db_name
+
         Command.handle = _foreign_key_ignoring_handle

         # With our class patch, does nothing but return some connection
vstepanov commented 12 years ago

Configuring the connection while creating a new database isn't very good solution, but it was implemented in the method django/db/backends/creation.py:BaseDatabaseCreation.create_test_db which we have overridden by _skip_create_test_db. So the name in the connection settings must be set in _skip_create_test_db.

vstepanov commented 12 years ago

To use non-existent DB!!

Your _NoseTestSuiteRunner.setupdatabases renamed DB name (added prefix test_ to original DB name) in connection's settings and calls _DjangoTestSuiteRunner.setupdatabases:

class NoseTestSuiteRunner(BasicNoseRunner):
    def setup_databases(self):
        ...
        connection.settings_dict['NAME'] = test_db_name
        ...
        return super(NoseTestSuiteRunner, self).setup_databases()

Note: before calls _DjangoTestSuiteRunner.setupdatabases all connections (_connection.settingsdict['NAME']) are renamed to the test DBs names (added prefix test_ to the original DB name).

Since a database can have multiple connections(aliases) to it, so:

class DjangoTestSuiteRunner(object):

...
   def setup_databases(self, **kwargs):

       ...

            for alias in aliases[1:]:
                connection = connections[alias]
                if db_name:
                    old_names.append((connection, db_name, False))
                    connection.settings_dict['NAME'] = test_db_name

You should put back original database name to _connection.settingsdict['NAME'] before calling _DjangoTestSuiteRunner.setupdatabases.