Commit | Line | Data |
---|---|---|
0f10058f | 1 | # GNU MediaGoblin -- federated, autonomous media hosting |
89694d6d | 2 | # Copyright (C) 2012, 2012 MediaGoblin contributors. See AUTHORS. |
0f10058f CAW |
3 | # |
4 | # This program is free software: you can redistribute it and/or modify | |
5 | # it under the terms of the GNU Affero General Public License as published by | |
6 | # the Free Software Foundation, either version 3 of the License, or | |
7 | # (at your option) any later version. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU Affero General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU Affero General Public License | |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | import copy | |
18 | ||
19 | from sqlalchemy import ( | |
5de0f4da | 20 | Table, Column, MetaData, Index, |
89694d6d | 21 | Integer, Float, Unicode, UnicodeText, DateTime, Boolean, |
c7fa585b | 22 | ForeignKey, UniqueConstraint, PickleType, VARCHAR) |
d74a9483 | 23 | from sqlalchemy.orm import sessionmaker, relationship |
0f10058f | 24 | from sqlalchemy.ext.declarative import declarative_base |
89694d6d | 25 | from sqlalchemy.sql import select, insert |
0f10058f CAW |
26 | from migrate import changeset |
27 | ||
28 | from mediagoblin.db.sql.base import GMGTableBase | |
e8e52b3a | 29 | from mediagoblin.db.sql.util import MigrationManager, RegisterMigration |
0f10058f CAW |
30 | |
31 | ||
32 | # This one will get filled with local migrations | |
33 | FULL_MIGRATIONS = {} | |
34 | ||
35 | ||
36 | ####################################################### | |
37 | # Migration set 1: Define initial models, no migrations | |
38 | ####################################################### | |
39 | ||
40 | Base1 = declarative_base(cls=GMGTableBase) | |
41 | ||
42 | class Creature1(Base1): | |
43 | __tablename__ = "creature" | |
44 | ||
45 | id = Column(Integer, primary_key=True) | |
46 | name = Column(Unicode, unique=True, nullable=False, index=True) | |
47 | num_legs = Column(Integer, nullable=False) | |
48 | is_demon = Column(Boolean) | |
49 | ||
50 | class Level1(Base1): | |
51 | __tablename__ = "level" | |
52 | ||
64d28064 | 53 | id = Column(Unicode, primary_key=True) |
caed154a | 54 | name = Column(Unicode) |
40f0996a | 55 | description = Column(Unicode) |
0f10058f CAW |
56 | exits = Column(PickleType) |
57 | ||
58 | SET1_MODELS = [Creature1, Level1] | |
59 | ||
a5e03db6 | 60 | SET1_MIGRATIONS = {} |
0f10058f CAW |
61 | |
62 | ####################################################### | |
63 | # Migration set 2: A few migrations and new model | |
64 | ####################################################### | |
65 | ||
66 | Base2 = declarative_base(cls=GMGTableBase) | |
67 | ||
68 | class Creature2(Base2): | |
69 | __tablename__ = "creature" | |
70 | ||
71 | id = Column(Integer, primary_key=True) | |
72 | name = Column(Unicode, unique=True, nullable=False, index=True) | |
73 | num_legs = Column(Integer, nullable=False) | |
d74a9483 | 74 | magical_powers = relationship("CreaturePower2") |
0f10058f CAW |
75 | |
76 | class CreaturePower2(Base2): | |
77 | __tablename__ = "creature_power" | |
78 | ||
79 | id = Column(Integer, primary_key=True) | |
80 | creature = Column( | |
81 | Integer, ForeignKey('creature.id'), nullable=False) | |
82 | name = Column(Unicode) | |
83 | description = Column(Unicode) | |
89694d6d | 84 | hitpower = Column(Integer, nullable=False) |
0f10058f CAW |
85 | |
86 | class Level2(Base2): | |
87 | __tablename__ = "level" | |
88 | ||
64d28064 | 89 | id = Column(Unicode, primary_key=True) |
0f10058f | 90 | name = Column(Unicode) |
40f0996a | 91 | description = Column(Unicode) |
0f10058f CAW |
92 | |
93 | class LevelExit2(Base2): | |
94 | __tablename__ = "level_exit" | |
95 | ||
96 | id = Column(Integer, primary_key=True) | |
97 | name = Column(Unicode) | |
98 | from_level = Column( | |
64d28064 | 99 | Unicode, ForeignKey('level.id'), nullable=False) |
0f10058f | 100 | to_level = Column( |
64d28064 | 101 | Unicode, ForeignKey('level.id'), nullable=False) |
0f10058f CAW |
102 | |
103 | SET2_MODELS = [Creature2, CreaturePower2, Level2, LevelExit2] | |
104 | ||
105 | ||
106 | @RegisterMigration(1, FULL_MIGRATIONS) | |
107 | def creature_remove_is_demon(db_conn): | |
356654de CAW |
108 | """ |
109 | Remove the is_demon field from the creature model. We don't need | |
110 | it! | |
111 | """ | |
7f3ec607 CAW |
112 | # :( Commented out 'cuz of: |
113 | # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242 | |
114 | ||
78d17b80 CAW |
115 | # metadata = MetaData(bind=db_conn.bind) |
116 | # creature_table = Table( | |
117 | # 'creature', metadata, | |
118 | # autoload=True, autoload_with=db_conn.bind) | |
119 | # creature_table.drop_column('is_demon') | |
120 | pass | |
121 | ||
0f10058f CAW |
122 | |
123 | @RegisterMigration(2, FULL_MIGRATIONS) | |
124 | def creature_powers_new_table(db_conn): | |
356654de CAW |
125 | """ |
126 | Add a new table for creature powers. Nothing needs to go in it | |
127 | yet though as there wasn't anything that previously held this | |
128 | information | |
129 | """ | |
e920b968 | 130 | metadata = MetaData(bind=db_conn.bind) |
78d17b80 CAW |
131 | |
132 | # We have to access the creature table so sqlalchemy can make the | |
133 | # foreign key relationship | |
134 | creature_table = Table( | |
135 | 'creature', metadata, | |
136 | autoload=True, autoload_with=db_conn.bind) | |
137 | ||
89694d6d CAW |
138 | creature_powers = Table( |
139 | 'creature_power', metadata, | |
140 | Column('id', Integer, primary_key=True), | |
141 | Column('creature', | |
142 | Integer, ForeignKey('creature.id'), nullable=False), | |
143 | Column('name', Unicode), | |
144 | Column('description', Unicode), | |
145 | Column('hitpower', Integer, nullable=False)) | |
e920b968 | 146 | metadata.create_all(db_conn.bind) |
89694d6d | 147 | |
0f10058f CAW |
148 | |
149 | @RegisterMigration(3, FULL_MIGRATIONS) | |
150 | def level_exits_new_table(db_conn): | |
356654de CAW |
151 | """ |
152 | Make a new table for level exits and move the previously pickled | |
153 | stuff over to here (then drop the old unneeded table) | |
154 | """ | |
89694d6d CAW |
155 | # First, create the table |
156 | # ----------------------- | |
e920b968 | 157 | metadata = MetaData(bind=db_conn.bind) |
78d17b80 CAW |
158 | |
159 | # Minimal representation of level table. | |
160 | # Not auto-introspecting here because of pickle table. I'm not | |
161 | # sure sqlalchemy can auto-introspect pickle columns. | |
162 | levels = Table( | |
163 | 'level', metadata, | |
164 | Column('id', Unicode, primary_key=True), | |
165 | Column('name', Unicode), | |
166 | Column('description', Unicode), | |
167 | Column('exits', PickleType)) | |
168 | ||
89694d6d CAW |
169 | level_exits = Table( |
170 | 'level_exit', metadata, | |
171 | Column('id', Integer, primary_key=True), | |
172 | Column('name', Unicode), | |
173 | Column('from_level', | |
78d17b80 | 174 | Unicode, ForeignKey('level.id'), nullable=False), |
89694d6d | 175 | Column('to_level', |
78d17b80 | 176 | Unicode, ForeignKey('level.id'), nullable=False)) |
e920b968 | 177 | metadata.create_all(db_conn.bind) |
89694d6d CAW |
178 | |
179 | # And now, convert all the old exit pickles to new level exits | |
180 | # ------------------------------------------------------------ | |
181 | ||
89694d6d CAW |
182 | # query over and insert |
183 | result = db_conn.execute( | |
184 | select([levels], levels.c.exits!=None)) | |
185 | ||
186 | for level in result: | |
78d17b80 CAW |
187 | |
188 | for exit_name, to_level in level['exits'].iteritems(): | |
189 | # Insert the level exit | |
190 | db_conn.execute( | |
191 | level_exits.insert().values( | |
192 | name=exit_name, | |
193 | from_level=level.id, | |
194 | to_level=to_level)) | |
89694d6d CAW |
195 | |
196 | # Finally, drop the old level exits pickle table | |
197 | # ---------------------------------------------- | |
473e0605 | 198 | levels.drop_column('exits') |
0f10058f CAW |
199 | |
200 | ||
201 | # A hack! At this point we freeze-fame and get just a partial list of | |
202 | # migrations | |
203 | ||
129c36be | 204 | SET2_MIGRATIONS = copy.copy(FULL_MIGRATIONS) |
0f10058f CAW |
205 | |
206 | ####################################################### | |
207 | # Migration set 3: Final migrations | |
208 | ####################################################### | |
209 | ||
210 | Base3 = declarative_base(cls=GMGTableBase) | |
211 | ||
212 | class Creature3(Base3): | |
213 | __tablename__ = "creature" | |
214 | ||
215 | id = Column(Integer, primary_key=True) | |
216 | name = Column(Unicode, unique=True, nullable=False, index=True) | |
217 | num_limbs= Column(Integer, nullable=False) | |
0f3526c6 | 218 | magical_powers = relationship("CreaturePower3") |
0f10058f CAW |
219 | |
220 | class CreaturePower3(Base3): | |
221 | __tablename__ = "creature_power" | |
222 | ||
223 | id = Column(Integer, primary_key=True) | |
224 | creature = Column( | |
225 | Integer, ForeignKey('creature.id'), nullable=False, index=True) | |
226 | name = Column(Unicode) | |
227 | description = Column(Unicode) | |
89694d6d | 228 | hitpower = Column(Float, nullable=False) |
0f10058f CAW |
229 | |
230 | class Level3(Base3): | |
231 | __tablename__ = "level" | |
232 | ||
64d28064 | 233 | id = Column(Unicode, primary_key=True) |
0f10058f | 234 | name = Column(Unicode) |
40f0996a | 235 | description = Column(Unicode) |
0f10058f CAW |
236 | |
237 | class LevelExit3(Base3): | |
238 | __tablename__ = "level_exit" | |
239 | ||
240 | id = Column(Integer, primary_key=True) | |
241 | name = Column(Unicode) | |
242 | from_level = Column( | |
64d28064 | 243 | Unicode, ForeignKey('level.id'), nullable=False, index=True) |
0f10058f | 244 | to_level = Column( |
64d28064 | 245 | Unicode, ForeignKey('level.id'), nullable=False, index=True) |
0f10058f CAW |
246 | |
247 | ||
248 | SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3] | |
caed154a | 249 | SET3_MIGRATIONS = FULL_MIGRATIONS |
0f10058f CAW |
250 | |
251 | ||
252 | @RegisterMigration(4, FULL_MIGRATIONS) | |
253 | def creature_num_legs_to_num_limbs(db_conn): | |
d6cdf64b CAW |
254 | """ |
255 | Turns out we're tracking all sorts of limbs, not "legs" | |
256 | specifically. Humans would be 4 here, for instance. So we | |
257 | renamed the column. | |
258 | """ | |
e920b968 | 259 | metadata = MetaData(bind=db_conn.bind) |
248b5061 CAW |
260 | creature_table = Table( |
261 | 'creature', metadata, | |
e920b968 | 262 | autoload=True, autoload_with=db_conn.bind) |
94eff10d | 263 | creature_table.c.num_legs.alter(name=u"num_limbs") |
248b5061 | 264 | |
0f10058f CAW |
265 | |
266 | @RegisterMigration(5, FULL_MIGRATIONS) | |
267 | def level_exit_index_from_and_to_level(db_conn): | |
d6cdf64b CAW |
268 | """ |
269 | Index the from and to levels of the level exit table. | |
270 | """ | |
e920b968 | 271 | metadata = MetaData(bind=db_conn.bind) |
248b5061 CAW |
272 | level_exit = Table( |
273 | 'level_exit', metadata, | |
e920b968 | 274 | autoload=True, autoload_with=db_conn.bind) |
78d17b80 CAW |
275 | Index('ix_level_exit_from_level', |
276 | level_exit.c.from_level).create(db_conn.bind) | |
277 | Index('ix_level_exit_to_level', | |
278 | level_exit.c.to_level).create(db_conn.bind) | |
248b5061 | 279 | |
0f10058f CAW |
280 | |
281 | @RegisterMigration(6, FULL_MIGRATIONS) | |
282 | def creature_power_index_creature(db_conn): | |
d6cdf64b CAW |
283 | """ |
284 | Index our foreign key relationship to the creatures | |
285 | """ | |
e920b968 | 286 | metadata = MetaData(bind=db_conn.bind) |
248b5061 CAW |
287 | creature_power = Table( |
288 | 'creature_power', metadata, | |
e920b968 | 289 | autoload=True, autoload_with=db_conn.bind) |
78d17b80 CAW |
290 | Index('ix_creature_power_creature', |
291 | creature_power.c.creature).create(db_conn.bind) | |
248b5061 | 292 | |
89694d6d CAW |
293 | |
294 | @RegisterMigration(7, FULL_MIGRATIONS) | |
295 | def creature_power_hitpower_to_float(db_conn): | |
d6cdf64b CAW |
296 | """ |
297 | Convert hitpower column on creature power table from integer to | |
298 | float. | |
299 | ||
300 | Turns out we want super precise values of how much hitpower there | |
301 | really is. | |
302 | """ | |
e920b968 | 303 | metadata = MetaData(bind=db_conn.bind) |
78d17b80 CAW |
304 | |
305 | # We have to access the creature table so sqlalchemy can make the | |
306 | # foreign key relationship | |
307 | creature_table = Table( | |
308 | 'creature', metadata, | |
309 | autoload=True, autoload_with=db_conn.bind) | |
310 | ||
248b5061 CAW |
311 | creature_power = Table( |
312 | 'creature_power', metadata, | |
78d17b80 CAW |
313 | Column('id', Integer, primary_key=True), |
314 | Column('creature', Integer, | |
315 | ForeignKey('creature.id'), nullable=False, | |
316 | index=True), | |
317 | Column('name', Unicode), | |
318 | Column('description', Unicode), | |
319 | Column('hitpower', Integer, nullable=False)) | |
320 | ||
248b5061 | 321 | creature_power.c.hitpower.alter(type=Float) |
64d28064 CAW |
322 | |
323 | ||
324 | def _insert_migration1_objects(session): | |
356654de CAW |
325 | """ |
326 | Test objects to insert for the first set of things | |
327 | """ | |
64d28064 CAW |
328 | # Insert creatures |
329 | session.add_all( | |
94eff10d | 330 | [Creature1(name=u'centipede', |
64d28064 CAW |
331 | num_legs=100, |
332 | is_demon=False), | |
94eff10d | 333 | Creature1(name=u'wolf', |
64d28064 CAW |
334 | num_legs=4, |
335 | is_demon=False), | |
336 | # don't ask me what a wizardsnake is. | |
94eff10d | 337 | Creature1(name=u'wizardsnake', |
64d28064 CAW |
338 | num_legs=0, |
339 | is_demon=True)]) | |
340 | ||
d74a9483 | 341 | # Insert levels |
64d28064 | 342 | session.add_all( |
94eff10d CAW |
343 | [Level1(id=u'necroplex', |
344 | name=u'The Necroplex', | |
345 | description=u'A complex full of pure deathzone.', | |
64d28064 CAW |
346 | exits={ |
347 | 'deathwell': 'evilstorm', | |
348 | 'portal': 'central_park'}), | |
94eff10d CAW |
349 | Level1(id=u'evilstorm', |
350 | name=u'Evil Storm', | |
351 | description=u'A storm full of pure evil.', | |
64d28064 | 352 | exits={}), # you can't escape the evilstorm |
caed154a | 353 | Level1(id=u'central_park', |
94eff10d CAW |
354 | name=u'Central Park, NY, NY', |
355 | description=u"New York's friendly Central Park.", | |
64d28064 CAW |
356 | exits={ |
357 | 'portal': 'necroplex'})]) | |
358 | ||
359 | session.commit() | |
360 | ||
d74a9483 CAW |
361 | |
362 | def _insert_migration2_objects(session): | |
356654de CAW |
363 | """ |
364 | Test objects to insert for the second set of things | |
365 | """ | |
d74a9483 CAW |
366 | # Insert creatures |
367 | session.add_all( | |
368 | [Creature2( | |
94eff10d | 369 | name=u'centipede', |
d74a9483 CAW |
370 | num_legs=100), |
371 | Creature2( | |
94eff10d | 372 | name=u'wolf', |
d74a9483 CAW |
373 | num_legs=4, |
374 | magical_powers = [ | |
375 | CreaturePower2( | |
94eff10d CAW |
376 | name=u"ice breath", |
377 | description=u"A blast of icy breath!", | |
d74a9483 CAW |
378 | hitpower=20), |
379 | CreaturePower2( | |
94eff10d CAW |
380 | name=u"death stare", |
381 | description=u"A frightening stare, for sure!", | |
d74a9483 CAW |
382 | hitpower=45)]), |
383 | Creature2( | |
94eff10d | 384 | name=u'wizardsnake', |
d74a9483 CAW |
385 | num_legs=0, |
386 | magical_powers=[ | |
387 | CreaturePower2( | |
94eff10d CAW |
388 | name=u'death_rattle', |
389 | description=u'A rattle... of DEATH!', | |
d74a9483 CAW |
390 | hitpower=1000), |
391 | CreaturePower2( | |
94eff10d | 392 | name=u'sneaky_stare', |
caed154a | 393 | description=u"The sneakiest stare you've ever seen!", |
d74a9483 CAW |
394 | hitpower=300), |
395 | CreaturePower2( | |
94eff10d CAW |
396 | name=u'slithery_smoke', |
397 | description=u"A blast of slithery, slithery smoke.", | |
d74a9483 CAW |
398 | hitpower=10), |
399 | CreaturePower2( | |
94eff10d CAW |
400 | name=u'treacherous_tremors', |
401 | description=u"The ground shakes beneath footed animals!", | |
d74a9483 CAW |
402 | hitpower=0)])]) |
403 | ||
404 | # Insert levels | |
405 | session.add_all( | |
94eff10d CAW |
406 | [Level2(id=u'necroplex', |
407 | name=u'The Necroplex', | |
408 | description=u'A complex full of pure deathzone.'), | |
409 | Level2(id=u'evilstorm', | |
410 | name=u'Evil Storm', | |
411 | description=u'A storm full of pure evil.', | |
d74a9483 | 412 | exits=[]), # you can't escape the evilstorm |
caed154a | 413 | Level2(id=u'central_park', |
94eff10d CAW |
414 | name=u'Central Park, NY, NY', |
415 | description=u"New York's friendly Central Park.")]) | |
d74a9483 CAW |
416 | |
417 | # necroplex exits | |
418 | session.add_all( | |
94eff10d CAW |
419 | [LevelExit2(name=u'deathwell', |
420 | from_level=u'necroplex', | |
421 | to_level=u'evilstorm'), | |
422 | LevelExit2(name=u'portal', | |
423 | from_level=u'necroplex', | |
424 | to_level=u'central_park')]) | |
d74a9483 CAW |
425 | |
426 | # there are no evilstorm exits because there is no exit from the | |
427 | # evilstorm | |
428 | ||
429 | # central park exits | |
430 | session.add_all( | |
94eff10d CAW |
431 | [LevelExit2(name=u'portal', |
432 | from_level=u'central_park', | |
433 | to_level=u'necroplex')]) | |
d74a9483 CAW |
434 | |
435 | session.commit() | |
dc3db468 CAW |
436 | |
437 | ||
438 | def _insert_migration3_objects(session): | |
439 | """ | |
440 | Test objects to insert for the third set of things | |
441 | """ | |
442 | # Insert creatures | |
443 | session.add_all( | |
444 | [Creature3( | |
94eff10d | 445 | name=u'centipede', |
dc3db468 CAW |
446 | num_limbs=100), |
447 | Creature3( | |
94eff10d | 448 | name=u'wolf', |
dc3db468 CAW |
449 | num_limbs=4, |
450 | magical_powers = [ | |
451 | CreaturePower3( | |
94eff10d CAW |
452 | name=u"ice breath", |
453 | description=u"A blast of icy breath!", | |
dc3db468 CAW |
454 | hitpower=20.0), |
455 | CreaturePower3( | |
94eff10d CAW |
456 | name=u"death stare", |
457 | description=u"A frightening stare, for sure!", | |
dc3db468 CAW |
458 | hitpower=45.0)]), |
459 | Creature3( | |
94eff10d | 460 | name=u'wizardsnake', |
dc3db468 CAW |
461 | num_limbs=0, |
462 | magical_powers=[ | |
463 | CreaturePower3( | |
94eff10d CAW |
464 | name=u'death_rattle', |
465 | description=u'A rattle... of DEATH!', | |
dc3db468 CAW |
466 | hitpower=1000.0), |
467 | CreaturePower3( | |
94eff10d | 468 | name=u'sneaky_stare', |
caed154a | 469 | description=u"The sneakiest stare you've ever seen!", |
dc3db468 CAW |
470 | hitpower=300.0), |
471 | CreaturePower3( | |
94eff10d CAW |
472 | name=u'slithery_smoke', |
473 | description=u"A blast of slithery, slithery smoke.", | |
dc3db468 CAW |
474 | hitpower=10.0), |
475 | CreaturePower3( | |
94eff10d CAW |
476 | name=u'treacherous_tremors', |
477 | description=u"The ground shakes beneath footed animals!", | |
dc3db468 CAW |
478 | hitpower=0.0)])], |
479 | # annnnnd one more to test a floating point hitpower | |
480 | Creature3( | |
94eff10d | 481 | name=u'deity', |
dc3db468 | 482 | numb_limbs=30, |
caed154a | 483 | magical_powers=[ |
dc3db468 | 484 | CreaturePower3( |
94eff10d CAW |
485 | name=u'smite', |
486 | description=u'Smitten by holy wrath!', | |
caed154a | 487 | hitpower=9999.9)])) |
dc3db468 CAW |
488 | |
489 | # Insert levels | |
490 | session.add_all( | |
94eff10d CAW |
491 | [Level3(id=u'necroplex', |
492 | name=u'The Necroplex', | |
493 | description=u'A complex full of pure deathzone.'), | |
494 | Level3(id=u'evilstorm', | |
495 | name=u'Evil Storm', | |
496 | description=u'A storm full of pure evil.', | |
dc3db468 | 497 | exits=[]), # you can't escape the evilstorm |
caed154a | 498 | Level3(id=u'central_park', |
94eff10d CAW |
499 | name=u'Central Park, NY, NY', |
500 | description=u"New York's friendly Central Park.")]) | |
dc3db468 CAW |
501 | |
502 | # necroplex exits | |
503 | session.add_all( | |
94eff10d CAW |
504 | [LevelExit3(name=u'deathwell', |
505 | from_level=u'necroplex', | |
506 | to_level=u'evilstorm'), | |
507 | LevelExit3(name=u'portal', | |
508 | from_level=u'necroplex', | |
509 | to_level=u'central_park')]) | |
dc3db468 CAW |
510 | |
511 | # there are no evilstorm exits because there is no exit from the | |
512 | # evilstorm | |
513 | ||
514 | # central park exits | |
515 | session.add_all( | |
94eff10d CAW |
516 | [LevelExit3(name=u'portal', |
517 | from_level=u'central_park', | |
518 | to_level=u'necroplex')]) | |
dc3db468 CAW |
519 | |
520 | session.commit() | |
521 | ||
522 | ||
245e6d83 | 523 | class CollectingPrinter(object): |
40f0996a CAW |
524 | def __init__(self): |
525 | self.collection = [] | |
526 | ||
527 | def __call__(self, string): | |
528 | self.collection.append(string) | |
529 | ||
530 | @property | |
531 | def combined_string(self): | |
532 | return u''.join(self.collection) | |
533 | ||
534 | ||
09e2c487 CAW |
535 | def create_test_engine(): |
536 | from sqlalchemy import create_engine | |
537 | engine = create_engine('sqlite:///:memory:', echo=False) | |
40f0996a CAW |
538 | Session = sessionmaker(bind=engine) |
539 | return engine, Session | |
540 | ||
541 | ||
caed154a CAW |
542 | def assert_col_type(column, this_class): |
543 | assert isinstance(column.type, this_class) | |
09e2c487 CAW |
544 | |
545 | ||
e8e52b3a CAW |
546 | def _get_level3_exits(session, level): |
547 | return dict( | |
548 | [(level_exit.name, level_exit.to_level) | |
549 | for level_exit in | |
550 | session.query(LevelExit3).filter_by(from_level=level.id)]) | |
551 | ||
552 | ||
09e2c487 CAW |
553 | def test_set1_to_set3(): |
554 | # Create / connect to database | |
94eff10d CAW |
555 | # ---------------------------- |
556 | ||
40f0996a | 557 | engine, Session = create_test_engine() |
94eff10d | 558 | |
09e2c487 | 559 | # Create tables by migrating on empty initial set |
94eff10d CAW |
560 | # ----------------------------------------------- |
561 | ||
ecb4cc89 | 562 | printer = CollectingPrinter() |
40f0996a CAW |
563 | migration_manager = MigrationManager( |
564 | '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), | |
565 | printer) | |
94eff10d | 566 | |
40f0996a CAW |
567 | # Check latest migration and database current migration |
568 | assert migration_manager.latest_migration == 0 | |
569 | assert migration_manager.database_current_migration == None | |
570 | ||
571 | result = migration_manager.init_or_migrate() | |
94eff10d | 572 | |
40f0996a CAW |
573 | # Make sure output was "inited" |
574 | assert result == u'inited' | |
575 | # Check output | |
94eff10d CAW |
576 | assert printer.combined_string == ( |
577 | "-> Initializing main mediagoblin tables... done.\n") | |
40f0996a CAW |
578 | # Check version in database |
579 | assert migration_manager.latest_migration == 0 | |
580 | assert migration_manager.database_current_migration == 0 | |
09e2c487 CAW |
581 | |
582 | # Install the initial set | |
94eff10d CAW |
583 | # ----------------------- |
584 | ||
40f0996a | 585 | _insert_migration1_objects(Session()) |
94eff10d | 586 | |
40f0996a CAW |
587 | # Try to "re-migrate" with same manager settings... nothing should happen |
588 | migration_manager = MigrationManager( | |
589 | '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), | |
590 | printer) | |
591 | assert migration_manager.init_or_migrate() == None | |
592 | ||
09e2c487 | 593 | # Check version in database |
40f0996a CAW |
594 | assert migration_manager.latest_migration == 0 |
595 | assert migration_manager.database_current_migration == 0 | |
596 | ||
597 | # Sanity check a few things in the database... | |
caed154a | 598 | metadata = MetaData(bind=engine) |
40f0996a CAW |
599 | |
600 | # Check the structure of the creature table | |
601 | creature_table = Table( | |
602 | 'creature', metadata, | |
caed154a | 603 | autoload=True, autoload_with=engine) |
40f0996a CAW |
604 | assert set(creature_table.c.keys()) == set( |
605 | ['id', 'name', 'num_legs', 'is_demon']) | |
606 | assert_col_type(creature_table.c.id, Integer) | |
c7fa585b | 607 | assert_col_type(creature_table.c.name, VARCHAR) |
40f0996a | 608 | assert creature_table.c.name.nullable is False |
c7fa585b CAW |
609 | #assert creature_table.c.name.index is True |
610 | #assert creature_table.c.name.unique is True | |
40f0996a CAW |
611 | assert_col_type(creature_table.c.num_legs, Integer) |
612 | assert creature_table.c.num_legs.nullable is False | |
613 | assert_col_type(creature_table.c.is_demon, Boolean) | |
614 | ||
615 | # Check the structure of the level table | |
616 | level_table = Table( | |
617 | 'level', metadata, | |
caed154a | 618 | autoload=True, autoload_with=engine) |
40f0996a CAW |
619 | assert set(level_table.c.keys()) == set( |
620 | ['id', 'name', 'description', 'exits']) | |
c7fa585b | 621 | assert_col_type(level_table.c.id, VARCHAR) |
94eff10d | 622 | assert level_table.c.id.primary_key is True |
c7fa585b CAW |
623 | assert_col_type(level_table.c.name, VARCHAR) |
624 | assert_col_type(level_table.c.description, VARCHAR) | |
40f0996a CAW |
625 | # Skipping exits... Not sure if we can detect pickletype, not a |
626 | # big deal regardless. | |
627 | ||
628 | # Now check to see if stuff seems to be in there. | |
caed154a CAW |
629 | session = Session() |
630 | ||
94eff10d CAW |
631 | creature = session.query(Creature1).filter_by( |
632 | name=u'centipede').one() | |
633 | assert creature.num_legs == 100 | |
634 | assert creature.is_demon == False | |
635 | ||
636 | creature = session.query(Creature1).filter_by( | |
637 | name=u'wolf').one() | |
638 | assert creature.num_legs == 4 | |
639 | assert creature.is_demon == False | |
640 | ||
641 | creature = session.query(Creature1).filter_by( | |
642 | name=u'wizardsnake').one() | |
643 | assert creature.num_legs == 0 | |
644 | assert creature.is_demon == True | |
645 | ||
646 | level = session.query(Level1).filter_by( | |
e8e52b3a | 647 | id=u'necroplex').one() |
94eff10d | 648 | assert level.name == u'The Necroplex' |
505c0db1 | 649 | assert level.description == u'A complex full of pure deathzone.' |
94eff10d CAW |
650 | assert level.exits == { |
651 | 'deathwell': 'evilstorm', | |
652 | 'portal': 'central_park'} | |
653 | ||
654 | level = session.query(Level1).filter_by( | |
e8e52b3a | 655 | id=u'evilstorm').one() |
94eff10d CAW |
656 | assert level.name == u'Evil Storm' |
657 | assert level.description == u'A storm full of pure evil.' | |
658 | assert level.exits == {} # You still can't escape the evilstorm! | |
659 | ||
660 | level = session.query(Level1).filter_by( | |
e8e52b3a | 661 | id=u'central_park').one() |
94eff10d CAW |
662 | assert level.name == u'Central Park, NY, NY' |
663 | assert level.description == u"New York's friendly Central Park." | |
664 | assert level.exits == { | |
665 | 'portal': 'necroplex'} | |
666 | ||
667 | # Create new migration manager, but make sure the db migration | |
668 | # isn't said to be updated yet | |
ecb4cc89 | 669 | printer = CollectingPrinter() |
94eff10d CAW |
670 | migration_manager = MigrationManager( |
671 | '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), | |
672 | printer) | |
673 | ||
be1077ac | 674 | assert migration_manager.latest_migration == 7 |
94eff10d | 675 | assert migration_manager.database_current_migration == 0 |
09e2c487 CAW |
676 | |
677 | # Migrate | |
94eff10d CAW |
678 | result = migration_manager.init_or_migrate() |
679 | ||
40f0996a | 680 | # Make sure result was "migrated" |
94eff10d CAW |
681 | assert result == u'migrated' |
682 | ||
683 | # TODO: Check output to user | |
684 | assert printer.combined_string == """\ | |
78d17b80 | 685 | -> Updating main mediagoblin tables: |
94eff10d CAW |
686 | + Running migration 1, "creature_remove_is_demon"... done. |
687 | + Running migration 2, "creature_powers_new_table"... done. | |
78d17b80 CAW |
688 | + Running migration 3, "level_exits_new_table"... done. |
689 | + Running migration 4, "creature_num_legs_to_num_limbs"... done. | |
690 | + Running migration 5, "level_exit_index_from_and_to_level"... done. | |
691 | + Running migration 6, "creature_power_index_creature"... done. | |
692 | + Running migration 7, "creature_power_hitpower_to_float"... done. | |
693 | """ | |
94eff10d | 694 | |
09e2c487 | 695 | # Make sure version matches expected |
94eff10d CAW |
696 | migration_manager = MigrationManager( |
697 | '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), | |
698 | printer) | |
be1077ac CAW |
699 | assert migration_manager.latest_migration == 7 |
700 | assert migration_manager.database_current_migration == 7 | |
94eff10d | 701 | |
09e2c487 | 702 | # Check all things in database match expected |
94eff10d CAW |
703 | |
704 | # Check the creature table | |
78d17b80 | 705 | metadata = MetaData(bind=engine) |
94eff10d CAW |
706 | creature_table = Table( |
707 | 'creature', metadata, | |
caed154a | 708 | autoload=True, autoload_with=engine) |
78d17b80 CAW |
709 | # assert set(creature_table.c.keys()) == set( |
710 | # ['id', 'name', 'num_limbs']) | |
94eff10d | 711 | assert set(creature_table.c.keys()) == set( |
78d17b80 | 712 | [u'id', 'name', u'num_limbs', u'is_demon']) |
94eff10d | 713 | assert_col_type(creature_table.c.id, Integer) |
c7fa585b | 714 | assert_col_type(creature_table.c.name, VARCHAR) |
94eff10d | 715 | assert creature_table.c.name.nullable is False |
c7fa585b CAW |
716 | #assert creature_table.c.name.index is True |
717 | #assert creature_table.c.name.unique is True | |
78d17b80 CAW |
718 | assert_col_type(creature_table.c.num_limbs, Integer) |
719 | assert creature_table.c.num_limbs.nullable is False | |
94eff10d CAW |
720 | |
721 | # Check the CreaturePower table | |
722 | creature_power_table = Table( | |
723 | 'creature_power', metadata, | |
caed154a | 724 | autoload=True, autoload_with=engine) |
94eff10d CAW |
725 | assert set(creature_power_table.c.keys()) == set( |
726 | ['id', 'creature', 'name', 'description', 'hitpower']) | |
727 | assert_col_type(creature_power_table.c.id, Integer) | |
728 | assert_col_type(creature_power_table.c.creature, Integer) | |
729 | assert creature_power_table.c.creature.nullable is False | |
c7fa585b CAW |
730 | assert_col_type(creature_power_table.c.name, VARCHAR) |
731 | assert_col_type(creature_power_table.c.description, VARCHAR) | |
690b51fa | 732 | assert_col_type(creature_power_table.c.hitpower, Float) |
94eff10d CAW |
733 | assert creature_power_table.c.hitpower.nullable is False |
734 | ||
735 | # Check the structure of the level table | |
736 | level_table = Table( | |
737 | 'level', metadata, | |
caed154a | 738 | autoload=True, autoload_with=engine) |
94eff10d CAW |
739 | assert set(level_table.c.keys()) == set( |
740 | ['id', 'name', 'description']) | |
c7fa585b | 741 | assert_col_type(level_table.c.id, VARCHAR) |
94eff10d | 742 | assert level_table.c.id.primary_key is True |
c7fa585b CAW |
743 | assert_col_type(level_table.c.name, VARCHAR) |
744 | assert_col_type(level_table.c.description, VARCHAR) | |
94eff10d CAW |
745 | |
746 | # Check the structure of the level_exits table | |
747 | level_exit_table = Table( | |
748 | 'level_exit', metadata, | |
caed154a | 749 | autoload=True, autoload_with=engine) |
94eff10d CAW |
750 | assert set(level_exit_table.c.keys()) == set( |
751 | ['id', 'name', 'from_level', 'to_level']) | |
752 | assert_col_type(level_exit_table.c.id, Integer) | |
c7fa585b CAW |
753 | assert_col_type(level_exit_table.c.name, VARCHAR) |
754 | assert_col_type(level_exit_table.c.from_level, VARCHAR) | |
94eff10d | 755 | assert level_exit_table.c.from_level.nullable is False |
c7fa585b CAW |
756 | #assert level_exit_table.c.from_level.index is True |
757 | assert_col_type(level_exit_table.c.to_level, VARCHAR) | |
94eff10d | 758 | assert level_exit_table.c.to_level.nullable is False |
c7fa585b | 759 | #assert level_exit_table.c.to_level.index is True |
94eff10d CAW |
760 | |
761 | # Now check to see if stuff seems to be in there. | |
caed154a | 762 | session = Session() |
e8e52b3a | 763 | creature = session.query(Creature3).filter_by( |
690b51fa | 764 | name=u'centipede').one() |
5de0f4da | 765 | assert creature.num_limbs == 100.0 |
78d17b80 | 766 | assert creature.magical_powers == [] |
690b51fa | 767 | |
e8e52b3a | 768 | creature = session.query(Creature3).filter_by( |
690b51fa | 769 | name=u'wolf').one() |
5de0f4da | 770 | assert creature.num_limbs == 4.0 |
78d17b80 | 771 | assert creature.magical_powers == [] |
690b51fa | 772 | |
e8e52b3a | 773 | creature = session.query(Creature3).filter_by( |
690b51fa | 774 | name=u'wizardsnake').one() |
5de0f4da | 775 | assert creature.num_limbs == 0.0 |
78d17b80 | 776 | assert creature.magical_powers == [] |
94eff10d | 777 | |
e8e52b3a CAW |
778 | level = session.query(Level3).filter_by( |
779 | id=u'necroplex').one() | |
780 | assert level.name == u'The Necroplex' | |
505c0db1 | 781 | assert level.description == u'A complex full of pure deathzone.' |
e8e52b3a CAW |
782 | level_exits = _get_level3_exits(session, level) |
783 | assert level_exits == { | |
784 | u'deathwell': u'evilstorm', | |
785 | u'portal': u'central_park'} | |
786 | ||
787 | level = session.query(Level3).filter_by( | |
788 | id=u'evilstorm').one() | |
789 | assert level.name == u'Evil Storm' | |
790 | assert level.description == u'A storm full of pure evil.' | |
791 | level_exits = _get_level3_exits(session, level) | |
792 | assert level_exits == {} # You still can't escape the evilstorm! | |
793 | ||
794 | level = session.query(Level3).filter_by( | |
795 | id=u'central_park').one() | |
796 | assert level.name == u'Central Park, NY, NY' | |
797 | assert level.description == u"New York's friendly Central Park." | |
798 | level_exits = _get_level3_exits(session, level) | |
799 | assert level_exits == { | |
800 | 'portal': 'necroplex'} | |
09e2c487 CAW |
801 | |
802 | ||
d2506eeb | 803 | #def test_set2_to_set3(): |
09e2c487 CAW |
804 | # Create / connect to database |
805 | # Create tables by migrating on empty initial set | |
806 | ||
807 | # Install the initial set | |
808 | # Check version in database | |
809 | # Sanity check a few things in the database | |
810 | ||
811 | # Migrate | |
812 | # Make sure version matches expected | |
813 | # Check all things in database match expected | |
d2506eeb | 814 | # pass |
09e2c487 CAW |
815 | |
816 | ||
d2506eeb | 817 | #def test_set1_to_set2_to_set3(): |
09e2c487 CAW |
818 | # Create / connect to database |
819 | # Create tables by migrating on empty initial set | |
820 | ||
821 | # Install the initial set | |
822 | # Check version in database | |
823 | # Sanity check a few things in the database | |
824 | ||
825 | # Migrate | |
826 | # Make sure version matches expected | |
827 | # Check all things in database match expected | |
828 | ||
829 | # Migrate again | |
830 | # Make sure version matches expected again | |
831 | # Check all things in database match expected again | |
690b51fa CAW |
832 | |
833 | ##### Set2 | |
834 | # creature_table = Table( | |
835 | # 'creature', metadata, | |
e920b968 | 836 | # autoload=True, autoload_with=db_conn.bind) |
690b51fa CAW |
837 | # assert set(creature_table.c.keys()) == set( |
838 | # ['id', 'name', 'num_legs']) | |
839 | # assert_col_type(creature_table.c.id, Integer) | |
c7fa585b | 840 | # assert_col_type(creature_table.c.name, VARCHAR) |
690b51fa CAW |
841 | # assert creature_table.c.name.nullable is False |
842 | # assert creature_table.c.name.index is True | |
843 | # assert creature_table.c.name.unique is True | |
844 | # assert_col_type(creature_table.c.num_legs, Integer) | |
845 | # assert creature_table.c.num_legs.nullable is False | |
846 | ||
847 | # # Check the CreaturePower table | |
848 | # creature_power_table = Table( | |
849 | # 'creature_power', metadata, | |
e920b968 | 850 | # autoload=True, autoload_with=db_conn.bind) |
690b51fa CAW |
851 | # assert set(creature_power_table.c.keys()) == set( |
852 | # ['id', 'creature', 'name', 'description', 'hitpower']) | |
853 | # assert_col_type(creature_power_table.c.id, Integer) | |
854 | # assert_col_type(creature_power_table.c.creature, Integer) | |
855 | # assert creature_power_table.c.creature.nullable is False | |
c7fa585b CAW |
856 | # assert_col_type(creature_power_table.c.name, VARCHAR) |
857 | # assert_col_type(creature_power_table.c.description, VARCHAR) | |
690b51fa CAW |
858 | # assert_col_type(creature_power_table.c.hitpower, Integer) |
859 | # assert creature_power_table.c.hitpower.nullable is False | |
860 | ||
861 | # # Check the structure of the level table | |
862 | # level_table = Table( | |
863 | # 'level', metadata, | |
e920b968 | 864 | # autoload=True, autoload_with=db_conn.bind) |
690b51fa CAW |
865 | # assert set(level_table.c.keys()) == set( |
866 | # ['id', 'name', 'description']) | |
c7fa585b | 867 | # assert_col_type(level_table.c.id, VARCHAR) |
690b51fa | 868 | # assert level_table.c.id.primary_key is True |
c7fa585b CAW |
869 | # assert_col_type(level_table.c.name, VARCHAR) |
870 | # assert_col_type(level_table.c.description, VARCHAR) | |
690b51fa CAW |
871 | |
872 | # # Check the structure of the level_exits table | |
873 | # level_exit_table = Table( | |
874 | # 'level_exit', metadata, | |
e920b968 | 875 | # autoload=True, autoload_with=db_conn.bind) |
690b51fa CAW |
876 | # assert set(level_exit_table.c.keys()) == set( |
877 | # ['id', 'name', 'from_level', 'to_level']) | |
878 | # assert_col_type(level_exit_table.c.id, Integer) | |
c7fa585b CAW |
879 | # assert_col_type(level_exit_table.c.name, VARCHAR) |
880 | # assert_col_type(level_exit_table.c.from_level, VARCHAR) | |
690b51fa | 881 | # assert level_exit_table.c.from_level.nullable is False |
c7fa585b | 882 | # assert_col_type(level_exit_table.c.to_level, VARCHAR) |
690b51fa | 883 | |
d2506eeb | 884 | # pass |