Skip to content

Commit 03a442c

Browse files
committed
Fixed django#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
1 parent 530ab32 commit 03a442c

File tree

2 files changed

+51
-34
lines changed

2 files changed

+51
-34
lines changed

django/test/simple.py

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -193,31 +193,35 @@ def reorder_suite(suite, classes):
193193

194194

195195
def dependency_ordered(test_databases, dependencies):
196-
"""Reorder test_databases into an order that honors the dependencies
196+
"""
197+
Reorder test_databases into an order that honors the dependencies
197198
described in TEST_DEPENDENCIES.
198199
"""
199200
ordered_test_databases = []
200201
resolved_databases = set()
202+
203+
# Maps db signature to dependencies of all it's aliases
204+
dependencies_map = {}
205+
206+
# sanity check - no DB can depend on it's own alias
207+
for sig, (_, aliases) in test_databases:
208+
all_deps = set()
209+
for alias in aliases:
210+
all_deps.update(dependencies.get(alias, []))
211+
if not all_deps.isdisjoint(aliases):
212+
raise ImproperlyConfigured(
213+
"Circular dependency: databases %r depend on each other, "
214+
"but are aliases." % aliases)
215+
dependencies_map[sig] = all_deps
216+
201217
while test_databases:
202218
changed = False
203219
deferred = []
204220

205-
while test_databases:
206-
signature, (db_name, aliases) = test_databases.pop()
207-
dependencies_satisfied = True
208-
for alias in aliases:
209-
if alias in dependencies:
210-
if all(a in resolved_databases
211-
for a in dependencies[alias]):
212-
# all dependencies for this alias are satisfied
213-
dependencies.pop(alias)
214-
resolved_databases.add(alias)
215-
else:
216-
dependencies_satisfied = False
217-
else:
218-
resolved_databases.add(alias)
219-
220-
if dependencies_satisfied:
221+
# Try to find a DB that has all it's dependencies met
222+
for signature, (db_name, aliases) in test_databases:
223+
if dependencies_map[signature].issubset(resolved_databases):
224+
resolved_databases.update(aliases)
221225
ordered_test_databases.append((signature, (db_name, aliases)))
222226
changed = True
223227
else:
@@ -282,9 +286,9 @@ def setup_databases(self, **kwargs):
282286
# we only need to create the test database once.
283287
item = test_databases.setdefault(
284288
connection.creation.test_db_signature(),
285-
(connection.settings_dict['NAME'], [])
289+
(connection.settings_dict['NAME'], set())
286290
)
287-
item[1].append(alias)
291+
item[1].add(alias)
288292

289293
if 'TEST_DEPENDENCIES' in connection.settings_dict:
290294
dependencies[alias] = (
@@ -297,26 +301,20 @@ def setup_databases(self, **kwargs):
297301
# Second pass -- actually create the databases.
298302
old_names = []
299303
mirrors = []
304+
300305
for signature, (db_name, aliases) in dependency_ordered(
301306
test_databases.items(), dependencies):
307+
test_db_name = None
302308
# Actually create the database for the first connection
303-
connection = connections[aliases[0]]
304-
old_names.append((connection, db_name, True))
305-
test_db_name = connection.creation.create_test_db(
306-
self.verbosity, autoclobber=not self.interactive)
307-
for alias in aliases[1:]:
309+
310+
for alias in aliases:
308311
connection = connections[alias]
309-
if db_name:
310-
old_names.append((connection, db_name, False))
311-
connection.settings_dict['NAME'] = test_db_name
312+
old_names.append((connection, db_name, True))
313+
if test_db_name is None:
314+
test_db_name = connection.creation.create_test_db(
315+
self.verbosity, autoclobber=not self.interactive)
312316
else:
313-
# If settings_dict['NAME'] isn't defined, we have a backend
314-
# where the name isn't important -- e.g., SQLite, which
315-
# uses :memory:. Force create the database instead of
316-
# assuming it's a duplicate.
317-
old_names.append((connection, db_name, True))
318-
connection.creation.create_test_db(
319-
self.verbosity, autoclobber=not self.interactive)
317+
connection.settings_dict['NAME'] = test_db_name
320318

321319
for alias, mirror_alias in mirrored_aliases.items():
322320
mirrors.append((alias, connections[alias].settings_dict['NAME']))

tests/regressiontests/test_runner/tests.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,25 @@ def test_circular_dependencies(self):
110110

111111
self.assertRaises(ImproperlyConfigured, simple.dependency_ordered, raw, dependencies=dependencies)
112112

113+
def test_own_alias_dependency(self):
114+
raw = [
115+
('s1', ('s1_db', ['alpha', 'bravo']))
116+
]
117+
dependencies = {
118+
'alpha': ['bravo']
119+
}
120+
121+
with self.assertRaises(ImproperlyConfigured):
122+
simple.dependency_ordered(raw, dependencies=dependencies)
123+
124+
# reordering aliases shouldn't matter
125+
raw = [
126+
('s1', ('s1_db', ['bravo', 'alpha']))
127+
]
128+
129+
with self.assertRaises(ImproperlyConfigured):
130+
simple.dependency_ordered(raw, dependencies=dependencies)
131+
113132

114133
class MockTestRunner(object):
115134
invoked = False

0 commit comments

Comments
 (0)