test_loader.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. from unittest import skipIf
  2. from django.test import TestCase, override_settings
  3. from django.db import connection, connections
  4. from django.db.migrations.loader import MigrationLoader, AmbiguityError
  5. from django.db.migrations.recorder import MigrationRecorder
  6. from django.test import modify_settings
  7. from django.utils import six
  8. class RecorderTests(TestCase):
  9. """
  10. Tests recording migrations as applied or not.
  11. """
  12. def test_apply(self):
  13. """
  14. Tests marking migrations as applied/unapplied.
  15. """
  16. recorder = MigrationRecorder(connection)
  17. self.assertEqual(
  18. set((x, y) for (x, y) in recorder.applied_migrations() if x == "myapp"),
  19. set(),
  20. )
  21. recorder.record_applied("myapp", "0432_ponies")
  22. self.assertEqual(
  23. set((x, y) for (x, y) in recorder.applied_migrations() if x == "myapp"),
  24. set([("myapp", "0432_ponies")]),
  25. )
  26. # That should not affect records of another database
  27. recorder_other = MigrationRecorder(connections['other'])
  28. self.assertEqual(
  29. set((x, y) for (x, y) in recorder_other.applied_migrations() if x == "myapp"),
  30. set(),
  31. )
  32. recorder.record_unapplied("myapp", "0432_ponies")
  33. self.assertEqual(
  34. set((x, y) for (x, y) in recorder.applied_migrations() if x == "myapp"),
  35. set(),
  36. )
  37. class LoaderTests(TestCase):
  38. """
  39. Tests the disk and database loader, and running through migrations
  40. in memory.
  41. """
  42. @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
  43. @modify_settings(INSTALLED_APPS={'append': 'basic'})
  44. def test_load(self):
  45. """
  46. Makes sure the loader can load the migrations for the test apps,
  47. and then render them out to a new Apps.
  48. """
  49. # Load and test the plan
  50. migration_loader = MigrationLoader(connection)
  51. self.assertEqual(
  52. migration_loader.graph.forwards_plan(("migrations", "0002_second")),
  53. [
  54. ("migrations", "0001_initial"),
  55. ("migrations", "0002_second"),
  56. ],
  57. )
  58. # Now render it out!
  59. project_state = migration_loader.project_state(("migrations", "0002_second"))
  60. self.assertEqual(len(project_state.models), 2)
  61. author_state = project_state.models["migrations", "author"]
  62. self.assertEqual(
  63. [x for x, y in author_state.fields],
  64. ["id", "name", "slug", "age", "rating"]
  65. )
  66. book_state = project_state.models["migrations", "book"]
  67. self.assertEqual(
  68. [x for x, y in book_state.fields],
  69. ["id", "author"]
  70. )
  71. # Ensure we've included unmigrated apps in there too
  72. self.assertIn("basic", project_state.real_apps)
  73. @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_unmigdep"})
  74. def test_load_unmigrated_dependency(self):
  75. """
  76. Makes sure the loader can load migrations with a dependency on an unmigrated app.
  77. """
  78. # Load and test the plan
  79. migration_loader = MigrationLoader(connection)
  80. self.assertEqual(
  81. migration_loader.graph.forwards_plan(("migrations", "0001_initial")),
  82. [
  83. ('contenttypes', '0001_initial'),
  84. ('auth', '0001_initial'),
  85. ("migrations", "0001_initial"),
  86. ],
  87. )
  88. # Now render it out!
  89. project_state = migration_loader.project_state(("migrations", "0001_initial"))
  90. self.assertEqual(len([m for a, m in project_state.models if a == "migrations"]), 1)
  91. book_state = project_state.models["migrations", "book"]
  92. self.assertEqual(
  93. [x for x, y in book_state.fields],
  94. ["id", "user"]
  95. )
  96. @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_run_before"})
  97. def test_run_before(self):
  98. """
  99. Makes sure the loader uses Migration.run_before.
  100. """
  101. # Load and test the plan
  102. migration_loader = MigrationLoader(connection)
  103. self.assertEqual(
  104. migration_loader.graph.forwards_plan(("migrations", "0002_second")),
  105. [
  106. ("migrations", "0001_initial"),
  107. ("migrations", "0003_third"),
  108. ("migrations", "0002_second"),
  109. ],
  110. )
  111. @override_settings(MIGRATION_MODULES={
  112. "migrations": "migrations.test_migrations_first",
  113. "migrations2": "migrations2.test_migrations_2_first",
  114. })
  115. @modify_settings(INSTALLED_APPS={'append': 'migrations2'})
  116. def test_first(self):
  117. """
  118. Makes sure the '__first__' migrations build correctly.
  119. """
  120. migration_loader = MigrationLoader(connection)
  121. self.assertEqual(
  122. migration_loader.graph.forwards_plan(("migrations", "second")),
  123. [
  124. ("migrations", "thefirst"),
  125. ("migrations2", "0001_initial"),
  126. ("migrations2", "0002_second"),
  127. ("migrations", "second"),
  128. ],
  129. )
  130. @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
  131. def test_name_match(self):
  132. "Tests prefix name matching"
  133. migration_loader = MigrationLoader(connection)
  134. self.assertEqual(
  135. migration_loader.get_migration_by_prefix("migrations", "0001").name,
  136. "0001_initial",
  137. )
  138. with self.assertRaises(AmbiguityError):
  139. migration_loader.get_migration_by_prefix("migrations", "0")
  140. with self.assertRaises(KeyError):
  141. migration_loader.get_migration_by_prefix("migrations", "blarg")
  142. def test_load_import_error(self):
  143. with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.import_error"}):
  144. with self.assertRaises(ImportError):
  145. MigrationLoader(connection)
  146. def test_load_module_file(self):
  147. with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.file"}):
  148. MigrationLoader(connection)
  149. @skipIf(six.PY2, "PY2 doesn't load empty dirs.")
  150. def test_load_empty_dir(self):
  151. with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.namespace"}):
  152. MigrationLoader(connection)
  153. @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"})
  154. def test_loading_squashed(self):
  155. "Tests loading a squashed migration"
  156. migration_loader = MigrationLoader(connection)
  157. recorder = MigrationRecorder(connection)
  158. # Loading with nothing applied should just give us the one node
  159. self.assertEqual(
  160. len([x for x in migration_loader.graph.nodes if x[0] == "migrations"]),
  161. 1,
  162. )
  163. # However, fake-apply one migration and it should now use the old two
  164. recorder.record_applied("migrations", "0001_initial")
  165. migration_loader.build_graph()
  166. self.assertEqual(
  167. len([x for x in migration_loader.graph.nodes if x[0] == "migrations"]),
  168. 2,
  169. )
  170. recorder.flush()