Fixed #17954 -- Fixed dependency checking for test databases. Thanks Łukasz Rekucki for the report and the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17931 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Claude Paroz 2012-04-24 16:05:47 +00:00
parent 530ab32e9f
commit 03a442c8ad
2 changed files with 51 additions and 34 deletions

View File

@ -193,31 +193,35 @@ def reorder_suite(suite, classes):
def dependency_ordered(test_databases, dependencies):
"""Reorder test_databases into an order that honors the dependencies
"""
Reorder test_databases into an order that honors the dependencies
described in TEST_DEPENDENCIES.
"""
ordered_test_databases = []
resolved_databases = set()
# Maps db signature to dependencies of all it's aliases
dependencies_map = {}
# sanity check - no DB can depend on it's own alias
for sig, (_, aliases) in test_databases:
all_deps = set()
for alias in aliases:
all_deps.update(dependencies.get(alias, []))
if not all_deps.isdisjoint(aliases):
raise ImproperlyConfigured(
"Circular dependency: databases %r depend on each other, "
"but are aliases." % aliases)
dependencies_map[sig] = all_deps
while test_databases:
changed = False
deferred = []
while test_databases:
signature, (db_name, aliases) = test_databases.pop()
dependencies_satisfied = True
for alias in aliases:
if alias in dependencies:
if all(a in resolved_databases
for a in dependencies[alias]):
# all dependencies for this alias are satisfied
dependencies.pop(alias)
resolved_databases.add(alias)
else:
dependencies_satisfied = False
else:
resolved_databases.add(alias)
if dependencies_satisfied:
# Try to find a DB that has all it's dependencies met
for signature, (db_name, aliases) in test_databases:
if dependencies_map[signature].issubset(resolved_databases):
resolved_databases.update(aliases)
ordered_test_databases.append((signature, (db_name, aliases)))
changed = True
else:
@ -282,9 +286,9 @@ class DjangoTestSuiteRunner(object):
# we only need to create the test database once.
item = test_databases.setdefault(
connection.creation.test_db_signature(),
(connection.settings_dict['NAME'], [])
(connection.settings_dict['NAME'], set())
)
item[1].append(alias)
item[1].add(alias)
if 'TEST_DEPENDENCIES' in connection.settings_dict:
dependencies[alias] = (
@ -297,26 +301,20 @@ class DjangoTestSuiteRunner(object):
# Second pass -- actually create the databases.
old_names = []
mirrors = []
for signature, (db_name, aliases) in dependency_ordered(
test_databases.items(), dependencies):
test_db_name = None
# Actually create the database for the first connection
connection = connections[aliases[0]]
old_names.append((connection, db_name, True))
test_db_name = connection.creation.create_test_db(
self.verbosity, autoclobber=not self.interactive)
for alias in aliases[1:]:
for alias in aliases:
connection = connections[alias]
if db_name:
old_names.append((connection, db_name, False))
connection.settings_dict['NAME'] = test_db_name
old_names.append((connection, db_name, True))
if test_db_name is None:
test_db_name = connection.creation.create_test_db(
self.verbosity, autoclobber=not self.interactive)
else:
# If settings_dict['NAME'] isn't defined, we have a backend
# where the name isn't important -- e.g., SQLite, which
# uses :memory:. Force create the database instead of
# assuming it's a duplicate.
old_names.append((connection, db_name, True))
connection.creation.create_test_db(
self.verbosity, autoclobber=not self.interactive)
connection.settings_dict['NAME'] = test_db_name
for alias, mirror_alias in mirrored_aliases.items():
mirrors.append((alias, connections[alias].settings_dict['NAME']))

View File

@ -110,6 +110,25 @@ class DependencyOrderingTests(unittest.TestCase):
self.assertRaises(ImproperlyConfigured, simple.dependency_ordered, raw, dependencies=dependencies)
def test_own_alias_dependency(self):
raw = [
('s1', ('s1_db', ['alpha', 'bravo']))
]
dependencies = {
'alpha': ['bravo']
}
with self.assertRaises(ImproperlyConfigured):
simple.dependency_ordered(raw, dependencies=dependencies)
# reordering aliases shouldn't matter
raw = [
('s1', ('s1_db', ['bravo', 'alpha']))
]
with self.assertRaises(ImproperlyConfigured):
simple.dependency_ordered(raw, dependencies=dependencies)
class MockTestRunner(object):
invoked = False