1 from dmigrations.tests.common import *
2 from dmigrations.migration_state import MigrationState
3 from dmigrations.migration_db import MigrationDb
6 CREATE TABLE `dmigrations` (
7 `id` int(11) NOT NULL auto_increment,
8 `migration` VARCHAR(255) NOT NULL,
10 ) ENGINE=InnoDB DEFAULT CHARSET=utf8
13 class MigrationStateTest(TestCase):
15 from django.db import connection
16 self.cursor = connection.cursor()
18 try: self.cursor.execute("DROP TABLE dmigrations")
21 def test_table_present_methods(self):
24 self.assert_equal(False, si.migration_table_present())
26 self.cursor.execute(create_new)
28 self.assert_equal(True, si.migration_table_present())
30 def test_init_on_fresh_db_creates_new_table(self):
33 self.assert_equal(False, si.migration_table_present())
37 self.assert_equal(True, si.migration_table_present())
39 def test_init_on_initialized_db_does_nothing(self):
40 self.cursor.execute(create_new)
44 self.assert_equal(True, si.migration_table_present())
48 self.assert_equal(True, si.migration_table_present())
50 def test_applying_and_unapplying(self):
51 def assert_applied(f, b, h):
52 self.assert_equal([f, b, h], [si.is_applied('001_foo'), si.is_applied('002_bar'), si.is_applied('005_hello')])
55 self.cursor.execute(create_new)
57 assert_applied(False, False, False)
59 si.mark_as_applied('001_foo')
60 assert_applied(True, False, False)
62 si.mark_as_applied('005_hello')
63 assert_applied(True, False, True)
65 si.mark_as_applied('005_hello')
66 assert_applied(True, False, True)
68 si.mark_as_unapplied('002_bar')
69 assert_applied(True, False, True)
71 si.mark_as_unapplied('005_hello')
72 assert_applied(True, False, False)
74 si.mark_as_applied('002_bar')
75 assert_applied(True, True, False)
77 def assert_plans(self, si, *plans):
79 query, expected_plan, plans = plans[0], plans[1], plans[2:]
81 if isinstance(expected_plan, type(Exception)) and issubclass(expected_plan, Exception):
82 self.assert_raises(expected_plan, lambda: si.plan(*query))
84 actual_plan = si.plan(*query)
85 self.assert_equal(expected_plan, actual_plan, u"Plan for %s expected to be %s but was %s" % (query, expected_plan, actual_plan))
88 db = MigrationDb(migrations = ['001_foo', '002_bar', '005_omg', '005_hello'])
89 si = MigrationState(migration_db=db)
94 ['apply', '1'], [('001_foo', 'up')],
95 ['apply', '001_foo'], [('001_foo', 'up')],
96 ['apply', '1', '2'], [('001_foo', 'up'), ('002_bar', 'up')],
97 ['unapply', '001_foo'], [],
98 ['unapply', '1', '2'], [],
100 ['all'], [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
101 ['up'], [('001_foo', 'up')],
104 ['to', '1'], [('001_foo', 'up')],
105 ['to', '2'], [('001_foo', 'up'), ('002_bar', 'up')],
106 ['upto', '2'], [('001_foo', 'up'), ('002_bar', 'up')],
107 ['upto', '002_bar'], [('001_foo', 'up'), ('002_bar', 'up')],
108 ['upto', '4'], [('001_foo', 'up'), ('002_bar', 'up')],
109 ['upto', '004_foo'], NoSuchMigrationError,
110 ['upto', '5'], AmbiguousMigrationNameError,
111 ['upto', '005_hello'], [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up')],
112 ['upto', '005_omg'], [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
117 si.mark_as_applied('002_bar')
119 self.assert_plans(si,
120 ['apply', '1'], [('001_foo', 'up')],
121 ['apply', '001_foo'], [('001_foo', 'up')],
122 ['apply', '1', '2'], [('001_foo', 'up')],
123 ['unapply', '001_foo'], [],
124 ['unapply', '1', '2'], [('002_bar', 'down')],
126 ['all'], [('001_foo', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
127 ['up'], [('001_foo', 'up')],
128 ['down'], [('002_bar', 'down')],
130 ['to', '1'], [('002_bar', 'down'), ('001_foo', 'up')],
131 ['to', '2'], [('001_foo', 'up')],
132 ['upto', '2'], [('001_foo', 'up')],
133 ['upto', '002_bar'], [('001_foo', 'up')],
134 ['upto', '4'], [('001_foo', 'up')],
135 ['upto', '004_foo'], NoSuchMigrationError,
136 ['upto', '5'], AmbiguousMigrationNameError,
137 ['upto', '005_hello'], [('001_foo', 'up'), ('005_hello', 'up')],
138 ['upto', '005_omg'], [('001_foo', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
139 ['downto', '1'], [('002_bar', 'down')],
143 si.mark_as_applied('001_foo')
145 self.assert_plans(si,
147 ['apply', '001_foo'], [],
148 ['apply', '1', '2'], [],
149 ['unapply', '001_foo'], [('001_foo', 'down')],
150 ['unapply', '1', '2'], [('001_foo', 'down'), ('002_bar', 'down')],
152 ['all'], [('005_hello', 'up'), ('005_omg', 'up')],
153 ['up'], [('005_hello', 'up')],
154 ['down'], [('002_bar', 'down')],
156 ['to', '1'], [('002_bar', 'down')],
159 ['upto', '002_bar'], [],
161 ['upto', '004_foo'], NoSuchMigrationError,
162 ['upto', '5'], AmbiguousMigrationNameError,
163 ['upto', '005_hello'], [('005_hello', 'up')],
164 ['upto', '005_omg'], [('005_hello', 'up'), ('005_omg', 'up')],
165 ['downto', '1'], [('002_bar', 'down')],
169 si.mark_as_unapplied('002_bar')
171 self.assert_plans(si,
173 ['apply', '001_foo'], [],
174 ['apply', '1', '2'], [('002_bar', 'up')],
175 ['unapply', '001_foo'], [('001_foo', 'down')],
176 ['unapply', '1', '2'], [('001_foo', 'down')],
178 ['all'], [('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
179 ['up'], [('002_bar', 'up')],
180 ['down'], [('001_foo', 'down')],
183 ['to', '2'], [('002_bar', 'up')],
184 ['upto', '2'], [('002_bar', 'up')],
185 ['upto', '002_bar'], [('002_bar', 'up')],
186 ['upto', '4'], [('002_bar', 'up')],
187 ['upto', '004_foo'], NoSuchMigrationError,
188 ['upto', '5'], AmbiguousMigrationNameError,
189 ['upto', '005_hello'], [('002_bar', 'up'), ('005_hello', 'up')],
190 ['upto', '005_omg'], [('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
195 si.mark_as_applied('002_bar')
196 si.mark_as_applied('005_hello')
197 si.mark_as_applied('005_omg')
199 self.assert_plans(si,
201 ['apply', '001_foo'], [],
202 ['apply', '1', '2'], [],
203 ['unapply', '001_foo'], [('001_foo', 'down')],
204 ['unapply', '1', '2'], [('001_foo', 'down'), ('002_bar', 'down')],
208 ['down'], [('005_omg', 'down')],
210 ['to', '1'], [('005_omg', 'down'), ('005_hello', 'down'), ('002_bar', 'down')],
211 ['to', '2'], [('005_omg', 'down'), ('005_hello', 'down')],
213 ['upto', '002_bar'], [],
215 ['upto', '004_foo'], NoSuchMigrationError,
216 ['upto', '5'], AmbiguousMigrationNameError,
217 ['upto', '005_hello'], [],
218 ['upto', '005_omg'], [],
219 ['downto', '1'], [('005_omg', 'down'), ('005_hello', 'down'), ('002_bar', 'down')],
220 ['downto', '2'], [('005_omg', 'down'), ('005_hello', 'down')],
223 def test_plan_with_dev(self):
224 # NOTE: si.mark_as_applied modifies global state, not si (MigrationState) object.
225 # There is only one meaningful MigrationState object per database,
226 # so it's an almost-singleton unless we support multiple databases at the same time.
227 # This makes testing quite ugly.
228 db = MigrationDb(migrations = ['001_foo', '002_DEV_bar', '005_omg', '006_DEV_hello'])
230 si = MigrationState(migration_db=db)
232 self.assert_plans(si,
233 ['up'], [('001_foo', 'up')],
234 ['upto', '5'], [('001_foo', 'up'), ('005_omg', 'up')],
235 ['upto', '6'], [('001_foo', 'up'), ('005_omg', 'up')],
236 ['all'], [('001_foo', 'up'), ('005_omg', 'up')],
239 si = MigrationState(migration_db=db, dev=True)
241 self.assert_plans(si,
242 ['up'], [('001_foo', 'up')],
243 ['upto', '5'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up')],
244 ['upto', '6'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
245 ['all'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
248 si.mark_as_applied('001_foo')
250 si = MigrationState(migration_db=db)
252 self.assert_plans(si,
253 ['up'], [('005_omg', 'up')],
254 ['upto', '5'], [('005_omg', 'up')],
255 ['upto', '6'], [('005_omg', 'up')],
256 ['all'], [('005_omg', 'up')],
259 si = MigrationState(migration_db=db, dev=True)
261 self.assert_plans(si,
262 ['up'], [('002_DEV_bar', 'up')],
263 ['upto', '5'], [('002_DEV_bar', 'up'), ('005_omg', 'up')],
264 ['upto', '6'], [('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
265 ['all'], [('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
268 si.mark_as_applied('002_DEV_bar')
270 si = MigrationState(migration_db=db)
272 self.assert_plans(si,
273 ['up'], [('005_omg', 'up')],
274 ['upto', '5'], [('005_omg', 'up')],
275 ['upto', '6'], [('005_omg', 'up')],
276 ['all'], [('005_omg', 'up')],
277 ['down'], [('001_foo', 'down')], # Is it better to always assume --dev on down ?
280 si = MigrationState(migration_db=db, dev=True)
282 self.assert_plans(si,
283 ['up'], [('005_omg', 'up')],
284 ['upto', '5'], [('005_omg', 'up')],
285 ['upto', '6'], [('005_omg', 'up'), ('006_DEV_hello', 'up')],
286 ['all'], [('005_omg', 'up'), ('006_DEV_hello', 'up')],
287 ['down'], [('002_DEV_bar', 'down')],
290 def test_all_migrations_applied(self):
291 db = MigrationDb(migrations = ['001_foo', '002_DEV_bar', '005_omg', '006_DEV_hello'])
292 si = MigrationState(migration_db=db)
295 si.mark_as_applied('005_omg')
296 si.mark_as_applied('001_foo')
297 si.mark_as_applied('009_bogus')
299 self.assert_equal(['001_foo', '005_omg', '009_bogus'], si.all_migrations_applied())