root / env / lib / python2.7 / site-packages / south / tests / logic.py @ d1a4905f
History | View | Annotate | Download (32.7 KB)
1 |
from south.tests import unittest |
---|---|
2 |
|
3 |
import datetime |
4 |
import sys |
5 |
|
6 |
from south import exceptions |
7 |
from south.migration import migrate_app |
8 |
from south.migration.base import all_migrations, Migrations |
9 |
from south.creator.changes import ManualChanges |
10 |
from south.migration.utils import depends, flatten, get_app_label |
11 |
from south.models import MigrationHistory |
12 |
from south.tests import Monkeypatcher |
13 |
from south.db import db |
14 |
|
15 |
|
16 |
|
17 |
class TestBrokenMigration(Monkeypatcher): |
18 |
installed_apps = ["fakeapp", "otherfakeapp", "brokenapp"] |
19 |
|
20 |
def test_broken_dependencies(self): |
21 |
self.assertRaises(
|
22 |
exceptions.DependsOnUnmigratedApplication, |
23 |
Migrations.calculate_dependencies, |
24 |
force=True,
|
25 |
) |
26 |
#depends_on_unknown = self.brokenapp['0002_depends_on_unknown']
|
27 |
#self.assertRaises(exceptions.DependsOnUnknownMigration,
|
28 |
# depends_on_unknown.dependencies)
|
29 |
#depends_on_higher = self.brokenapp['0003_depends_on_higher']
|
30 |
#self.assertRaises(exceptions.DependsOnHigherMigration,
|
31 |
# depends_on_higher.dependencies)
|
32 |
|
33 |
|
34 |
class TestMigration(Monkeypatcher): |
35 |
installed_apps = ["fakeapp", "otherfakeapp"] |
36 |
|
37 |
def setUp(self): |
38 |
super(TestMigration, self).setUp() |
39 |
self.fakeapp = Migrations('fakeapp') |
40 |
self.otherfakeapp = Migrations('otherfakeapp') |
41 |
Migrations.calculate_dependencies(force=True)
|
42 |
|
43 |
def test_str(self): |
44 |
migrations = [str(m) for m in self.fakeapp] |
45 |
self.assertEqual(['fakeapp:0001_spam', |
46 |
'fakeapp:0002_eggs',
|
47 |
'fakeapp:0003_alter_spam'],
|
48 |
migrations) |
49 |
|
50 |
def test_repr(self): |
51 |
migrations = [repr(m) for m in self.fakeapp] |
52 |
self.assertEqual(['<Migration: fakeapp:0001_spam>', |
53 |
'<Migration: fakeapp:0002_eggs>',
|
54 |
'<Migration: fakeapp:0003_alter_spam>'],
|
55 |
migrations) |
56 |
|
57 |
def test_app_label(self): |
58 |
self.assertEqual(['fakeapp', 'fakeapp', 'fakeapp'], |
59 |
[m.app_label() for m in self.fakeapp]) |
60 |
|
61 |
def test_name(self): |
62 |
self.assertEqual(['0001_spam', '0002_eggs', '0003_alter_spam'], |
63 |
[m.name() for m in self.fakeapp]) |
64 |
|
65 |
def test_full_name(self): |
66 |
self.assertEqual(['fakeapp.migrations.0001_spam', |
67 |
'fakeapp.migrations.0002_eggs',
|
68 |
'fakeapp.migrations.0003_alter_spam'],
|
69 |
[m.full_name() for m in self.fakeapp]) |
70 |
|
71 |
def test_migration(self): |
72 |
# Can't use vanilla import, modules beginning with numbers aren't in grammar
|
73 |
M1 = __import__("fakeapp.migrations.0001_spam", {}, {}, ['Migration']).Migration |
74 |
M2 = __import__("fakeapp.migrations.0002_eggs", {}, {}, ['Migration']).Migration |
75 |
M3 = __import__("fakeapp.migrations.0003_alter_spam", {}, {}, ['Migration']).Migration |
76 |
self.assertEqual([M1, M2, M3],
|
77 |
[m.migration().Migration for m in self.fakeapp]) |
78 |
self.assertRaises(exceptions.UnknownMigration,
|
79 |
self.fakeapp['9999_unknown'].migration) |
80 |
|
81 |
def test_previous(self): |
82 |
self.assertEqual([None, |
83 |
self.fakeapp['0001_spam'], |
84 |
self.fakeapp['0002_eggs']], |
85 |
[m.previous() for m in self.fakeapp]) |
86 |
|
87 |
def test_dependencies(self): |
88 |
"Test that the dependency detection works."
|
89 |
self.assertEqual([
|
90 |
set([]),
|
91 |
set([self.fakeapp['0001_spam']]), |
92 |
set([self.fakeapp['0002_eggs']]) |
93 |
], |
94 |
[m.dependencies for m in self.fakeapp], |
95 |
) |
96 |
self.assertEqual([
|
97 |
set([self.fakeapp['0001_spam']]), |
98 |
set([self.otherfakeapp['0001_first']]), |
99 |
set([
|
100 |
self.otherfakeapp['0002_second'], |
101 |
self.fakeapp['0003_alter_spam'], |
102 |
]) |
103 |
], |
104 |
[m.dependencies for m in self.otherfakeapp], |
105 |
) |
106 |
|
107 |
def test_forwards_plan(self): |
108 |
self.assertEqual([
|
109 |
[self.fakeapp['0001_spam']], |
110 |
[ |
111 |
self.fakeapp['0001_spam'], |
112 |
self.fakeapp['0002_eggs'] |
113 |
], |
114 |
[ |
115 |
self.fakeapp['0001_spam'], |
116 |
self.fakeapp['0002_eggs'], |
117 |
self.fakeapp['0003_alter_spam'], |
118 |
] |
119 |
], |
120 |
[m.forwards_plan() for m in self.fakeapp], |
121 |
) |
122 |
self.assertEqual([
|
123 |
[ |
124 |
self.fakeapp['0001_spam'], |
125 |
self.otherfakeapp['0001_first'] |
126 |
], |
127 |
[ |
128 |
self.fakeapp['0001_spam'], |
129 |
self.otherfakeapp['0001_first'], |
130 |
self.otherfakeapp['0002_second'] |
131 |
], |
132 |
[ |
133 |
self.fakeapp['0001_spam'], |
134 |
self.otherfakeapp['0001_first'], |
135 |
self.otherfakeapp['0002_second'], |
136 |
self.fakeapp['0002_eggs'], |
137 |
self.fakeapp['0003_alter_spam'], |
138 |
self.otherfakeapp['0003_third'], |
139 |
] |
140 |
], |
141 |
[m.forwards_plan() for m in self.otherfakeapp], |
142 |
) |
143 |
|
144 |
def test_is_before(self): |
145 |
F1 = self.fakeapp['0001_spam'] |
146 |
F2 = self.fakeapp['0002_eggs'] |
147 |
F3 = self.fakeapp['0003_alter_spam'] |
148 |
O1 = self.otherfakeapp['0001_first'] |
149 |
O2 = self.otherfakeapp['0002_second'] |
150 |
O3 = self.otherfakeapp['0003_third'] |
151 |
self.assertTrue(F1.is_before(F2))
|
152 |
self.assertTrue(F1.is_before(F3))
|
153 |
self.assertTrue(F2.is_before(F3))
|
154 |
self.assertEqual(O3.is_before(O1), False) |
155 |
self.assertEqual(O3.is_before(O2), False) |
156 |
self.assertEqual(O2.is_before(O2), False) |
157 |
self.assertEqual(O2.is_before(O1), False) |
158 |
self.assertEqual(F2.is_before(O1), None) |
159 |
self.assertEqual(F2.is_before(O2), None) |
160 |
self.assertEqual(F2.is_before(O3), None) |
161 |
|
162 |
|
163 |
class TestMigrationDependencies(Monkeypatcher): |
164 |
installed_apps = ['deps_a', 'deps_b', 'deps_c'] |
165 |
|
166 |
def setUp(self): |
167 |
super(TestMigrationDependencies, self).setUp() |
168 |
self.deps_a = Migrations('deps_a') |
169 |
self.deps_b = Migrations('deps_b') |
170 |
self.deps_c = Migrations('deps_c') |
171 |
Migrations.calculate_dependencies(force=True)
|
172 |
|
173 |
def test_dependencies(self): |
174 |
self.assertEqual(
|
175 |
[ |
176 |
set([]),
|
177 |
set([self.deps_a['0001_a']]), |
178 |
set([self.deps_a['0002_a']]), |
179 |
set([
|
180 |
self.deps_a['0003_a'], |
181 |
self.deps_b['0003_b'], |
182 |
]), |
183 |
set([self.deps_a['0004_a']]), |
184 |
], |
185 |
[m.dependencies for m in self.deps_a], |
186 |
) |
187 |
self.assertEqual(
|
188 |
[ |
189 |
set([]),
|
190 |
set([
|
191 |
self.deps_b['0001_b'], |
192 |
self.deps_a['0002_a'] |
193 |
]), |
194 |
set([
|
195 |
self.deps_b['0002_b'], |
196 |
self.deps_a['0003_a'] |
197 |
]), |
198 |
set([self.deps_b['0003_b']]), |
199 |
set([self.deps_b['0004_b']]), |
200 |
], |
201 |
[m.dependencies for m in self.deps_b], |
202 |
) |
203 |
self.assertEqual(
|
204 |
[ |
205 |
set([]),
|
206 |
set([self.deps_c['0001_c']]), |
207 |
set([self.deps_c['0002_c']]), |
208 |
set([self.deps_c['0003_c']]), |
209 |
set([
|
210 |
self.deps_c['0004_c'], |
211 |
self.deps_a['0002_a'] |
212 |
]), |
213 |
], |
214 |
[m.dependencies for m in self.deps_c], |
215 |
) |
216 |
|
217 |
def test_dependents(self): |
218 |
self.assertEqual([set([self.deps_a['0002_a']]), |
219 |
set([self.deps_c['0005_c'], |
220 |
self.deps_b['0002_b'], |
221 |
self.deps_a['0003_a']]), |
222 |
set([self.deps_b['0003_b'], |
223 |
self.deps_a['0004_a']]), |
224 |
set([self.deps_a['0005_a']]), |
225 |
set([])],
|
226 |
[m.dependents for m in self.deps_a]) |
227 |
self.assertEqual([set([self.deps_b['0002_b']]), |
228 |
set([self.deps_b['0003_b']]), |
229 |
set([self.deps_b['0004_b'], |
230 |
self.deps_a['0004_a']]), |
231 |
set([self.deps_b['0005_b']]), |
232 |
set([])],
|
233 |
[m.dependents for m in self.deps_b]) |
234 |
self.assertEqual([set([self.deps_c['0002_c']]), |
235 |
set([self.deps_c['0003_c']]), |
236 |
set([self.deps_c['0004_c']]), |
237 |
set([self.deps_c['0005_c']]), |
238 |
set([])],
|
239 |
[m.dependents for m in self.deps_c]) |
240 |
|
241 |
def test_forwards_plan(self): |
242 |
self.assertEqual([[self.deps_a['0001_a']], |
243 |
[self.deps_a['0001_a'], |
244 |
self.deps_a['0002_a']], |
245 |
[self.deps_a['0001_a'], |
246 |
self.deps_a['0002_a'], |
247 |
self.deps_a['0003_a']], |
248 |
[self.deps_b['0001_b'], |
249 |
self.deps_a['0001_a'], |
250 |
self.deps_a['0002_a'], |
251 |
self.deps_b['0002_b'], |
252 |
self.deps_a['0003_a'], |
253 |
self.deps_b['0003_b'], |
254 |
self.deps_a['0004_a']], |
255 |
[self.deps_b['0001_b'], |
256 |
self.deps_a['0001_a'], |
257 |
self.deps_a['0002_a'], |
258 |
self.deps_b['0002_b'], |
259 |
self.deps_a['0003_a'], |
260 |
self.deps_b['0003_b'], |
261 |
self.deps_a['0004_a'], |
262 |
self.deps_a['0005_a']]], |
263 |
[m.forwards_plan() for m in self.deps_a]) |
264 |
self.assertEqual([[self.deps_b['0001_b']], |
265 |
[self.deps_b['0001_b'], |
266 |
self.deps_a['0001_a'], |
267 |
self.deps_a['0002_a'], |
268 |
self.deps_b['0002_b']], |
269 |
[self.deps_b['0001_b'], |
270 |
self.deps_a['0001_a'], |
271 |
self.deps_a['0002_a'], |
272 |
self.deps_b['0002_b'], |
273 |
self.deps_a['0003_a'], |
274 |
self.deps_b['0003_b']], |
275 |
[self.deps_b['0001_b'], |
276 |
self.deps_a['0001_a'], |
277 |
self.deps_a['0002_a'], |
278 |
self.deps_b['0002_b'], |
279 |
self.deps_a['0003_a'], |
280 |
self.deps_b['0003_b'], |
281 |
self.deps_b['0004_b']], |
282 |
[self.deps_b['0001_b'], |
283 |
self.deps_a['0001_a'], |
284 |
self.deps_a['0002_a'], |
285 |
self.deps_b['0002_b'], |
286 |
self.deps_a['0003_a'], |
287 |
self.deps_b['0003_b'], |
288 |
self.deps_b['0004_b'], |
289 |
self.deps_b['0005_b']]], |
290 |
[m.forwards_plan() for m in self.deps_b]) |
291 |
self.assertEqual([[self.deps_c['0001_c']], |
292 |
[self.deps_c['0001_c'], |
293 |
self.deps_c['0002_c']], |
294 |
[self.deps_c['0001_c'], |
295 |
self.deps_c['0002_c'], |
296 |
self.deps_c['0003_c']], |
297 |
[self.deps_c['0001_c'], |
298 |
self.deps_c['0002_c'], |
299 |
self.deps_c['0003_c'], |
300 |
self.deps_c['0004_c']], |
301 |
[self.deps_c['0001_c'], |
302 |
self.deps_c['0002_c'], |
303 |
self.deps_c['0003_c'], |
304 |
self.deps_c['0004_c'], |
305 |
self.deps_a['0001_a'], |
306 |
self.deps_a['0002_a'], |
307 |
self.deps_c['0005_c']]], |
308 |
[m.forwards_plan() for m in self.deps_c]) |
309 |
|
310 |
def test_backwards_plan(self): |
311 |
self.assertEqual([
|
312 |
[ |
313 |
self.deps_c['0005_c'], |
314 |
self.deps_b['0005_b'], |
315 |
self.deps_b['0004_b'], |
316 |
self.deps_a['0005_a'], |
317 |
self.deps_a['0004_a'], |
318 |
self.deps_b['0003_b'], |
319 |
self.deps_b['0002_b'], |
320 |
self.deps_a['0003_a'], |
321 |
self.deps_a['0002_a'], |
322 |
self.deps_a['0001_a'], |
323 |
], |
324 |
[ |
325 |
self.deps_c['0005_c'], |
326 |
self.deps_b['0005_b'], |
327 |
self.deps_b['0004_b'], |
328 |
self.deps_a['0005_a'], |
329 |
self.deps_a['0004_a'], |
330 |
self.deps_b['0003_b'], |
331 |
self.deps_b['0002_b'], |
332 |
self.deps_a['0003_a'], |
333 |
self.deps_a['0002_a'], |
334 |
], |
335 |
[ |
336 |
self.deps_b['0005_b'], |
337 |
self.deps_b['0004_b'], |
338 |
self.deps_a['0005_a'], |
339 |
self.deps_a['0004_a'], |
340 |
self.deps_b['0003_b'], |
341 |
self.deps_a['0003_a'], |
342 |
], |
343 |
[ |
344 |
self.deps_a['0005_a'], |
345 |
self.deps_a['0004_a'], |
346 |
], |
347 |
[ |
348 |
self.deps_a['0005_a'], |
349 |
] |
350 |
], [m.backwards_plan() for m in self.deps_a]) |
351 |
self.assertEqual([
|
352 |
[ |
353 |
self.deps_b['0005_b'], |
354 |
self.deps_b['0004_b'], |
355 |
self.deps_a['0005_a'], |
356 |
self.deps_a['0004_a'], |
357 |
self.deps_b['0003_b'], |
358 |
self.deps_b['0002_b'], |
359 |
self.deps_b['0001_b'], |
360 |
], |
361 |
[ |
362 |
self.deps_b['0005_b'], |
363 |
self.deps_b['0004_b'], |
364 |
self.deps_a['0005_a'], |
365 |
self.deps_a['0004_a'], |
366 |
self.deps_b['0003_b'], |
367 |
self.deps_b['0002_b'], |
368 |
], |
369 |
[ |
370 |
self.deps_b['0005_b'], |
371 |
self.deps_b['0004_b'], |
372 |
self.deps_a['0005_a'], |
373 |
self.deps_a['0004_a'], |
374 |
self.deps_b['0003_b'], |
375 |
], |
376 |
[ |
377 |
self.deps_b['0005_b'], |
378 |
self.deps_b['0004_b'], |
379 |
], |
380 |
[ |
381 |
self.deps_b['0005_b'], |
382 |
], |
383 |
], [m.backwards_plan() for m in self.deps_b]) |
384 |
self.assertEqual([
|
385 |
[ |
386 |
self.deps_c['0005_c'], |
387 |
self.deps_c['0004_c'], |
388 |
self.deps_c['0003_c'], |
389 |
self.deps_c['0002_c'], |
390 |
self.deps_c['0001_c'], |
391 |
], |
392 |
[ |
393 |
self.deps_c['0005_c'], |
394 |
self.deps_c['0004_c'], |
395 |
self.deps_c['0003_c'], |
396 |
self.deps_c['0002_c'], |
397 |
], |
398 |
[ |
399 |
self.deps_c['0005_c'], |
400 |
self.deps_c['0004_c'], |
401 |
self.deps_c['0003_c'], |
402 |
], |
403 |
[ |
404 |
self.deps_c['0005_c'], |
405 |
self.deps_c['0004_c'], |
406 |
], |
407 |
[self.deps_c['0005_c']] |
408 |
], [m.backwards_plan() for m in self.deps_c]) |
409 |
|
410 |
|
411 |
class TestCircularDependencies(Monkeypatcher): |
412 |
installed_apps = ["circular_a", "circular_b"] |
413 |
|
414 |
def test_plans(self): |
415 |
Migrations.calculate_dependencies(force=True)
|
416 |
circular_a = Migrations('circular_a')
|
417 |
circular_b = Migrations('circular_b')
|
418 |
self.assertRaises(
|
419 |
exceptions.CircularDependency, |
420 |
circular_a[-1].forwards_plan,
|
421 |
) |
422 |
self.assertRaises(
|
423 |
exceptions.CircularDependency, |
424 |
circular_b[-1].forwards_plan,
|
425 |
) |
426 |
self.assertRaises(
|
427 |
exceptions.CircularDependency, |
428 |
circular_a[-1].backwards_plan,
|
429 |
) |
430 |
self.assertRaises(
|
431 |
exceptions.CircularDependency, |
432 |
circular_b[-1].backwards_plan,
|
433 |
) |
434 |
|
435 |
|
436 |
class TestMigrations(Monkeypatcher): |
437 |
installed_apps = ["fakeapp", "otherfakeapp"] |
438 |
|
439 |
def test_all(self): |
440 |
|
441 |
M1 = Migrations(__import__("fakeapp", {}, {}, [''])) |
442 |
M2 = Migrations(__import__("otherfakeapp", {}, {}, [''])) |
443 |
|
444 |
self.assertEqual(
|
445 |
[M1, M2], |
446 |
list(all_migrations()),
|
447 |
) |
448 |
|
449 |
def test(self): |
450 |
|
451 |
M1 = Migrations(__import__("fakeapp", {}, {}, [''])) |
452 |
|
453 |
self.assertEqual(M1, Migrations("fakeapp")) |
454 |
self.assertEqual(M1, Migrations(self.create_fake_app("fakeapp"))) |
455 |
|
456 |
def test_application(self): |
457 |
fakeapp = Migrations("fakeapp")
|
458 |
application = __import__("fakeapp", {}, {}, ['']) |
459 |
self.assertEqual(application, fakeapp.application)
|
460 |
|
461 |
def test_migration(self): |
462 |
# Can't use vanilla import, modules beginning with numbers aren't in grammar
|
463 |
M1 = __import__("fakeapp.migrations.0001_spam", {}, {}, ['Migration']).Migration |
464 |
M2 = __import__("fakeapp.migrations.0002_eggs", {}, {}, ['Migration']).Migration |
465 |
migration = Migrations('fakeapp')
|
466 |
self.assertEqual(M1, migration['0001_spam'].migration().Migration) |
467 |
self.assertEqual(M2, migration['0002_eggs'].migration().Migration) |
468 |
self.assertRaises(exceptions.UnknownMigration,
|
469 |
migration['0001_jam'].migration)
|
470 |
|
471 |
def test_guess_migration(self): |
472 |
# Can't use vanilla import, modules beginning with numbers aren't in grammar
|
473 |
M1 = __import__("fakeapp.migrations.0001_spam", {}, {}, ['Migration']).Migration |
474 |
migration = Migrations('fakeapp')
|
475 |
self.assertEqual(M1, migration.guess_migration("0001_spam").migration().Migration) |
476 |
self.assertEqual(M1, migration.guess_migration("0001_spa").migration().Migration) |
477 |
self.assertEqual(M1, migration.guess_migration("0001_sp").migration().Migration) |
478 |
self.assertEqual(M1, migration.guess_migration("0001_s").migration().Migration) |
479 |
self.assertEqual(M1, migration.guess_migration("0001_").migration().Migration) |
480 |
self.assertEqual(M1, migration.guess_migration("0001").migration().Migration) |
481 |
self.assertRaises(exceptions.UnknownMigration,
|
482 |
migration.guess_migration, "0001-spam")
|
483 |
self.assertRaises(exceptions.MultiplePrefixMatches,
|
484 |
migration.guess_migration, "000")
|
485 |
self.assertRaises(exceptions.MultiplePrefixMatches,
|
486 |
migration.guess_migration, "")
|
487 |
self.assertRaises(exceptions.UnknownMigration,
|
488 |
migration.guess_migration, "0001_spams")
|
489 |
self.assertRaises(exceptions.UnknownMigration,
|
490 |
migration.guess_migration, "0001_jam")
|
491 |
|
492 |
def test_app_label(self): |
493 |
names = ['fakeapp', 'otherfakeapp'] |
494 |
self.assertEqual(names,
|
495 |
[Migrations(n).app_label() for n in names]) |
496 |
|
497 |
def test_full_name(self): |
498 |
names = ['fakeapp', 'otherfakeapp'] |
499 |
self.assertEqual([n + '.migrations' for n in names], |
500 |
[Migrations(n).full_name() for n in names]) |
501 |
|
502 |
|
503 |
class TestMigrationLogic(Monkeypatcher): |
504 |
|
505 |
"""
|
506 |
Tests if the various logic functions in migration actually work.
|
507 |
"""
|
508 |
|
509 |
installed_apps = ["fakeapp", "otherfakeapp"] |
510 |
|
511 |
def assertListEqual(self, list1, list2, msg=None): |
512 |
list1 = list(list1)
|
513 |
list2 = list(list2)
|
514 |
list1.sort() |
515 |
list2.sort() |
516 |
return self.assert_(list1 == list2, "%s is not equal to %s" % (list1, list2)) |
517 |
|
518 |
def test_find_ghost_migrations(self): |
519 |
pass
|
520 |
|
521 |
def test_apply_migrations(self): |
522 |
MigrationHistory.objects.all().delete() |
523 |
migrations = Migrations("fakeapp")
|
524 |
|
525 |
# We should start with no migrations
|
526 |
self.assertEqual(list(MigrationHistory.objects.all()), []) |
527 |
|
528 |
# Apply them normally
|
529 |
migrate_app(migrations, target_name=None, fake=False, |
530 |
load_initial_data=True)
|
531 |
|
532 |
# We should finish with all migrations
|
533 |
self.assertListEqual(
|
534 |
((u"fakeapp", u"0001_spam"), |
535 |
(u"fakeapp", u"0002_eggs"), |
536 |
(u"fakeapp", u"0003_alter_spam"),), |
537 |
MigrationHistory.objects.values_list("app_name", "migration"), |
538 |
) |
539 |
|
540 |
# Now roll them backwards
|
541 |
migrate_app(migrations, target_name="zero", fake=False) |
542 |
|
543 |
# Finish with none
|
544 |
self.assertEqual(list(MigrationHistory.objects.all()), []) |
545 |
|
546 |
|
547 |
def test_migration_merge_forwards(self): |
548 |
MigrationHistory.objects.all().delete() |
549 |
migrations = Migrations("fakeapp")
|
550 |
|
551 |
# We should start with no migrations
|
552 |
self.assertEqual(list(MigrationHistory.objects.all()), []) |
553 |
|
554 |
# Insert one in the wrong order
|
555 |
MigrationHistory.objects.create(app_name = "fakeapp",
|
556 |
migration = "0002_eggs",
|
557 |
applied = datetime.datetime.now()) |
558 |
|
559 |
# Did it go in?
|
560 |
self.assertListEqual(
|
561 |
((u"fakeapp", u"0002_eggs"),), |
562 |
MigrationHistory.objects.values_list("app_name", "migration"), |
563 |
) |
564 |
|
565 |
# Apply them normally
|
566 |
self.assertRaises(exceptions.InconsistentMigrationHistory,
|
567 |
migrate_app, |
568 |
migrations, target_name=None, fake=False) |
569 |
self.assertRaises(exceptions.InconsistentMigrationHistory,
|
570 |
migrate_app, |
571 |
migrations, target_name='zero', fake=False) |
572 |
try:
|
573 |
migrate_app(migrations, target_name=None, fake=False) |
574 |
except exceptions.InconsistentMigrationHistory, e:
|
575 |
self.assertEqual(
|
576 |
[ |
577 |
( |
578 |
migrations['0002_eggs'],
|
579 |
migrations['0001_spam'],
|
580 |
) |
581 |
], |
582 |
e.problems, |
583 |
) |
584 |
try:
|
585 |
migrate_app(migrations, target_name="zero", fake=False) |
586 |
except exceptions.InconsistentMigrationHistory, e:
|
587 |
self.assertEqual(
|
588 |
[ |
589 |
( |
590 |
migrations['0002_eggs'],
|
591 |
migrations['0001_spam'],
|
592 |
) |
593 |
], |
594 |
e.problems, |
595 |
) |
596 |
|
597 |
# Nothing should have changed (no merge mode!)
|
598 |
self.assertListEqual(
|
599 |
((u"fakeapp", u"0002_eggs"),), |
600 |
MigrationHistory.objects.values_list("app_name", "migration"), |
601 |
) |
602 |
|
603 |
# Apply with merge
|
604 |
migrate_app(migrations, target_name=None, merge=True, fake=False) |
605 |
|
606 |
# We should finish with all migrations
|
607 |
self.assertListEqual(
|
608 |
((u"fakeapp", u"0001_spam"), |
609 |
(u"fakeapp", u"0002_eggs"), |
610 |
(u"fakeapp", u"0003_alter_spam"),), |
611 |
MigrationHistory.objects.values_list("app_name", "migration"), |
612 |
) |
613 |
|
614 |
# Now roll them backwards
|
615 |
migrate_app(migrations, target_name="0002", fake=False) |
616 |
migrate_app(migrations, target_name="0001", fake=True) |
617 |
migrate_app(migrations, target_name="zero", fake=False) |
618 |
|
619 |
# Finish with none
|
620 |
self.assertEqual(list(MigrationHistory.objects.all()), []) |
621 |
|
622 |
def test_alter_column_null(self): |
623 |
|
624 |
def null_ok(eat_exception=True): |
625 |
from django.db import connection, transaction |
626 |
# the DBAPI introspection module fails on postgres NULLs.
|
627 |
cursor = connection.cursor() |
628 |
|
629 |
# SQLite has weird now()
|
630 |
if db.backend_name == "sqlite3": |
631 |
now_func = "DATETIME('NOW')"
|
632 |
# So does SQLServer... should we be using a backend attribute?
|
633 |
elif db.backend_name == "pyodbc": |
634 |
now_func = "GETDATE()"
|
635 |
elif db.backend_name == "oracle": |
636 |
now_func = "SYSDATE"
|
637 |
else:
|
638 |
now_func = "NOW()"
|
639 |
|
640 |
try:
|
641 |
if db.backend_name == "pyodbc": |
642 |
cursor.execute("SET IDENTITY_INSERT southtest_spam ON;")
|
643 |
cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, NULL, %s, 'whatever');" % now_func)
|
644 |
except:
|
645 |
if eat_exception:
|
646 |
transaction.rollback() |
647 |
return False |
648 |
else:
|
649 |
raise
|
650 |
else:
|
651 |
cursor.execute("DELETE FROM southtest_spam")
|
652 |
transaction.commit() |
653 |
return True |
654 |
|
655 |
MigrationHistory.objects.all().delete() |
656 |
migrations = Migrations("fakeapp")
|
657 |
|
658 |
# by default name is NOT NULL
|
659 |
migrate_app(migrations, target_name="0002", fake=False) |
660 |
self.failIf(null_ok())
|
661 |
self.assertListEqual(
|
662 |
((u"fakeapp", u"0001_spam"), |
663 |
(u"fakeapp", u"0002_eggs"),), |
664 |
MigrationHistory.objects.values_list("app_name", "migration"), |
665 |
) |
666 |
|
667 |
# after 0003, it should be NULL
|
668 |
migrate_app(migrations, target_name="0003", fake=False) |
669 |
self.assert_(null_ok(False)) |
670 |
self.assertListEqual(
|
671 |
((u"fakeapp", u"0001_spam"), |
672 |
(u"fakeapp", u"0002_eggs"), |
673 |
(u"fakeapp", u"0003_alter_spam"),), |
674 |
MigrationHistory.objects.values_list("app_name", "migration"), |
675 |
) |
676 |
|
677 |
# make sure it is NOT NULL again
|
678 |
migrate_app(migrations, target_name="0002", fake=False) |
679 |
self.failIf(null_ok(), 'weight not null after migration') |
680 |
self.assertListEqual(
|
681 |
((u"fakeapp", u"0001_spam"), |
682 |
(u"fakeapp", u"0002_eggs"),), |
683 |
MigrationHistory.objects.values_list("app_name", "migration"), |
684 |
) |
685 |
|
686 |
# finish with no migrations, otherwise other tests fail...
|
687 |
migrate_app(migrations, target_name="zero", fake=False) |
688 |
self.assertEqual(list(MigrationHistory.objects.all()), []) |
689 |
|
690 |
def test_dependencies(self): |
691 |
|
692 |
fakeapp = Migrations("fakeapp")
|
693 |
otherfakeapp = Migrations("otherfakeapp")
|
694 |
|
695 |
# Test a simple path
|
696 |
self.assertEqual([fakeapp['0001_spam'], |
697 |
fakeapp['0002_eggs'],
|
698 |
fakeapp['0003_alter_spam']],
|
699 |
fakeapp['0003_alter_spam'].forwards_plan())
|
700 |
|
701 |
# And a complex one.
|
702 |
self.assertEqual(
|
703 |
[ |
704 |
fakeapp['0001_spam'],
|
705 |
otherfakeapp['0001_first'],
|
706 |
otherfakeapp['0002_second'],
|
707 |
fakeapp['0002_eggs'],
|
708 |
fakeapp['0003_alter_spam'],
|
709 |
otherfakeapp['0003_third']
|
710 |
], |
711 |
otherfakeapp['0003_third'].forwards_plan(),
|
712 |
) |
713 |
|
714 |
|
715 |
class TestMigrationUtils(Monkeypatcher): |
716 |
installed_apps = ["fakeapp", "otherfakeapp"] |
717 |
|
718 |
def test_get_app_label(self): |
719 |
self.assertEqual(
|
720 |
"southtest",
|
721 |
get_app_label(self.create_fake_app("southtest.models")), |
722 |
) |
723 |
self.assertEqual(
|
724 |
"baz",
|
725 |
get_app_label(self.create_fake_app("foo.bar.baz.models")), |
726 |
) |
727 |
|
728 |
class TestUtils(unittest.TestCase): |
729 |
|
730 |
def test_flatten(self): |
731 |
self.assertEqual([], list(flatten(iter([])))) |
732 |
self.assertEqual([], list(flatten(iter([iter([]), ])))) |
733 |
self.assertEqual([1], list(flatten(iter([1])))) |
734 |
self.assertEqual([1, 2], list(flatten(iter([1, 2])))) |
735 |
self.assertEqual([1, 2], list(flatten(iter([iter([1]), 2])))) |
736 |
self.assertEqual([1, 2], list(flatten(iter([iter([1, 2])])))) |
737 |
self.assertEqual([1, 2, 3], list(flatten(iter([iter([1, 2]), 3])))) |
738 |
self.assertEqual([1, 2, 3], |
739 |
list(flatten(iter([iter([1]), iter([2]), 3])))) |
740 |
self.assertEqual([1, 2, 3], |
741 |
list(flatten([[1], [2], 3]))) |
742 |
|
743 |
def test_depends(self): |
744 |
graph = {'A1': []}
|
745 |
self.assertEqual(['A1'], |
746 |
depends('A1', lambda n: graph[n])) |
747 |
graph = {'A1': [],
|
748 |
'A2': ['A1'], |
749 |
'A3': ['A2']} |
750 |
self.assertEqual(['A1', 'A2', 'A3'], |
751 |
depends('A3', lambda n: graph[n])) |
752 |
graph = {'A1': [],
|
753 |
'A2': ['A1'], |
754 |
'A3': ['A2', 'A1']} |
755 |
self.assertEqual(['A1', 'A2', 'A3'], |
756 |
depends('A3', lambda n: graph[n])) |
757 |
graph = {'A1': [],
|
758 |
'A2': ['A1'], |
759 |
'A3': ['A2', 'A1', 'B1'], |
760 |
'B1': []}
|
761 |
self.assertEqual(
|
762 |
['B1', 'A1', 'A2', 'A3'], |
763 |
depends('A3', lambda n: graph[n]), |
764 |
) |
765 |
graph = {'A1': [],
|
766 |
'A2': ['A1'], |
767 |
'A3': ['A2', 'A1', 'B2'], |
768 |
'B1': [],
|
769 |
'B2': ['B1']} |
770 |
self.assertEqual(
|
771 |
['B1', 'B2', 'A1', 'A2', 'A3'], |
772 |
depends('A3', lambda n: graph[n]), |
773 |
) |
774 |
graph = {'A1': [],
|
775 |
'A2': ['A1', 'B1'], |
776 |
'A3': ['A2'], |
777 |
'B1': ['A1']} |
778 |
self.assertEqual(['A1', 'B1', 'A2', 'A3'], |
779 |
depends('A3', lambda n: graph[n])) |
780 |
graph = {'A1': [],
|
781 |
'A2': ['A1'], |
782 |
'A3': ['A2', 'A1', 'B2'], |
783 |
'B1': [],
|
784 |
'B2': ['B1', 'C1'], |
785 |
'C1': ['B1']} |
786 |
self.assertEqual(
|
787 |
['B1', 'C1', 'B2', 'A1', 'A2', 'A3'], |
788 |
depends('A3', lambda n: graph[n]), |
789 |
) |
790 |
graph = {'A1': [],
|
791 |
'A2': ['A1'], |
792 |
'A3': ['A2', 'B2', 'A1', 'C1'], |
793 |
'B1': ['A1'], |
794 |
'B2': ['B1', 'C2', 'A1'], |
795 |
'C1': ['B1'], |
796 |
'C2': ['C1', 'A1'], |
797 |
'C3': ['C2']} |
798 |
self.assertEqual(
|
799 |
['A1', 'B1', 'C1', 'C2', 'B2', 'A2', 'A3'], |
800 |
depends('A3', lambda n: graph[n]), |
801 |
) |
802 |
|
803 |
def assertCircularDependency(self, trace, target, graph): |
804 |
"Custom assertion that checks a circular dependency is detected correctly."
|
805 |
self.assertRaises(
|
806 |
exceptions.CircularDependency, |
807 |
depends, |
808 |
target, |
809 |
lambda n: graph[n],
|
810 |
) |
811 |
try:
|
812 |
depends(target, lambda n: graph[n])
|
813 |
except exceptions.CircularDependency, e:
|
814 |
self.assertEqual(trace, e.trace)
|
815 |
|
816 |
def test_depends_cycle(self): |
817 |
graph = {'A1': ['A1']} |
818 |
self.assertCircularDependency(
|
819 |
['A1', 'A1'], |
820 |
'A1',
|
821 |
graph, |
822 |
) |
823 |
graph = {'A1': [],
|
824 |
'A2': ['A1', 'A2'], |
825 |
'A3': ['A2']} |
826 |
self.assertCircularDependency(
|
827 |
['A2', 'A2'], |
828 |
'A3',
|
829 |
graph, |
830 |
) |
831 |
graph = {'A1': [],
|
832 |
'A2': ['A1'], |
833 |
'A3': ['A2', 'A3'], |
834 |
'A4': ['A3']} |
835 |
self.assertCircularDependency(
|
836 |
['A3', 'A3'], |
837 |
'A4',
|
838 |
graph, |
839 |
) |
840 |
graph = {'A1': ['B1'], |
841 |
'B1': ['A1']} |
842 |
self.assertCircularDependency(
|
843 |
['A1', 'B1', 'A1'], |
844 |
'A1',
|
845 |
graph, |
846 |
) |
847 |
graph = {'A1': [],
|
848 |
'A2': ['A1', 'B2'], |
849 |
'A3': ['A2'], |
850 |
'B1': [],
|
851 |
'B2': ['B1', 'A2'], |
852 |
'B3': ['B2']} |
853 |
self.assertCircularDependency(
|
854 |
['A2', 'B2', 'A2'], |
855 |
'A3',
|
856 |
graph, |
857 |
) |
858 |
graph = {'A1': [],
|
859 |
'A2': ['A1', 'B3'], |
860 |
'A3': ['A2'], |
861 |
'B1': [],
|
862 |
'B2': ['B1', 'A2'], |
863 |
'B3': ['B2']} |
864 |
self.assertCircularDependency(
|
865 |
['A2', 'B3', 'B2', 'A2'], |
866 |
'A3',
|
867 |
graph, |
868 |
) |
869 |
graph = {'A1': [],
|
870 |
'A2': ['A1'], |
871 |
'A3': ['A2', 'B2'], |
872 |
'A4': ['A3'], |
873 |
'B1': ['A3'], |
874 |
'B2': ['B1']} |
875 |
self.assertCircularDependency(
|
876 |
['A3', 'B2', 'B1', 'A3'], |
877 |
'A4',
|
878 |
graph, |
879 |
) |
880 |
|
881 |
class TestManualChanges(Monkeypatcher): |
882 |
installed_apps = ["fakeapp", "otherfakeapp"] |
883 |
|
884 |
def test_suggest_name(self): |
885 |
migrations = Migrations('fakeapp')
|
886 |
change = ManualChanges(migrations, |
887 |
[], |
888 |
['fakeapp.slug'],
|
889 |
[]) |
890 |
self.assertEquals(change.suggest_name(),
|
891 |
'add_field_fakeapp_slug')
|
892 |
|
893 |
change = ManualChanges(migrations, |
894 |
[], |
895 |
[], |
896 |
['fakeapp.slug'])
|
897 |
self.assertEquals(change.suggest_name(),
|
898 |
'add_index_fakeapp_slug')
|