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 @RegisterMigration(8, FULL_MIGRATIONS
)
326 def creature_power_name_creature_unique(db_conn
):
328 Add a unique constraint to name and creature on creature_power.
330 We don't want multiple creature powers with the same name per creature!
332 # Note: We don't actually check to see if this constraint is set
333 # up because at present there's no way to do so in sqlalchemy :\
335 metadata
= MetaData(bind
=db_conn
.bind
)
337 creature_power
= Table(
338 'creature_power', metadata
,
339 autoload
=True, autoload_with
=db_conn
.bind
)
341 cons
= changeset
.constraint
.UniqueConstraint(
342 'name', 'creature', table
=creature_power
)
347 def _insert_migration1_objects(session
):
349 Test objects to insert for the first set of things
353 [Creature1(name
=u
'centipede',
356 Creature1(name
=u
'wolf',
359 # don't ask me what a wizardsnake is.
360 Creature1(name
=u
'wizardsnake',
366 [Level1(id=u
'necroplex',
367 name
=u
'The Necroplex',
368 description
=u
'A complex full of pure deathzone.',
370 u
'deathwell': u
'evilstorm',
371 u
'portal': u
'central_park'}),
372 Level1(id=u
'evilstorm',
374 description
=u
'A storm full of pure evil.',
375 exits
={}), # you can't escape the evilstorm
376 Level1(id=u
'central_park',
377 name
=u
'Central Park, NY, NY',
378 description
=u
"New York's friendly Central Park.",
380 u
'portal': u
'necroplex'})])
385 def _insert_migration2_objects(session
):
387 Test objects to insert for the second set of things
400 description
=u
"A blast of icy breath!",
404 description
=u
"A frightening stare, for sure!",
411 name
=u
'death_rattle',
412 description
=u
'A rattle... of DEATH!',
415 name
=u
'sneaky_stare',
416 description
=u
"The sneakiest stare you've ever seen!",
419 name
=u
'slithery_smoke',
420 description
=u
"A blast of slithery, slithery smoke.",
423 name
=u
'treacherous_tremors',
424 description
=u
"The ground shakes beneath footed animals!",
429 [Level2(id=u
'necroplex',
430 name
=u
'The Necroplex',
431 description
=u
'A complex full of pure deathzone.'),
432 Level2(id=u
'evilstorm',
434 description
=u
'A storm full of pure evil.',
435 exits
=[]), # you can't escape the evilstorm
436 Level2(id=u
'central_park',
437 name
=u
'Central Park, NY, NY',
438 description
=u
"New York's friendly Central Park.")])
442 [LevelExit2(name
=u
'deathwell',
443 from_level
=u
'necroplex',
444 to_level
=u
'evilstorm'),
445 LevelExit2(name
=u
'portal',
446 from_level
=u
'necroplex',
447 to_level
=u
'central_park')])
449 # there are no evilstorm exits because there is no exit from the
454 [LevelExit2(name
=u
'portal',
455 from_level
=u
'central_park',
456 to_level
=u
'necroplex')])
461 def _insert_migration3_objects(session
):
463 Test objects to insert for the third set of things
476 description
=u
"A blast of icy breath!",
480 description
=u
"A frightening stare, for sure!",
487 name
=u
'death_rattle',
488 description
=u
'A rattle... of DEATH!',
491 name
=u
'sneaky_stare',
492 description
=u
"The sneakiest stare you've ever seen!",
495 name
=u
'slithery_smoke',
496 description
=u
"A blast of slithery, slithery smoke.",
499 name
=u
'treacherous_tremors',
500 description
=u
"The ground shakes beneath footed animals!",
502 # annnnnd one more to test a floating point hitpower
509 description
=u
'Smitten by holy wrath!',
514 [Level3(id=u
'necroplex',
515 name
=u
'The Necroplex',
516 description
=u
'A complex full of pure deathzone.'),
517 Level3(id=u
'evilstorm',
519 description
=u
'A storm full of pure evil.',
520 exits
=[]), # you can't escape the evilstorm
521 Level3(id=u
'central_park',
522 name
=u
'Central Park, NY, NY',
523 description
=u
"New York's friendly Central Park.")])
527 [LevelExit3(name
=u
'deathwell',
528 from_level
=u
'necroplex',
529 to_level
=u
'evilstorm'),
530 LevelExit3(name
=u
'portal',
531 from_level
=u
'necroplex',
532 to_level
=u
'central_park')])
534 # there are no evilstorm exits because there is no exit from the
539 [LevelExit3(name
=u
'portal',
540 from_level
=u
'central_park',
541 to_level
=u
'necroplex')])
546 def create_test_engine():
547 from sqlalchemy
import create_engine
548 engine
= create_engine('sqlite:///:memory:', echo
=False)
549 Session
= sessionmaker(bind
=engine
)
550 return engine
, Session
553 def assert_col_type(column
, this_class
):
554 assert isinstance(column
.type, this_class
)
557 def _get_level3_exits(session
, level
):
559 [(level_exit
.name
, level_exit
.to_level
)
561 session
.query(LevelExit3
).filter_by(from_level
=level
.id)])
564 def test_set1_to_set3():
565 # Create / connect to database
566 # ----------------------------
568 engine
, Session
= create_test_engine()
570 # Create tables by migrating on empty initial set
571 # -----------------------------------------------
573 printer
= CollectingPrinter()
574 migration_manager
= MigrationManager(
575 u
'__main__', SET1_MODELS
, SET1_MIGRATIONS
, Session(),
578 # Check latest migration and database current migration
579 assert migration_manager
.latest_migration
== 0
580 assert migration_manager
.database_current_migration
== None
582 result
= migration_manager
.init_or_migrate()
584 # Make sure output was "inited"
585 assert result
== u
'inited'
587 assert printer
.combined_string
== (
588 "-> Initializing main mediagoblin tables... done.\n")
589 # Check version in database
590 assert migration_manager
.latest_migration
== 0
591 assert migration_manager
.database_current_migration
== 0
593 # Install the initial set
594 # -----------------------
596 _insert_migration1_objects(Session())
598 # Try to "re-migrate" with same manager settings... nothing should happen
599 migration_manager
= MigrationManager(
600 u
'__main__', SET1_MODELS
, SET1_MIGRATIONS
, Session(),
602 assert migration_manager
.init_or_migrate() == None
604 # Check version in database
605 assert migration_manager
.latest_migration
== 0
606 assert migration_manager
.database_current_migration
== 0
608 # Sanity check a few things in the database...
609 metadata
= MetaData(bind
=engine
)
611 # Check the structure of the creature table
612 creature_table
= Table(
613 'creature', metadata
,
614 autoload
=True, autoload_with
=engine
)
615 assert set(creature_table
.c
.keys()) == set(
616 ['id', 'name', 'num_legs', 'is_demon'])
617 assert_col_type(creature_table
.c
.id, Integer
)
618 assert_col_type(creature_table
.c
.name
, VARCHAR
)
619 assert creature_table
.c
.name
.nullable
is False
620 #assert creature_table.c.name.index is True
621 #assert creature_table.c.name.unique is True
622 assert_col_type(creature_table
.c
.num_legs
, Integer
)
623 assert creature_table
.c
.num_legs
.nullable
is False
624 assert_col_type(creature_table
.c
.is_demon
, Boolean
)
626 # Check the structure of the level table
629 autoload
=True, autoload_with
=engine
)
630 assert set(level_table
.c
.keys()) == set(
631 ['id', 'name', 'description', 'exits'])
632 assert_col_type(level_table
.c
.id, VARCHAR
)
633 assert level_table
.c
.id.primary_key
is True
634 assert_col_type(level_table
.c
.name
, VARCHAR
)
635 assert_col_type(level_table
.c
.description
, VARCHAR
)
636 # Skipping exits... Not sure if we can detect pickletype, not a
637 # big deal regardless.
639 # Now check to see if stuff seems to be in there.
642 creature
= session
.query(Creature1
).filter_by(
643 name
=u
'centipede').one()
644 assert creature
.num_legs
== 100
645 assert creature
.is_demon
== False
647 creature
= session
.query(Creature1
).filter_by(
649 assert creature
.num_legs
== 4
650 assert creature
.is_demon
== False
652 creature
= session
.query(Creature1
).filter_by(
653 name
=u
'wizardsnake').one()
654 assert creature
.num_legs
== 0
655 assert creature
.is_demon
== True
657 level
= session
.query(Level1
).filter_by(
658 id=u
'necroplex').one()
659 assert level
.name
== u
'The Necroplex'
660 assert level
.description
== u
'A complex full of pure deathzone.'
661 assert level
.exits
== {
662 'deathwell': 'evilstorm',
663 'portal': 'central_park'}
665 level
= session
.query(Level1
).filter_by(
666 id=u
'evilstorm').one()
667 assert level
.name
== u
'Evil Storm'
668 assert level
.description
== u
'A storm full of pure evil.'
669 assert level
.exits
== {} # You still can't escape the evilstorm!
671 level
= session
.query(Level1
).filter_by(
672 id=u
'central_park').one()
673 assert level
.name
== u
'Central Park, NY, NY'
674 assert level
.description
== u
"New York's friendly Central Park."
675 assert level
.exits
== {
676 'portal': 'necroplex'}
678 # Create new migration manager, but make sure the db migration
679 # isn't said to be updated yet
680 printer
= CollectingPrinter()
681 migration_manager
= MigrationManager(
682 u
'__main__', SET3_MODELS
, SET3_MIGRATIONS
, Session(),
685 assert migration_manager
.latest_migration
== 8
686 assert migration_manager
.database_current_migration
== 0
689 result
= migration_manager
.init_or_migrate()
691 # Make sure result was "migrated"
692 assert result
== u
'migrated'
694 # TODO: Check output to user
695 assert printer
.combined_string
== """\
696 -> Updating main mediagoblin tables:
697 + Running migration 1, "creature_remove_is_demon"... done.
698 + Running migration 2, "creature_powers_new_table"... done.
699 + Running migration 3, "level_exits_new_table"... done.
700 + Running migration 4, "creature_num_legs_to_num_limbs"... done.
701 + Running migration 5, "level_exit_index_from_and_to_level"... done.
702 + Running migration 6, "creature_power_index_creature"... done.
703 + Running migration 7, "creature_power_hitpower_to_float"... done.
704 + Running migration 8, "creature_power_name_creature_unique"... done.
707 # Make sure version matches expected
708 migration_manager
= MigrationManager(
709 u
'__main__', SET3_MODELS
, SET3_MIGRATIONS
, Session(),
711 assert migration_manager
.latest_migration
== 8
712 assert migration_manager
.database_current_migration
== 8
714 # Check all things in database match expected
716 # Check the creature table
717 metadata
= MetaData(bind
=engine
)
718 creature_table
= Table(
719 'creature', metadata
,
720 autoload
=True, autoload_with
=engine
)
721 # assert set(creature_table.c.keys()) == set(
722 # ['id', 'name', 'num_limbs'])
723 assert set(creature_table
.c
.keys()) == set(
724 [u
'id', 'name', u
'num_limbs', u
'is_demon'])
725 assert_col_type(creature_table
.c
.id, Integer
)
726 assert_col_type(creature_table
.c
.name
, VARCHAR
)
727 assert creature_table
.c
.name
.nullable
is False
728 #assert creature_table.c.name.index is True
729 #assert creature_table.c.name.unique is True
730 assert_col_type(creature_table
.c
.num_limbs
, Integer
)
731 assert creature_table
.c
.num_limbs
.nullable
is False
733 # Check the CreaturePower table
734 creature_power_table
= Table(
735 'creature_power', metadata
,
736 autoload
=True, autoload_with
=engine
)
737 assert set(creature_power_table
.c
.keys()) == set(
738 ['id', 'creature', 'name', 'description', 'hitpower'])
739 assert_col_type(creature_power_table
.c
.id, Integer
)
740 assert_col_type(creature_power_table
.c
.creature
, Integer
)
741 assert creature_power_table
.c
.creature
.nullable
is False
742 assert_col_type(creature_power_table
.c
.name
, VARCHAR
)
743 assert_col_type(creature_power_table
.c
.description
, VARCHAR
)
744 assert_col_type(creature_power_table
.c
.hitpower
, Float
)
745 assert creature_power_table
.c
.hitpower
.nullable
is False
747 # Check the structure of the level table
750 autoload
=True, autoload_with
=engine
)
751 assert set(level_table
.c
.keys()) == set(
752 ['id', 'name', 'description'])
753 assert_col_type(level_table
.c
.id, VARCHAR
)
754 assert level_table
.c
.id.primary_key
is True
755 assert_col_type(level_table
.c
.name
, VARCHAR
)
756 assert_col_type(level_table
.c
.description
, VARCHAR
)
758 # Check the structure of the level_exits table
759 level_exit_table
= Table(
760 'level_exit', metadata
,
761 autoload
=True, autoload_with
=engine
)
762 assert set(level_exit_table
.c
.keys()) == set(
763 ['id', 'name', 'from_level', 'to_level'])
764 assert_col_type(level_exit_table
.c
.id, Integer
)
765 assert_col_type(level_exit_table
.c
.name
, VARCHAR
)
766 assert_col_type(level_exit_table
.c
.from_level
, VARCHAR
)
767 assert level_exit_table
.c
.from_level
.nullable
is False
768 #assert level_exit_table.c.from_level.index is True
769 assert_col_type(level_exit_table
.c
.to_level
, VARCHAR
)
770 assert level_exit_table
.c
.to_level
.nullable
is False
771 #assert level_exit_table.c.to_level.index is True
773 # Now check to see if stuff seems to be in there.
775 creature
= session
.query(Creature3
).filter_by(
776 name
=u
'centipede').one()
777 assert creature
.num_limbs
== 100.0
778 assert creature
.magical_powers
== []
780 creature
= session
.query(Creature3
).filter_by(
782 assert creature
.num_limbs
== 4.0
783 assert creature
.magical_powers
== []
785 creature
= session
.query(Creature3
).filter_by(
786 name
=u
'wizardsnake').one()
787 assert creature
.num_limbs
== 0.0
788 assert creature
.magical_powers
== []
790 level
= session
.query(Level3
).filter_by(
791 id=u
'necroplex').one()
792 assert level
.name
== u
'The Necroplex'
793 assert level
.description
== u
'A complex full of pure deathzone.'
794 level_exits
= _get_level3_exits(session
, level
)
795 assert level_exits
== {
796 u
'deathwell': u
'evilstorm',
797 u
'portal': u
'central_park'}
799 level
= session
.query(Level3
).filter_by(
800 id=u
'evilstorm').one()
801 assert level
.name
== u
'Evil Storm'
802 assert level
.description
== u
'A storm full of pure evil.'
803 level_exits
= _get_level3_exits(session
, level
)
804 assert level_exits
== {} # You still can't escape the evilstorm!
806 level
= session
.query(Level3
).filter_by(
807 id=u
'central_park').one()
808 assert level
.name
== u
'Central Park, NY, NY'
809 assert level
.description
== u
"New York's friendly Central Park."
810 level_exits
= _get_level3_exits(session
, level
)
811 assert level_exits
== {
812 'portal': 'necroplex'}
815 #def test_set2_to_set3():
816 # Create / connect to database
817 # Create tables by migrating on empty initial set
819 # Install the initial set
820 # Check version in database
821 # Sanity check a few things in the database
824 # Make sure version matches expected
825 # Check all things in database match expected
829 #def test_set1_to_set2_to_set3():
830 # Create / connect to database
831 # Create tables by migrating on empty initial set
833 # Install the initial set
834 # Check version in database
835 # Sanity check a few things in the database
838 # Make sure version matches expected
839 # Check all things in database match expected
842 # Make sure version matches expected again
843 # Check all things in database match expected again
846 # creature_table = Table(
847 # 'creature', metadata,
848 # autoload=True, autoload_with=db_conn.bind)
849 # assert set(creature_table.c.keys()) == set(
850 # ['id', 'name', 'num_legs'])
851 # assert_col_type(creature_table.c.id, Integer)
852 # assert_col_type(creature_table.c.name, VARCHAR)
853 # assert creature_table.c.name.nullable is False
854 # assert creature_table.c.name.index is True
855 # assert creature_table.c.name.unique is True
856 # assert_col_type(creature_table.c.num_legs, Integer)
857 # assert creature_table.c.num_legs.nullable is False
859 # # Check the CreaturePower table
860 # creature_power_table = Table(
861 # 'creature_power', metadata,
862 # autoload=True, autoload_with=db_conn.bind)
863 # assert set(creature_power_table.c.keys()) == set(
864 # ['id', 'creature', 'name', 'description', 'hitpower'])
865 # assert_col_type(creature_power_table.c.id, Integer)
866 # assert_col_type(creature_power_table.c.creature, Integer)
867 # assert creature_power_table.c.creature.nullable is False
868 # assert_col_type(creature_power_table.c.name, VARCHAR)
869 # assert_col_type(creature_power_table.c.description, VARCHAR)
870 # assert_col_type(creature_power_table.c.hitpower, Integer)
871 # assert creature_power_table.c.hitpower.nullable is False
873 # # Check the structure of the level table
874 # level_table = Table(
876 # autoload=True, autoload_with=db_conn.bind)
877 # assert set(level_table.c.keys()) == set(
878 # ['id', 'name', 'description'])
879 # assert_col_type(level_table.c.id, VARCHAR)
880 # assert level_table.c.id.primary_key is True
881 # assert_col_type(level_table.c.name, VARCHAR)
882 # assert_col_type(level_table.c.description, VARCHAR)
884 # # Check the structure of the level_exits table
885 # level_exit_table = Table(
886 # 'level_exit', metadata,
887 # autoload=True, autoload_with=db_conn.bind)
888 # assert set(level_exit_table.c.keys()) == set(
889 # ['id', 'name', 'from_level', 'to_level'])
890 # assert_col_type(level_exit_table.c.id, Integer)
891 # assert_col_type(level_exit_table.c.name, VARCHAR)
892 # assert_col_type(level_exit_table.c.from_level, VARCHAR)
893 # assert level_exit_table.c.from_level.nullable is False
894 # assert_col_type(level_exit_table.c.to_level, VARCHAR)