1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

[multi-db] Updated tests/runtests.py to create test databases for all

named connections (if any) in addition to the default connection. 
Updated LazyConnectionManager to allow assignment to connection names. 


git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3238 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jason Pellerin 2006-06-29 22:00:25 +00:00
parent 75b64abaa7
commit a50d895f28
2 changed files with 121 additions and 59 deletions

View File

@ -96,10 +96,13 @@ class LazyConnectionManager(object):
def __getitem__(self, k): def __getitem__(self, k):
try: try:
return self._connections[k] return self.__dict__['_connections'][k]
except KeyError: except KeyError:
return self.connect(k) return self.connect(k)
def __setitem__(self, k, v):
self.__dict__['_connections'][k] = v
def connect(self, name): def connect(self, name):
"""Return the connection with this name in """Return the connection with this name in
settings.DATABASES. Creates the connection if it doesn't yet settings.DATABASES. Creates the connection if it doesn't yet

View File

@ -84,13 +84,79 @@ class TestRunner:
def __init__(self, verbosity_level=0, which_tests=None): def __init__(self, verbosity_level=0, which_tests=None):
self.verbosity_level = verbosity_level self.verbosity_level = verbosity_level
self.which_tests = which_tests self.which_tests = which_tests
self.created_dbs = []
self.sqlite_memory_db_used = False
self.cleanup_files = []
def output(self, required_level, message): def output(self, required_level, message):
if self.verbosity_level > required_level - 1: if self.verbosity_level > required_level - 1:
print message print message
def create_test_db(self, connection):
"""Create a test db, returning a ConnectionInfo object holding
a connection to that db.
"""
from django.db import connect
settings = connection.settings
# If we're using SQLite, it's more convenient to test against an
# in-memory database. But we can only do this for the first one; after
# that we have to use temp files.
if settings.DATABASE_ENGINE == "sqlite3":
if self.sqlite_memory_db_used:
import tempfile
fd, filename = tempfile.mkstemp()
os.close(fd)
db_name = filename
self.cleanup_files.append(filename)
else:
db_name = ":memory:"
self.sqlite_memory_db_used = True
else:
db_name = TEST_DATABASE_NAME
if self.created_dbs:
db_name += "_%s" % (len(self.created_dbs))
# Create the test database and connect to it. We need to autocommit
# if the database supports it because PostgreSQL doesn't allow
# CREATE/DROP DATABASE statements within transactions.
cursor = connection.cursor()
self._set_autocommit(connection)
self.output(1, "Creating test database %s for %s" %
(db_name, settings.DATABASE_NAME))
try:
cursor.execute("CREATE DATABASE %s" % db_name)
except Exception, e:
sys.stderr.write("Got an error creating the test database: %s\n" % e)
confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % db_name)
if confirm == 'yes':
cursor.execute("DROP DATABASE %s" % db_name)
cursor.execute("CREATE DATABASE %s" % db_name)
else:
raise Exception("Tests cancelled.")
settings.DATABASE_NAME = db_name
connection.close()
# Initialize the test database.
info = connect(settings)
cursor = info.connection.cursor()
self.created_dbs.append((db_name, info))
return info
def run_tests(self): def run_tests(self):
self.setup()
try:
self._run_tests()
finally:
self.teardown()
def setup(self):
from django.conf import settings from django.conf import settings
from django.db import connection, connections
from django.core import management
from django.db.models.loading import load_app
# An empty access of the settings to force the default options to be # An empty access of the settings to force the default options to be
# installed prior to assigning to them. # installed prior to assigning to them.
@ -102,9 +168,55 @@ class TestRunner:
# Manually set DEBUG = False. # Manually set DEBUG = False.
settings.DEBUG = False settings.DEBUG = False
self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE)
# Create test dbs for the default connection and any named connections
# in settings. Remeber the original default db name so we can connect
# there to drop the created test dbs.
self._old_database_name = settings.DATABASE_NAME
self.create_test_db(connection)
if hasattr(settings, 'DATABASES'):
for name, info in settings.DATABASES.items():
cx = connections[name]
test_connection = self.create_test_db(cx.connection)
connections[name] = test_connection
# Install the core always installed apps
for app in ALWAYS_INSTALLED_APPS:
self.output(1, "Installing contrib app %s" % app)
mod = load_app(app)
management.install(mod)
def teardown(self):
# Unless we're using SQLite, remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it's not allowed to delete a database while being
# connected to it.
from django.db import connection from django.db import connection
from django.conf import settings
connection.close()
settings.DATABASE_NAME = self._old_database_name
for db_name, cx in self.created_dbs:
settings = cx.settings
cx.close()
if settings.DATABASE_ENGINE != "sqlite3":
cursor = connection.cursor()
self.output(1, "Deleting test database %s" % db_name)
self._set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors.
cursor.execute("DROP DATABASE %s" % db_name)
# Clean up sqlite dbs created on the filesystem
for filename in self.cleanup_files:
if os.path.exists(filename):
os.unlink(filename)
def _run_tests(self):
# Run the tests for each test model.
from django.core import management from django.core import management
import django.db.models from django.db.models.loading import load_app
from django.db import models
# Determine which models we're going to test. # Determine which models we're going to test.
test_models = get_test_models() test_models = get_test_models()
@ -130,46 +242,6 @@ class TestRunner:
all_tests.append((loc, test)) all_tests.append((loc, test))
test_models = all_tests test_models = all_tests
self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE)
# If we're using SQLite, it's more convenient to test against an
# in-memory database.
if settings.DATABASE_ENGINE == "sqlite3":
global TEST_DATABASE_NAME
TEST_DATABASE_NAME = ":memory:"
else:
# Create the test database and connect to it. We need to autocommit
# if the database supports it because PostgreSQL doesn't allow
# CREATE/DROP DATABASE statements within transactions.
cursor = connection.cursor()
self._set_autocommit(connection)
self.output(1, "Creating test database")
try:
cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME)
except Exception, e:
sys.stderr.write("Got an error creating the test database: %s\n" % e)
confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
if confirm == 'yes':
cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME)
cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME)
else:
print "Tests cancelled."
return
connection.close()
old_database_name = settings.DATABASE_NAME
settings.DATABASE_NAME = TEST_DATABASE_NAME
# Initialize the test database.
cursor = connection.cursor()
from django.db.models.loading import load_app
# Install the core always installed apps
for app in ALWAYS_INSTALLED_APPS:
self.output(1, "Installing contrib app %s" % app)
mod = load_app(app)
management.install(mod)
# Run the tests for each test model.
self.output(1, "Running app tests") self.output(1, "Running app tests")
for model_dir, model_name in test_models: for model_dir, model_name in test_models:
self.output(1, "%s model: Importing" % model_name) self.output(1, "%s model: Importing" % model_name)
@ -187,7 +259,7 @@ class TestRunner:
# Run the API tests. # Run the API tests.
p = doctest.DocTestParser() p = doctest.DocTestParser()
test_namespace = dict([(m._meta.object_name, m) \ test_namespace = dict([(m._meta.object_name, m) \
for m in django.db.models.get_models(mod)]) for m in models.get_models(mod)])
dtest = p.get_doctest(mod.API_TESTS, test_namespace, model_name, None, None) dtest = p.get_doctest(mod.API_TESTS, test_namespace, model_name, None, None)
# Manually set verbose=False, because "-v" command-line parameter # Manually set verbose=False, because "-v" command-line parameter
# has side effects on doctest TestRunner class. # has side effects on doctest TestRunner class.
@ -242,19 +314,6 @@ class TestRunner:
log_error(module, "Exception running tests", ''.join(traceback.format_exception(*sys.exc_info())[1:])) log_error(module, "Exception running tests", ''.join(traceback.format_exception(*sys.exc_info())[1:]))
continue continue
# Unless we're using SQLite, remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it's not allowed to delete a database while being
# connected to it.
if settings.DATABASE_ENGINE != "sqlite3":
connection.close()
settings.DATABASE_NAME = old_database_name
cursor = connection.cursor()
self.output(1, "Deleting test database")
self._set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors.
cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME)
# Display output. # Display output.
if error_list: if error_list:
for d in error_list: for d in error_list: