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