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
.sql
.base
import GMGTableBase
29 from mediagoblin
.db
.sql
.util
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
]
63 #######################################################
64 # Migration set 2: A few migrations and new model
65 #######################################################
67 Base2
= declarative_base(cls
=GMGTableBase
)
69 class Creature2(Base2
):
70 __tablename__
= "creature"
72 id = Column(Integer
, primary_key
=True)
73 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
74 num_legs
= Column(Integer
, nullable
=False)
75 magical_powers
= relationship("CreaturePower2")
77 class CreaturePower2(Base2
):
78 __tablename__
= "creature_power"
80 id = Column(Integer
, primary_key
=True)
82 Integer
, ForeignKey('creature.id'), nullable
=False)
83 name
= Column(Unicode
)
84 description
= Column(Unicode
)
85 hitpower
= Column(Integer
, nullable
=False)
88 __tablename__
= "level"
90 id = Column(Unicode
, primary_key
=True)
91 name
= Column(Unicode
)
92 description
= Column(Unicode
)
94 class LevelExit2(Base2
):
95 __tablename__
= "level_exit"
97 id = Column(Integer
, primary_key
=True)
98 name
= Column(Unicode
)
100 Unicode
, ForeignKey('level.id'), nullable
=False)
102 Unicode
, ForeignKey('level.id'), nullable
=False)
104 SET2_MODELS
= [Creature2
, CreaturePower2
, Level2
, LevelExit2
]
107 @RegisterMigration(1, FULL_MIGRATIONS
)
108 def creature_remove_is_demon(db_conn
):
110 Remove the is_demon field from the creature model. We don't need
113 # :( Commented out 'cuz of:
114 # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242
116 # metadata = MetaData(bind=db_conn.bind)
117 # creature_table = Table(
118 # 'creature', metadata,
119 # autoload=True, autoload_with=db_conn.bind)
120 # creature_table.drop_column('is_demon')
124 @RegisterMigration(2, FULL_MIGRATIONS
)
125 def creature_powers_new_table(db_conn
):
127 Add a new table for creature powers. Nothing needs to go in it
128 yet though as there wasn't anything that previously held this
131 metadata
= MetaData(bind
=db_conn
.bind
)
133 # We have to access the creature table so sqlalchemy can make the
134 # foreign key relationship
135 creature_table
= Table(
136 'creature', metadata
,
137 autoload
=True, autoload_with
=db_conn
.bind
)
139 creature_powers
= Table(
140 'creature_power', metadata
,
141 Column('id', Integer
, primary_key
=True),
143 Integer
, ForeignKey('creature.id'), nullable
=False),
144 Column('name', Unicode
),
145 Column('description', Unicode
),
146 Column('hitpower', Integer
, nullable
=False))
147 metadata
.create_all(db_conn
.bind
)
150 @RegisterMigration(3, FULL_MIGRATIONS
)
151 def level_exits_new_table(db_conn
):
153 Make a new table for level exits and move the previously pickled
154 stuff over to here (then drop the old unneeded table)
156 # First, create the table
157 # -----------------------
158 metadata
= MetaData(bind
=db_conn
.bind
)
160 # Minimal representation of level table.
161 # Not auto-introspecting here because of pickle table. I'm not
162 # sure sqlalchemy can auto-introspect pickle columns.
165 Column('id', Unicode
, primary_key
=True),
166 Column('name', Unicode
),
167 Column('description', Unicode
),
168 Column('exits', PickleType
))
171 'level_exit', metadata
,
172 Column('id', Integer
, primary_key
=True),
173 Column('name', Unicode
),
175 Unicode
, ForeignKey('level.id'), nullable
=False),
177 Unicode
, ForeignKey('level.id'), nullable
=False))
178 metadata
.create_all(db_conn
.bind
)
180 # And now, convert all the old exit pickles to new level exits
181 # ------------------------------------------------------------
183 # query over and insert
184 result
= db_conn
.execute(
185 select([levels
], levels
.c
.exits
!=None))
189 for exit_name
, to_level
in level
['exits'].iteritems():
190 # Insert the level exit
192 level_exits
.insert().values(
197 # Finally, drop the old level exits pickle table
198 # ----------------------------------------------
199 levels
.drop_column('exits')
202 # A hack! At this point we freeze-fame and get just a partial list of
205 SET2_MIGRATIONS
= copy
.copy(FULL_MIGRATIONS
)
207 #######################################################
208 # Migration set 3: Final migrations
209 #######################################################
211 Base3
= declarative_base(cls
=GMGTableBase
)
213 class Creature3(Base3
):
214 __tablename__
= "creature"
216 id = Column(Integer
, primary_key
=True)
217 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
218 num_limbs
= Column(Integer
, nullable
=False)
219 magical_powers
= relationship("CreaturePower3")
221 class CreaturePower3(Base3
):
222 __tablename__
= "creature_power"
224 id = Column(Integer
, primary_key
=True)
226 Integer
, ForeignKey('creature.id'), nullable
=False, index
=True)
227 name
= Column(Unicode
)
228 description
= Column(Unicode
)
229 hitpower
= Column(Float
, nullable
=False)
232 __tablename__
= "level"
234 id = Column(Unicode
, primary_key
=True)
235 name
= Column(Unicode
)
236 description
= Column(Unicode
)
238 class LevelExit3(Base3
):
239 __tablename__
= "level_exit"
241 id = Column(Integer
, primary_key
=True)
242 name
= Column(Unicode
)
244 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
246 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
249 SET3_MODELS
= [Creature3
, CreaturePower3
, Level3
, LevelExit3
]
250 SET3_MIGRATIONS
= FULL_MIGRATIONS
253 @RegisterMigration(4, FULL_MIGRATIONS
)
254 def creature_num_legs_to_num_limbs(db_conn
):
256 Turns out we're tracking all sorts of limbs, not "legs"
257 specifically. Humans would be 4 here, for instance. So we
260 metadata
= MetaData(bind
=db_conn
.bind
)
261 creature_table
= Table(
262 'creature', metadata
,
263 autoload
=True, autoload_with
=db_conn
.bind
)
264 creature_table
.c
.num_legs
.alter(name
=u
"num_limbs")
267 @RegisterMigration(5, FULL_MIGRATIONS
)
268 def level_exit_index_from_and_to_level(db_conn
):
270 Index the from and to levels of the level exit table.
272 metadata
= MetaData(bind
=db_conn
.bind
)
274 'level_exit', metadata
,
275 autoload
=True, autoload_with
=db_conn
.bind
)
276 Index('ix_level_exit_from_level',
277 level_exit
.c
.from_level
).create(db_conn
.bind
)
278 Index('ix_level_exit_to_level',
279 level_exit
.c
.to_level
).create(db_conn
.bind
)
282 @RegisterMigration(6, FULL_MIGRATIONS
)
283 def creature_power_index_creature(db_conn
):
285 Index our foreign key relationship to the creatures
287 metadata
= MetaData(bind
=db_conn
.bind
)
288 creature_power
= Table(
289 'creature_power', metadata
,
290 autoload
=True, autoload_with
=db_conn
.bind
)
291 Index('ix_creature_power_creature',
292 creature_power
.c
.creature
).create(db_conn
.bind
)
295 @RegisterMigration(7, FULL_MIGRATIONS
)
296 def creature_power_hitpower_to_float(db_conn
):
298 Convert hitpower column on creature power table from integer to
301 Turns out we want super precise values of how much hitpower there
304 metadata
= MetaData(bind
=db_conn
.bind
)
306 # We have to access the creature table so sqlalchemy can make the
307 # foreign key relationship
308 creature_table
= Table(
309 'creature', metadata
,
310 autoload
=True, autoload_with
=db_conn
.bind
)
312 creature_power
= Table(
313 'creature_power', metadata
,
314 Column('id', Integer
, primary_key
=True),
315 Column('creature', Integer
,
316 ForeignKey('creature.id'), nullable
=False,
318 Column('name', Unicode
),
319 Column('description', Unicode
),
320 Column('hitpower', Integer
, nullable
=False))
322 creature_power
.c
.hitpower
.alter(type=Float
)
325 def _insert_migration1_objects(session
):
327 Test objects to insert for the first set of things
331 [Creature1(name
=u
'centipede',
334 Creature1(name
=u
'wolf',
337 # don't ask me what a wizardsnake is.
338 Creature1(name
=u
'wizardsnake',
344 [Level1(id=u
'necroplex',
345 name
=u
'The Necroplex',
346 description
=u
'A complex full of pure deathzone.',
348 u
'deathwell': u
'evilstorm',
349 u
'portal': u
'central_park'}),
350 Level1(id=u
'evilstorm',
352 description
=u
'A storm full of pure evil.',
353 exits
={}), # you can't escape the evilstorm
354 Level1(id=u
'central_park',
355 name
=u
'Central Park, NY, NY',
356 description
=u
"New York's friendly Central Park.",
358 u
'portal': u
'necroplex'})])
363 def _insert_migration2_objects(session
):
365 Test objects to insert for the second set of things
378 description
=u
"A blast of icy breath!",
382 description
=u
"A frightening stare, for sure!",
389 name
=u
'death_rattle',
390 description
=u
'A rattle... of DEATH!',
393 name
=u
'sneaky_stare',
394 description
=u
"The sneakiest stare you've ever seen!",
397 name
=u
'slithery_smoke',
398 description
=u
"A blast of slithery, slithery smoke.",
401 name
=u
'treacherous_tremors',
402 description
=u
"The ground shakes beneath footed animals!",
407 [Level2(id=u
'necroplex',
408 name
=u
'The Necroplex',
409 description
=u
'A complex full of pure deathzone.'),
410 Level2(id=u
'evilstorm',
412 description
=u
'A storm full of pure evil.',
413 exits
=[]), # you can't escape the evilstorm
414 Level2(id=u
'central_park',
415 name
=u
'Central Park, NY, NY',
416 description
=u
"New York's friendly Central Park.")])
420 [LevelExit2(name
=u
'deathwell',
421 from_level
=u
'necroplex',
422 to_level
=u
'evilstorm'),
423 LevelExit2(name
=u
'portal',
424 from_level
=u
'necroplex',
425 to_level
=u
'central_park')])
427 # there are no evilstorm exits because there is no exit from the
432 [LevelExit2(name
=u
'portal',
433 from_level
=u
'central_park',
434 to_level
=u
'necroplex')])
439 def _insert_migration3_objects(session
):
441 Test objects to insert for the third set of things
454 description
=u
"A blast of icy breath!",
458 description
=u
"A frightening stare, for sure!",
465 name
=u
'death_rattle',
466 description
=u
'A rattle... of DEATH!',
469 name
=u
'sneaky_stare',
470 description
=u
"The sneakiest stare you've ever seen!",
473 name
=u
'slithery_smoke',
474 description
=u
"A blast of slithery, slithery smoke.",
477 name
=u
'treacherous_tremors',
478 description
=u
"The ground shakes beneath footed animals!",
480 # annnnnd one more to test a floating point hitpower
487 description
=u
'Smitten by holy wrath!',
492 [Level3(id=u
'necroplex',
493 name
=u
'The Necroplex',
494 description
=u
'A complex full of pure deathzone.'),
495 Level3(id=u
'evilstorm',
497 description
=u
'A storm full of pure evil.',
498 exits
=[]), # you can't escape the evilstorm
499 Level3(id=u
'central_park',
500 name
=u
'Central Park, NY, NY',
501 description
=u
"New York's friendly Central Park.")])
505 [LevelExit3(name
=u
'deathwell',
506 from_level
=u
'necroplex',
507 to_level
=u
'evilstorm'),
508 LevelExit3(name
=u
'portal',
509 from_level
=u
'necroplex',
510 to_level
=u
'central_park')])
512 # there are no evilstorm exits because there is no exit from the
517 [LevelExit3(name
=u
'portal',
518 from_level
=u
'central_park',
519 to_level
=u
'necroplex')])
524 def create_test_engine():
525 from sqlalchemy
import create_engine
526 engine
= create_engine('sqlite:///:memory:', echo
=False)
527 Session
= sessionmaker(bind
=engine
)
528 return engine
, Session
531 def assert_col_type(column
, this_class
):
532 assert isinstance(column
.type, this_class
)
535 def _get_level3_exits(session
, level
):
537 [(level_exit
.name
, level_exit
.to_level
)
539 session
.query(LevelExit3
).filter_by(from_level
=level
.id)])
542 def test_set1_to_set3():
543 # Create / connect to database
544 # ----------------------------
546 engine
, Session
= create_test_engine()
548 # Create tables by migrating on empty initial set
549 # -----------------------------------------------
551 printer
= CollectingPrinter()
552 migration_manager
= MigrationManager(
553 u
'__main__', SET1_MODELS
, SET1_MIGRATIONS
, Session(),
556 # Check latest migration and database current migration
557 assert migration_manager
.latest_migration
== 0
558 assert migration_manager
.database_current_migration
== None
560 result
= migration_manager
.init_or_migrate()
562 # Make sure output was "inited"
563 assert result
== u
'inited'
565 assert printer
.combined_string
== (
566 "-> Initializing main mediagoblin tables... done.\n")
567 # Check version in database
568 assert migration_manager
.latest_migration
== 0
569 assert migration_manager
.database_current_migration
== 0
571 # Install the initial set
572 # -----------------------
574 _insert_migration1_objects(Session())
576 # Try to "re-migrate" with same manager settings... nothing should happen
577 migration_manager
= MigrationManager(
578 u
'__main__', SET1_MODELS
, SET1_MIGRATIONS
, Session(),
580 assert migration_manager
.init_or_migrate() == None
582 # Check version in database
583 assert migration_manager
.latest_migration
== 0
584 assert migration_manager
.database_current_migration
== 0
586 # Sanity check a few things in the database...
587 metadata
= MetaData(bind
=engine
)
589 # Check the structure of the creature table
590 creature_table
= Table(
591 'creature', metadata
,
592 autoload
=True, autoload_with
=engine
)
593 assert set(creature_table
.c
.keys()) == set(
594 ['id', 'name', 'num_legs', 'is_demon'])
595 assert_col_type(creature_table
.c
.id, Integer
)
596 assert_col_type(creature_table
.c
.name
, VARCHAR
)
597 assert creature_table
.c
.name
.nullable
is False
598 #assert creature_table.c.name.index is True
599 #assert creature_table.c.name.unique is True
600 assert_col_type(creature_table
.c
.num_legs
, Integer
)
601 assert creature_table
.c
.num_legs
.nullable
is False
602 assert_col_type(creature_table
.c
.is_demon
, Boolean
)
604 # Check the structure of the level table
607 autoload
=True, autoload_with
=engine
)
608 assert set(level_table
.c
.keys()) == set(
609 ['id', 'name', 'description', 'exits'])
610 assert_col_type(level_table
.c
.id, VARCHAR
)
611 assert level_table
.c
.id.primary_key
is True
612 assert_col_type(level_table
.c
.name
, VARCHAR
)
613 assert_col_type(level_table
.c
.description
, VARCHAR
)
614 # Skipping exits... Not sure if we can detect pickletype, not a
615 # big deal regardless.
617 # Now check to see if stuff seems to be in there.
620 creature
= session
.query(Creature1
).filter_by(
621 name
=u
'centipede').one()
622 assert creature
.num_legs
== 100
623 assert creature
.is_demon
== False
625 creature
= session
.query(Creature1
).filter_by(
627 assert creature
.num_legs
== 4
628 assert creature
.is_demon
== False
630 creature
= session
.query(Creature1
).filter_by(
631 name
=u
'wizardsnake').one()
632 assert creature
.num_legs
== 0
633 assert creature
.is_demon
== True
635 level
= session
.query(Level1
).filter_by(
636 id=u
'necroplex').one()
637 assert level
.name
== u
'The Necroplex'
638 assert level
.description
== u
'A complex full of pure deathzone.'
639 assert level
.exits
== {
640 'deathwell': 'evilstorm',
641 'portal': 'central_park'}
643 level
= session
.query(Level1
).filter_by(
644 id=u
'evilstorm').one()
645 assert level
.name
== u
'Evil Storm'
646 assert level
.description
== u
'A storm full of pure evil.'
647 assert level
.exits
== {} # You still can't escape the evilstorm!
649 level
= session
.query(Level1
).filter_by(
650 id=u
'central_park').one()
651 assert level
.name
== u
'Central Park, NY, NY'
652 assert level
.description
== u
"New York's friendly Central Park."
653 assert level
.exits
== {
654 'portal': 'necroplex'}
656 # Create new migration manager, but make sure the db migration
657 # isn't said to be updated yet
658 printer
= CollectingPrinter()
659 migration_manager
= MigrationManager(
660 u
'__main__', SET3_MODELS
, SET3_MIGRATIONS
, Session(),
663 assert migration_manager
.latest_migration
== 7
664 assert migration_manager
.database_current_migration
== 0
667 result
= migration_manager
.init_or_migrate()
669 # Make sure result was "migrated"
670 assert result
== u
'migrated'
672 # TODO: Check output to user
673 assert printer
.combined_string
== """\
674 -> Updating main mediagoblin tables:
675 + Running migration 1, "creature_remove_is_demon"... done.
676 + Running migration 2, "creature_powers_new_table"... done.
677 + Running migration 3, "level_exits_new_table"... done.
678 + Running migration 4, "creature_num_legs_to_num_limbs"... done.
679 + Running migration 5, "level_exit_index_from_and_to_level"... done.
680 + Running migration 6, "creature_power_index_creature"... done.
681 + Running migration 7, "creature_power_hitpower_to_float"... done.
684 # Make sure version matches expected
685 migration_manager
= MigrationManager(
686 u
'__main__', SET3_MODELS
, SET3_MIGRATIONS
, Session(),
688 assert migration_manager
.latest_migration
== 7
689 assert migration_manager
.database_current_migration
== 7
691 # Check all things in database match expected
693 # Check the creature table
694 metadata
= MetaData(bind
=engine
)
695 creature_table
= Table(
696 'creature', metadata
,
697 autoload
=True, autoload_with
=engine
)
698 # assert set(creature_table.c.keys()) == set(
699 # ['id', 'name', 'num_limbs'])
700 assert set(creature_table
.c
.keys()) == set(
701 [u
'id', 'name', u
'num_limbs', u
'is_demon'])
702 assert_col_type(creature_table
.c
.id, Integer
)
703 assert_col_type(creature_table
.c
.name
, VARCHAR
)
704 assert creature_table
.c
.name
.nullable
is False
705 #assert creature_table.c.name.index is True
706 #assert creature_table.c.name.unique is True
707 assert_col_type(creature_table
.c
.num_limbs
, Integer
)
708 assert creature_table
.c
.num_limbs
.nullable
is False
710 # Check the CreaturePower table
711 creature_power_table
= Table(
712 'creature_power', metadata
,
713 autoload
=True, autoload_with
=engine
)
714 assert set(creature_power_table
.c
.keys()) == set(
715 ['id', 'creature', 'name', 'description', 'hitpower'])
716 assert_col_type(creature_power_table
.c
.id, Integer
)
717 assert_col_type(creature_power_table
.c
.creature
, Integer
)
718 assert creature_power_table
.c
.creature
.nullable
is False
719 assert_col_type(creature_power_table
.c
.name
, VARCHAR
)
720 assert_col_type(creature_power_table
.c
.description
, VARCHAR
)
721 assert_col_type(creature_power_table
.c
.hitpower
, Float
)
722 assert creature_power_table
.c
.hitpower
.nullable
is False
724 # Check the structure of the level table
727 autoload
=True, autoload_with
=engine
)
728 assert set(level_table
.c
.keys()) == set(
729 ['id', 'name', 'description'])
730 assert_col_type(level_table
.c
.id, VARCHAR
)
731 assert level_table
.c
.id.primary_key
is True
732 assert_col_type(level_table
.c
.name
, VARCHAR
)
733 assert_col_type(level_table
.c
.description
, VARCHAR
)
735 # Check the structure of the level_exits table
736 level_exit_table
= Table(
737 'level_exit', metadata
,
738 autoload
=True, autoload_with
=engine
)
739 assert set(level_exit_table
.c
.keys()) == set(
740 ['id', 'name', 'from_level', 'to_level'])
741 assert_col_type(level_exit_table
.c
.id, Integer
)
742 assert_col_type(level_exit_table
.c
.name
, VARCHAR
)
743 assert_col_type(level_exit_table
.c
.from_level
, VARCHAR
)
744 assert level_exit_table
.c
.from_level
.nullable
is False
745 #assert level_exit_table.c.from_level.index is True
746 assert_col_type(level_exit_table
.c
.to_level
, VARCHAR
)
747 assert level_exit_table
.c
.to_level
.nullable
is False
748 #assert level_exit_table.c.to_level.index is True
750 # Now check to see if stuff seems to be in there.
752 creature
= session
.query(Creature3
).filter_by(
753 name
=u
'centipede').one()
754 assert creature
.num_limbs
== 100.0
755 assert creature
.magical_powers
== []
757 creature
= session
.query(Creature3
).filter_by(
759 assert creature
.num_limbs
== 4.0
760 assert creature
.magical_powers
== []
762 creature
= session
.query(Creature3
).filter_by(
763 name
=u
'wizardsnake').one()
764 assert creature
.num_limbs
== 0.0
765 assert creature
.magical_powers
== []
767 level
= session
.query(Level3
).filter_by(
768 id=u
'necroplex').one()
769 assert level
.name
== u
'The Necroplex'
770 assert level
.description
== u
'A complex full of pure deathzone.'
771 level_exits
= _get_level3_exits(session
, level
)
772 assert level_exits
== {
773 u
'deathwell': u
'evilstorm',
774 u
'portal': u
'central_park'}
776 level
= session
.query(Level3
).filter_by(
777 id=u
'evilstorm').one()
778 assert level
.name
== u
'Evil Storm'
779 assert level
.description
== u
'A storm full of pure evil.'
780 level_exits
= _get_level3_exits(session
, level
)
781 assert level_exits
== {} # You still can't escape the evilstorm!
783 level
= session
.query(Level3
).filter_by(
784 id=u
'central_park').one()
785 assert level
.name
== u
'Central Park, NY, NY'
786 assert level
.description
== u
"New York's friendly Central Park."
787 level_exits
= _get_level3_exits(session
, level
)
788 assert level_exits
== {
789 'portal': 'necroplex'}
792 #def test_set2_to_set3():
793 # Create / connect to database
794 # Create tables by migrating on empty initial set
796 # Install the initial set
797 # Check version in database
798 # Sanity check a few things in the database
801 # Make sure version matches expected
802 # Check all things in database match expected
806 #def test_set1_to_set2_to_set3():
807 # Create / connect to database
808 # Create tables by migrating on empty initial set
810 # Install the initial set
811 # Check version in database
812 # Sanity check a few things in the database
815 # Make sure version matches expected
816 # Check all things in database match expected
819 # Make sure version matches expected again
820 # Check all things in database match expected again
823 # creature_table = Table(
824 # 'creature', metadata,
825 # autoload=True, autoload_with=db_conn.bind)
826 # assert set(creature_table.c.keys()) == set(
827 # ['id', 'name', 'num_legs'])
828 # assert_col_type(creature_table.c.id, Integer)
829 # assert_col_type(creature_table.c.name, VARCHAR)
830 # assert creature_table.c.name.nullable is False
831 # assert creature_table.c.name.index is True
832 # assert creature_table.c.name.unique is True
833 # assert_col_type(creature_table.c.num_legs, Integer)
834 # assert creature_table.c.num_legs.nullable is False
836 # # Check the CreaturePower table
837 # creature_power_table = Table(
838 # 'creature_power', metadata,
839 # autoload=True, autoload_with=db_conn.bind)
840 # assert set(creature_power_table.c.keys()) == set(
841 # ['id', 'creature', 'name', 'description', 'hitpower'])
842 # assert_col_type(creature_power_table.c.id, Integer)
843 # assert_col_type(creature_power_table.c.creature, Integer)
844 # assert creature_power_table.c.creature.nullable is False
845 # assert_col_type(creature_power_table.c.name, VARCHAR)
846 # assert_col_type(creature_power_table.c.description, VARCHAR)
847 # assert_col_type(creature_power_table.c.hitpower, Integer)
848 # assert creature_power_table.c.hitpower.nullable is False
850 # # Check the structure of the level table
851 # level_table = Table(
853 # autoload=True, autoload_with=db_conn.bind)
854 # assert set(level_table.c.keys()) == set(
855 # ['id', 'name', 'description'])
856 # assert_col_type(level_table.c.id, VARCHAR)
857 # assert level_table.c.id.primary_key is True
858 # assert_col_type(level_table.c.name, VARCHAR)
859 # assert_col_type(level_table.c.description, VARCHAR)
861 # # Check the structure of the level_exits table
862 # level_exit_table = Table(
863 # 'level_exit', metadata,
864 # autoload=True, autoload_with=db_conn.bind)
865 # assert set(level_exit_table.c.keys()) == set(
866 # ['id', 'name', 'from_level', 'to_level'])
867 # assert_col_type(level_exit_table.c.id, Integer)
868 # assert_col_type(level_exit_table.c.name, VARCHAR)
869 # assert_col_type(level_exit_table.c.from_level, VARCHAR)
870 # assert level_exit_table.c.from_level.nullable is False
871 # assert_col_type(level_exit_table.c.to_level, VARCHAR)