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