1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2012, 2012 MediaGoblin contributors. See AUTHORS.
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.
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.
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/>.
19 from sqlalchemy
import (
20 Table
, Column
, MetaData
, Index
,
21 Integer
, Float
, Unicode
, UnicodeText
, DateTime
, Boolean
,
22 ForeignKey
, UniqueConstraint
, PickleType
, VARCHAR
)
23 from sqlalchemy
.orm
import sessionmaker
, relationship
24 from sqlalchemy
.ext
.declarative
import declarative_base
25 from sqlalchemy
.sql
import select
, insert
26 from migrate
import changeset
28 from mediagoblin
.db
.base
import GMGTableBase
29 from mediagoblin
.db
.migration_tools
import MigrationManager
, RegisterMigration
30 from mediagoblin
.tools
.common
import CollectingPrinter
33 # This one will get filled with local migrations
37 #######################################################
38 # Migration set 1: Define initial models, no migrations
39 #######################################################
41 Base1
= declarative_base(cls
=GMGTableBase
)
43 class Creature1(Base1
):
44 __tablename__
= "creature"
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
)
52 __tablename__
= "level"
54 id = Column(Unicode
, primary_key
=True)
55 name
= Column(Unicode
)
56 description
= Column(Unicode
)
57 exits
= Column(PickleType
)
59 SET1_MODELS
= [Creature1
, Level1
]
61 FOUNDATIONS
= {Creature1
:[{'name':u
'goblin','num_legs':2,'is_demon':False},
62 {'name':u
'cerberus','num_legs':4,'is_demon':True}]
67 #######################################################
68 # Migration set 2: A few migrations and new model
69 #######################################################
71 Base2
= declarative_base(cls
=GMGTableBase
)
73 class Creature2(Base2
):
74 __tablename__
= "creature"
76 id = Column(Integer
, primary_key
=True)
77 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
78 num_legs
= Column(Integer
, nullable
=False)
79 magical_powers
= relationship("CreaturePower2")
81 class CreaturePower2(Base2
):
82 __tablename__
= "creature_power"
84 id = Column(Integer
, primary_key
=True)
86 Integer
, ForeignKey('creature.id'), nullable
=False)
87 name
= Column(Unicode
)
88 description
= Column(Unicode
)
89 hitpower
= Column(Integer
, nullable
=False)
92 __tablename__
= "level"
94 id = Column(Unicode
, primary_key
=True)
95 name
= Column(Unicode
)
96 description
= Column(Unicode
)
98 class LevelExit2(Base2
):
99 __tablename__
= "level_exit"
101 id = Column(Integer
, primary_key
=True)
102 name
= Column(Unicode
)
104 Unicode
, ForeignKey('level.id'), nullable
=False)
106 Unicode
, ForeignKey('level.id'), nullable
=False)
108 SET2_MODELS
= [Creature2
, CreaturePower2
, Level2
, LevelExit2
]
111 @RegisterMigration(1, FULL_MIGRATIONS
)
112 def creature_remove_is_demon(db_conn
):
114 Remove the is_demon field from the creature model. We don't need
117 # :( Commented out 'cuz of:
118 # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242
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')
128 @RegisterMigration(2, FULL_MIGRATIONS
)
129 def creature_powers_new_table(db_conn
):
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
135 metadata
= MetaData(bind
=db_conn
.bind
)
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
)
143 creature_powers
= Table(
144 'creature_power', metadata
,
145 Column('id', Integer
, primary_key
=True),
147 Integer
, ForeignKey('creature.id'), nullable
=False),
148 Column('name', Unicode
),
149 Column('description', Unicode
),
150 Column('hitpower', Integer
, nullable
=False))
151 metadata
.create_all(db_conn
.bind
)
154 @RegisterMigration(3, FULL_MIGRATIONS
)
155 def level_exits_new_table(db_conn
):
157 Make a new table for level exits and move the previously pickled
158 stuff over to here (then drop the old unneeded table)
160 # First, create the table
161 # -----------------------
162 metadata
= MetaData(bind
=db_conn
.bind
)
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.
169 Column('id', Unicode
, primary_key
=True),
170 Column('name', Unicode
),
171 Column('description', Unicode
),
172 Column('exits', PickleType
))
175 'level_exit', metadata
,
176 Column('id', Integer
, primary_key
=True),
177 Column('name', Unicode
),
179 Unicode
, ForeignKey('level.id'), nullable
=False),
181 Unicode
, ForeignKey('level.id'), nullable
=False))
182 metadata
.create_all(db_conn
.bind
)
184 # And now, convert all the old exit pickles to new level exits
185 # ------------------------------------------------------------
187 # query over and insert
188 result
= db_conn
.execute(
189 select([levels
], levels
.c
.exits
!=None))
193 for exit_name
, to_level
in level
['exits'].iteritems():
194 # Insert the level exit
196 level_exits
.insert().values(
201 # Finally, drop the old level exits pickle table
202 # ----------------------------------------------
203 levels
.drop_column('exits')
206 # A hack! At this point we freeze-fame and get just a partial list of
209 SET2_MIGRATIONS
= copy
.copy(FULL_MIGRATIONS
)
211 #######################################################
212 # Migration set 3: Final migrations
213 #######################################################
215 Base3
= declarative_base(cls
=GMGTableBase
)
217 class Creature3(Base3
):
218 __tablename__
= "creature"
220 id = Column(Integer
, primary_key
=True)
221 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
222 num_limbs
= Column(Integer
, nullable
=False)
223 magical_powers
= relationship("CreaturePower3")
225 class CreaturePower3(Base3
):
226 __tablename__
= "creature_power"
228 id = Column(Integer
, primary_key
=True)
230 Integer
, ForeignKey('creature.id'), nullable
=False, index
=True)
231 name
= Column(Unicode
)
232 description
= Column(Unicode
)
233 hitpower
= Column(Float
, nullable
=False)
236 __tablename__
= "level"
238 id = Column(Unicode
, primary_key
=True)
239 name
= Column(Unicode
)
240 description
= Column(Unicode
)
242 class LevelExit3(Base3
):
243 __tablename__
= "level_exit"
245 id = Column(Integer
, primary_key
=True)
246 name
= Column(Unicode
)
248 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
250 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
253 SET3_MODELS
= [Creature3
, CreaturePower3
, Level3
, LevelExit3
]
254 SET3_MIGRATIONS
= FULL_MIGRATIONS
257 @RegisterMigration(4, FULL_MIGRATIONS
)
258 def creature_num_legs_to_num_limbs(db_conn
):
260 Turns out we're tracking all sorts of limbs, not "legs"
261 specifically. Humans would be 4 here, for instance. So we
264 metadata
= MetaData(bind
=db_conn
.bind
)
265 creature_table
= Table(
266 'creature', metadata
,
267 autoload
=True, autoload_with
=db_conn
.bind
)
268 creature_table
.c
.num_legs
.alter(name
=u
"num_limbs")
271 @RegisterMigration(5, FULL_MIGRATIONS
)
272 def level_exit_index_from_and_to_level(db_conn
):
274 Index the from and to levels of the level exit table.
276 metadata
= MetaData(bind
=db_conn
.bind
)
278 'level_exit', metadata
,
279 autoload
=True, autoload_with
=db_conn
.bind
)
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
)
286 @RegisterMigration(6, FULL_MIGRATIONS
)
287 def creature_power_index_creature(db_conn
):
289 Index our foreign key relationship to the creatures
291 metadata
= MetaData(bind
=db_conn
.bind
)
292 creature_power
= Table(
293 'creature_power', metadata
,
294 autoload
=True, autoload_with
=db_conn
.bind
)
295 Index('ix_creature_power_creature',
296 creature_power
.c
.creature
).create(db_conn
.bind
)
299 @RegisterMigration(7, FULL_MIGRATIONS
)
300 def creature_power_hitpower_to_float(db_conn
):
302 Convert hitpower column on creature power table from integer to
305 Turns out we want super precise values of how much hitpower there
308 metadata
= MetaData(bind
=db_conn
.bind
)
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
)
316 creature_power
= Table(
317 'creature_power', metadata
,
318 Column('id', Integer
, primary_key
=True),
319 Column('creature', Integer
,
320 ForeignKey('creature.id'), nullable
=False,
322 Column('name', Unicode
),
323 Column('description', Unicode
),
324 Column('hitpower', Integer
, nullable
=False))
326 creature_power
.c
.hitpower
.alter(type=Float
)
329 @RegisterMigration(8, FULL_MIGRATIONS
)
330 def creature_power_name_creature_unique(db_conn
):
332 Add a unique constraint to name and creature on creature_power.
334 We don't want multiple creature powers with the same name per creature!
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 :\
339 metadata
= MetaData(bind
=db_conn
.bind
)
341 creature_power
= Table(
342 'creature_power', metadata
,
343 autoload
=True, autoload_with
=db_conn
.bind
)
345 cons
= changeset
.constraint
.UniqueConstraint(
346 'name', 'creature', table
=creature_power
)
351 def _insert_migration1_objects(session
):
353 Test objects to insert for the first set of things
357 [Creature1(name
=u
'centipede',
360 Creature1(name
=u
'wolf',
363 # don't ask me what a wizardsnake is.
364 Creature1(name
=u
'wizardsnake',
370 [Level1(id=u
'necroplex',
371 name
=u
'The Necroplex',
372 description
=u
'A complex full of pure deathzone.',
374 u
'deathwell': u
'evilstorm',
375 u
'portal': u
'central_park'}),
376 Level1(id=u
'evilstorm',
378 description
=u
'A storm full of pure evil.',
379 exits
={}), # you can't escape the evilstorm
380 Level1(id=u
'central_park',
381 name
=u
'Central Park, NY, NY',
382 description
=u
"New York's friendly Central Park.",
384 u
'portal': u
'necroplex'})])
389 def _insert_migration2_objects(session
):
391 Test objects to insert for the second set of things
404 description
=u
"A blast of icy breath!",
408 description
=u
"A frightening stare, for sure!",
415 name
=u
'death_rattle',
416 description
=u
'A rattle... of DEATH!',
419 name
=u
'sneaky_stare',
420 description
=u
"The sneakiest stare you've ever seen!",
423 name
=u
'slithery_smoke',
424 description
=u
"A blast of slithery, slithery smoke.",
427 name
=u
'treacherous_tremors',
428 description
=u
"The ground shakes beneath footed animals!",
433 [Level2(id=u
'necroplex',
434 name
=u
'The Necroplex',
435 description
=u
'A complex full of pure deathzone.'),
436 Level2(id=u
'evilstorm',
438 description
=u
'A storm full of pure evil.',
439 exits
=[]), # you can't escape the evilstorm
440 Level2(id=u
'central_park',
441 name
=u
'Central Park, NY, NY',
442 description
=u
"New York's friendly Central Park.")])
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')])
453 # there are no evilstorm exits because there is no exit from the
458 [LevelExit2(name
=u
'portal',
459 from_level
=u
'central_park',
460 to_level
=u
'necroplex')])
465 def _insert_migration3_objects(session
):
467 Test objects to insert for the third set of things
480 description
=u
"A blast of icy breath!",
484 description
=u
"A frightening stare, for sure!",
491 name
=u
'death_rattle',
492 description
=u
'A rattle... of DEATH!',
495 name
=u
'sneaky_stare',
496 description
=u
"The sneakiest stare you've ever seen!",
499 name
=u
'slithery_smoke',
500 description
=u
"A blast of slithery, slithery smoke.",
503 name
=u
'treacherous_tremors',
504 description
=u
"The ground shakes beneath footed animals!",
506 # annnnnd one more to test a floating point hitpower
513 description
=u
'Smitten by holy wrath!',
518 [Level3(id=u
'necroplex',
519 name
=u
'The Necroplex',
520 description
=u
'A complex full of pure deathzone.'),
521 Level3(id=u
'evilstorm',
523 description
=u
'A storm full of pure evil.',
524 exits
=[]), # you can't escape the evilstorm
525 Level3(id=u
'central_park',
526 name
=u
'Central Park, NY, NY',
527 description
=u
"New York's friendly Central Park.")])
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')])
538 # there are no evilstorm exits because there is no exit from the
543 [LevelExit3(name
=u
'portal',
544 from_level
=u
'central_park',
545 to_level
=u
'necroplex')])
549 def create_test_engine():
550 from sqlalchemy
import create_engine
551 engine
= create_engine('sqlite:///:memory:', echo
=False)
552 Session
= sessionmaker(bind
=engine
)
553 return engine
, Session
556 def assert_col_type(column
, this_class
):
557 assert isinstance(column
.type, this_class
)
560 def _get_level3_exits(session
, level
):
562 [(level_exit
.name
, level_exit
.to_level
)
564 session
.query(LevelExit3
).filter_by(from_level
=level
.id)])
567 def test_set1_to_set3():
568 # Create / connect to database
569 # ----------------------------
571 engine
, Session
= create_test_engine()
573 # Create tables by migrating on empty initial set
574 # -----------------------------------------------
576 printer
= CollectingPrinter()
577 migration_manager
= MigrationManager(
578 u
'__main__', SET1_MODELS
, FOUNDATIONS
, SET1_MIGRATIONS
, Session(),
581 # Check latest migration and database current migration
582 assert migration_manager
.latest_migration
== 0
583 assert migration_manager
.database_current_migration
== None
585 result
= migration_manager
.init_or_migrate()
587 # Make sure output was "inited"
588 assert result
== u
'inited'
590 assert printer
.combined_string
== (
591 "-> Initializing main mediagoblin tables... done.\n" + \
592 " + Laying foundations for Creature1 table\n" )
593 # Check version in database
594 assert migration_manager
.latest_migration
== 0
595 assert migration_manager
.database_current_migration
== 0
598 # Install the initial set
599 # -----------------------
601 _insert_migration1_objects(Session())
603 # Try to "re-migrate" with same manager settings... nothing should happen
604 migration_manager
= MigrationManager(
605 u
'__main__', SET1_MODELS
, FOUNDATIONS
, SET1_MIGRATIONS
,
607 assert migration_manager
.init_or_migrate() == None
609 # Check version in database
610 assert migration_manager
.latest_migration
== 0
611 assert migration_manager
.database_current_migration
== 0
613 # Sanity check a few things in the database...
614 metadata
= MetaData(bind
=engine
)
616 # Check the structure of the creature table
617 creature_table
= Table(
618 'creature', metadata
,
619 autoload
=True, autoload_with
=engine
)
620 assert set(creature_table
.c
.keys()) == set(
621 ['id', 'name', 'num_legs', 'is_demon'])
622 assert_col_type(creature_table
.c
.id, Integer
)
623 assert_col_type(creature_table
.c
.name
, VARCHAR
)
624 assert creature_table
.c
.name
.nullable
is False
625 #assert creature_table.c.name.index is True
626 #assert creature_table.c.name.unique is True
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
)
631 # Check the structure of the level table
634 autoload
=True, autoload_with
=engine
)
635 assert set(level_table
.c
.keys()) == set(
636 ['id', 'name', 'description', 'exits'])
637 assert_col_type(level_table
.c
.id, VARCHAR
)
638 assert level_table
.c
.id.primary_key
is True
639 assert_col_type(level_table
.c
.name
, VARCHAR
)
640 assert_col_type(level_table
.c
.description
, VARCHAR
)
641 # Skipping exits... Not sure if we can detect pickletype, not a
642 # big deal regardless.
644 # Now check to see if stuff seems to be in there.
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
653 creature
= session
.query(Creature1
).filter_by(
654 name
=u
'cerberus').one()
655 assert creature
.num_legs
== 4
656 assert creature
.is_demon
== True
659 # Check the creation of the inserted rows on the creature and levels tables
661 creature
= session
.query(Creature1
).filter_by(
662 name
=u
'centipede').one()
663 assert creature
.num_legs
== 100
664 assert creature
.is_demon
== False
666 creature
= session
.query(Creature1
).filter_by(
668 assert creature
.num_legs
== 4
669 assert creature
.is_demon
== False
671 creature
= session
.query(Creature1
).filter_by(
672 name
=u
'wizardsnake').one()
673 assert creature
.num_legs
== 0
674 assert creature
.is_demon
== True
676 level
= session
.query(Level1
).filter_by(
677 id=u
'necroplex').one()
678 assert level
.name
== u
'The Necroplex'
679 assert level
.description
== u
'A complex full of pure deathzone.'
680 assert level
.exits
== {
681 'deathwell': 'evilstorm',
682 'portal': 'central_park'}
684 level
= session
.query(Level1
).filter_by(
685 id=u
'evilstorm').one()
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!
690 level
= session
.query(Level1
).filter_by(
691 id=u
'central_park').one()
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'}
697 # Create new migration manager, but make sure the db migration
698 # isn't said to be updated yet
699 printer
= CollectingPrinter()
700 migration_manager
= MigrationManager(
701 u
'__main__', SET3_MODELS
, FOUNDATIONS
, SET3_MIGRATIONS
, Session(),
704 assert migration_manager
.latest_migration
== 8
705 assert migration_manager
.database_current_migration
== 0
708 result
= migration_manager
.init_or_migrate()
710 # Make sure result was "migrated"
711 assert result
== u
'migrated'
713 # TODO: Check output to user
714 assert printer
.combined_string
== """\
715 -> Updating main mediagoblin tables:
716 + Running migration 1, "creature_remove_is_demon"... done.
717 + Running migration 2, "creature_powers_new_table"... done.
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.
723 + Running migration 8, "creature_power_name_creature_unique"... done.
726 # Make sure version matches expected
727 migration_manager
= MigrationManager(
728 u
'__main__', SET3_MODELS
, FOUNDATIONS
, SET3_MIGRATIONS
, Session(),
730 assert migration_manager
.latest_migration
== 8
731 assert migration_manager
.database_current_migration
== 8
733 # Check all things in database match expected
735 # Check the creature table
736 metadata
= MetaData(bind
=engine
)
737 creature_table
= Table(
738 'creature', metadata
,
739 autoload
=True, autoload_with
=engine
)
740 # assert set(creature_table.c.keys()) == set(
741 # ['id', 'name', 'num_limbs'])
742 assert set(creature_table
.c
.keys()) == set(
743 [u
'id', 'name', u
'num_limbs', u
'is_demon'])
744 assert_col_type(creature_table
.c
.id, Integer
)
745 assert_col_type(creature_table
.c
.name
, VARCHAR
)
746 assert creature_table
.c
.name
.nullable
is False
747 #assert creature_table.c.name.index is True
748 #assert creature_table.c.name.unique is True
749 assert_col_type(creature_table
.c
.num_limbs
, Integer
)
750 assert creature_table
.c
.num_limbs
.nullable
is False
752 # Check the CreaturePower table
753 creature_power_table
= Table(
754 'creature_power', metadata
,
755 autoload
=True, autoload_with
=engine
)
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
761 assert_col_type(creature_power_table
.c
.name
, VARCHAR
)
762 assert_col_type(creature_power_table
.c
.description
, VARCHAR
)
763 assert_col_type(creature_power_table
.c
.hitpower
, Float
)
764 assert creature_power_table
.c
.hitpower
.nullable
is False
766 # Check the structure of the level table
769 autoload
=True, autoload_with
=engine
)
770 assert set(level_table
.c
.keys()) == set(
771 ['id', 'name', 'description'])
772 assert_col_type(level_table
.c
.id, VARCHAR
)
773 assert level_table
.c
.id.primary_key
is True
774 assert_col_type(level_table
.c
.name
, VARCHAR
)
775 assert_col_type(level_table
.c
.description
, VARCHAR
)
777 # Check the structure of the level_exits table
778 level_exit_table
= Table(
779 'level_exit', metadata
,
780 autoload
=True, autoload_with
=engine
)
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
)
784 assert_col_type(level_exit_table
.c
.name
, VARCHAR
)
785 assert_col_type(level_exit_table
.c
.from_level
, VARCHAR
)
786 assert level_exit_table
.c
.from_level
.nullable
is False
787 #assert level_exit_table.c.from_level.index is True
788 assert_col_type(level_exit_table
.c
.to_level
, VARCHAR
)
789 assert level_exit_table
.c
.to_level
.nullable
is False
790 #assert level_exit_table.c.to_level.index is True
792 # Now check to see if stuff seems to be in there.
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
802 # Then make sure the models have been migrated correctly
803 creature
= session
.query(Creature3
).filter_by(
804 name
=u
'centipede').one()
805 assert creature
.num_limbs
== 100.0
806 assert creature
.magical_powers
== []
808 creature
= session
.query(Creature3
).filter_by(
810 assert creature
.num_limbs
== 4.0
811 assert creature
.magical_powers
== []
813 creature
= session
.query(Creature3
).filter_by(
814 name
=u
'wizardsnake').one()
815 assert creature
.num_limbs
== 0.0
816 assert creature
.magical_powers
== []
818 level
= session
.query(Level3
).filter_by(
819 id=u
'necroplex').one()
820 assert level
.name
== u
'The Necroplex'
821 assert level
.description
== u
'A complex full of pure deathzone.'
822 level_exits
= _get_level3_exits(session
, level
)
823 assert level_exits
== {
824 u
'deathwell': u
'evilstorm',
825 u
'portal': u
'central_park'}
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!
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'}
843 #def test_set2_to_set3():
844 # Create / connect to database
845 # Create tables by migrating on empty initial set
847 # Install the initial set
848 # Check version in database
849 # Sanity check a few things in the database
852 # Make sure version matches expected
853 # Check all things in database match expected
857 #def test_set1_to_set2_to_set3():
858 # Create / connect to database
859 # Create tables by migrating on empty initial set
861 # Install the initial set
862 # Check version in database
863 # Sanity check a few things in the database
866 # Make sure version matches expected
867 # Check all things in database match expected
870 # Make sure version matches expected again
871 # Check all things in database match expected again
874 # creature_table = Table(
875 # 'creature', metadata,
876 # autoload=True, autoload_with=db_conn.bind)
877 # assert set(creature_table.c.keys()) == set(
878 # ['id', 'name', 'num_legs'])
879 # assert_col_type(creature_table.c.id, Integer)
880 # assert_col_type(creature_table.c.name, VARCHAR)
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
887 # # Check the CreaturePower table
888 # creature_power_table = Table(
889 # 'creature_power', metadata,
890 # autoload=True, autoload_with=db_conn.bind)
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
896 # assert_col_type(creature_power_table.c.name, VARCHAR)
897 # assert_col_type(creature_power_table.c.description, VARCHAR)
898 # assert_col_type(creature_power_table.c.hitpower, Integer)
899 # assert creature_power_table.c.hitpower.nullable is False
901 # # Check the structure of the level table
902 # level_table = Table(
904 # autoload=True, autoload_with=db_conn.bind)
905 # assert set(level_table.c.keys()) == set(
906 # ['id', 'name', 'description'])
907 # assert_col_type(level_table.c.id, VARCHAR)
908 # assert level_table.c.id.primary_key is True
909 # assert_col_type(level_table.c.name, VARCHAR)
910 # assert_col_type(level_table.c.description, VARCHAR)
912 # # Check the structure of the level_exits table
913 # level_exit_table = Table(
914 # 'level_exit', metadata,
915 # autoload=True, autoload_with=db_conn.bind)
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)
919 # assert_col_type(level_exit_table.c.name, VARCHAR)
920 # assert_col_type(level_exit_table.c.from_level, VARCHAR)
921 # assert level_exit_table.c.from_level.nullable is False
922 # assert_col_type(level_exit_table.c.to_level, VARCHAR)