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:
parent
530ab32e9f
commit
03a442c8ad
|
@ -193,31 +193,35 @@ def reorder_suite(suite, classes):
|
||||||
|
|
||||||
|
|
||||||
def dependency_ordered(test_databases, dependencies):
|
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.
|
described in TEST_DEPENDENCIES.
|
||||||
"""
|
"""
|
||||||
ordered_test_databases = []
|
ordered_test_databases = []
|
||||||
resolved_databases = set()
|
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:
|
while test_databases:
|
||||||
changed = False
|
changed = False
|
||||||
deferred = []
|
deferred = []
|
||||||
|
|
||||||
while test_databases:
|
# Try to find a DB that has all it's dependencies met
|
||||||
signature, (db_name, aliases) = test_databases.pop()
|
for signature, (db_name, aliases) in test_databases:
|
||||||
dependencies_satisfied = True
|
if dependencies_map[signature].issubset(resolved_databases):
|
||||||
for alias in aliases:
|
resolved_databases.update(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:
|
|
||||||
ordered_test_databases.append((signature, (db_name, aliases)))
|
ordered_test_databases.append((signature, (db_name, aliases)))
|
||||||
changed = True
|
changed = True
|
||||||
else:
|
else:
|
||||||
|
@ -282,9 +286,9 @@ class DjangoTestSuiteRunner(object):
|
||||||
# we only need to create the test database once.
|
# we only need to create the test database once.
|
||||||
item = test_databases.setdefault(
|
item = test_databases.setdefault(
|
||||||
connection.creation.test_db_signature(),
|
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:
|
if 'TEST_DEPENDENCIES' in connection.settings_dict:
|
||||||
dependencies[alias] = (
|
dependencies[alias] = (
|
||||||
|
@ -297,26 +301,20 @@ class DjangoTestSuiteRunner(object):
|
||||||
# Second pass -- actually create the databases.
|
# Second pass -- actually create the databases.
|
||||||
old_names = []
|
old_names = []
|
||||||
mirrors = []
|
mirrors = []
|
||||||
|
|
||||||
for signature, (db_name, aliases) in dependency_ordered(
|
for signature, (db_name, aliases) in dependency_ordered(
|
||||||
test_databases.items(), dependencies):
|
test_databases.items(), dependencies):
|
||||||
|
test_db_name = None
|
||||||
# Actually create the database for the first connection
|
# Actually create the database for the first connection
|
||||||
connection = connections[aliases[0]]
|
|
||||||
old_names.append((connection, db_name, True))
|
for alias in aliases:
|
||||||
test_db_name = connection.creation.create_test_db(
|
|
||||||
self.verbosity, autoclobber=not self.interactive)
|
|
||||||
for alias in aliases[1:]:
|
|
||||||
connection = connections[alias]
|
connection = connections[alias]
|
||||||
if db_name:
|
old_names.append((connection, db_name, True))
|
||||||
old_names.append((connection, db_name, False))
|
if test_db_name is None:
|
||||||
connection.settings_dict['NAME'] = test_db_name
|
test_db_name = connection.creation.create_test_db(
|
||||||
|
self.verbosity, autoclobber=not self.interactive)
|
||||||
else:
|
else:
|
||||||
# If settings_dict['NAME'] isn't defined, we have a backend
|
connection.settings_dict['NAME'] = test_db_name
|
||||||
# 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)
|
|
||||||
|
|
||||||
for alias, mirror_alias in mirrored_aliases.items():
|
for alias, mirror_alias in mirrored_aliases.items():
|
||||||
mirrors.append((alias, connections[alias].settings_dict['NAME']))
|
mirrors.append((alias, connections[alias].settings_dict['NAME']))
|
||||||
|
|
|
@ -110,6 +110,25 @@ class DependencyOrderingTests(unittest.TestCase):
|
||||||
|
|
||||||
self.assertRaises(ImproperlyConfigured, simple.dependency_ordered, raw, dependencies=dependencies)
|
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):
|
class MockTestRunner(object):
|
||||||
invoked = False
|
invoked = False
|
||||||
|
|
Loading…
Reference in New Issue