Commenting out the migrations that don't exist yet
[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
28from mediagoblin.db.sql.base import GMGTableBase
e8e52b3a 29from mediagoblin.db.sql.util import MigrationManager, RegisterMigration
0f10058f
CAW
30
31
32# This one will get filled with local migrations
33FULL_MIGRATIONS = {}
34
35
36#######################################################
37# Migration set 1: Define initial models, no migrations
38#######################################################
39
40Base1 = declarative_base(cls=GMGTableBase)
41
42class 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
50class 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
58SET1_MODELS = [Creature1, Level1]
59
a5e03db6 60SET1_MIGRATIONS = {}
0f10058f
CAW
61
62#######################################################
63# Migration set 2: A few migrations and new model
64#######################################################
65
66Base2 = declarative_base(cls=GMGTableBase)
67
68class 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
76class 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
86class 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
93class 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
103SET2_MODELS = [Creature2, CreaturePower2, Level2, LevelExit2]
104
105
106@RegisterMigration(1, FULL_MIGRATIONS)
107def 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)
124def 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)
150def 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 204SET2_MIGRATIONS = copy.copy(FULL_MIGRATIONS)
0f10058f
CAW
205
206#######################################################
207# Migration set 3: Final migrations
208#######################################################
209
210Base3 = declarative_base(cls=GMGTableBase)
211
212class 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
220class 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
230class 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
237class 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
248SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3]
caed154a 249SET3_MIGRATIONS = FULL_MIGRATIONS
0f10058f
CAW
250
251
252@RegisterMigration(4, FULL_MIGRATIONS)
253def 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)
267def 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)
282def 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)
295def 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
324def _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
362def _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
438def _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 523class 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
535def 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
542def assert_col_type(column, this_class):
543 assert isinstance(column.type, this_class)
09e2c487
CAW
544
545
e8e52b3a
CAW
546def _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
553def 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