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 SET1_FOUNDATIONS
= {Creature1
:[{'name':u
'goblin','num_legs':2,'is_demon':False},
62 {'name':u
'cerberus','num_legs':4,'is_demon':True}]}
66 #######################################################
67 # Migration set 2: A few migrations and new model
68 #######################################################
70 Base2
= declarative_base(cls
=GMGTableBase
)
72 class Creature2(Base2
):
73 __tablename__
= "creature"
75 id = Column(Integer
, primary_key
=True)
76 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
77 num_legs
= Column(Integer
, nullable
=False)
78 magical_powers
= relationship("CreaturePower2")
80 class CreaturePower2(Base2
):
81 __tablename__
= "creature_power"
83 id = Column(Integer
, primary_key
=True)
85 Integer
, ForeignKey('creature.id'), nullable
=False)
86 name
= Column(Unicode
)
87 description
= Column(Unicode
)
88 hitpower
= Column(Integer
, nullable
=False)
91 __tablename__
= "level"
93 id = Column(Unicode
, primary_key
=True)
94 name
= Column(Unicode
)
95 description
= Column(Unicode
)
97 class LevelExit2(Base2
):
98 __tablename__
= "level_exit"
100 id = Column(Integer
, primary_key
=True)
101 name
= Column(Unicode
)
103 Unicode
, ForeignKey('level.id'), nullable
=False)
105 Unicode
, ForeignKey('level.id'), nullable
=False)
107 SET2_MODELS
= [Creature2
, CreaturePower2
, Level2
, LevelExit2
]
110 @RegisterMigration(1, FULL_MIGRATIONS
)
111 def creature_remove_is_demon(db_conn
):
113 Remove the is_demon field from the creature model. We don't need
116 # :( Commented out 'cuz of:
117 # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242
119 # metadata = MetaData(bind=db_conn.bind)
120 # creature_table = Table(
121 # 'creature', metadata,
122 # autoload=True, autoload_with=db_conn.bind)
123 # creature_table.drop_column('is_demon')
127 @RegisterMigration(2, FULL_MIGRATIONS
)
128 def creature_powers_new_table(db_conn
):
130 Add a new table for creature powers. Nothing needs to go in it
131 yet though as there wasn't anything that previously held this
134 metadata
= MetaData(bind
=db_conn
.bind
)
136 # We have to access the creature table so sqlalchemy can make the
137 # foreign key relationship
138 creature_table
= Table(
139 'creature', metadata
,
140 autoload
=True, autoload_with
=db_conn
.bind
)
142 creature_powers
= Table(
143 'creature_power', metadata
,
144 Column('id', Integer
, primary_key
=True),
146 Integer
, ForeignKey('creature.id'), nullable
=False),
147 Column('name', Unicode
),
148 Column('description', Unicode
),
149 Column('hitpower', Integer
, nullable
=False))
150 metadata
.create_all(db_conn
.bind
)
153 @RegisterMigration(3, FULL_MIGRATIONS
)
154 def level_exits_new_table(db_conn
):
156 Make a new table for level exits and move the previously pickled
157 stuff over to here (then drop the old unneeded table)
159 # First, create the table
160 # -----------------------
161 metadata
= MetaData(bind
=db_conn
.bind
)
163 # Minimal representation of level table.
164 # Not auto-introspecting here because of pickle table. I'm not
165 # sure sqlalchemy can auto-introspect pickle columns.
168 Column('id', Unicode
, primary_key
=True),
169 Column('name', Unicode
),
170 Column('description', Unicode
),
171 Column('exits', PickleType
))
174 'level_exit', metadata
,
175 Column('id', Integer
, primary_key
=True),
176 Column('name', Unicode
),
178 Unicode
, ForeignKey('level.id'), nullable
=False),
180 Unicode
, ForeignKey('level.id'), nullable
=False))
181 metadata
.create_all(db_conn
.bind
)
183 # And now, convert all the old exit pickles to new level exits
184 # ------------------------------------------------------------
186 # query over and insert
187 result
= db_conn
.execute(
188 select([levels
], levels
.c
.exits
!=None))
192 for exit_name
, to_level
in level
['exits'].iteritems():
193 # Insert the level exit
195 level_exits
.insert().values(
200 # Finally, drop the old level exits pickle table
201 # ----------------------------------------------
202 levels
.drop_column('exits')
205 # A hack! At this point we freeze-fame and get just a partial list of
208 SET2_MIGRATIONS
= copy
.copy(FULL_MIGRATIONS
)
210 #######################################################
211 # Migration set 3: Final migrations
212 #######################################################
214 Base3
= declarative_base(cls
=GMGTableBase
)
216 class Creature3(Base3
):
217 __tablename__
= "creature"
219 id = Column(Integer
, primary_key
=True)
220 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
221 num_limbs
= Column(Integer
, nullable
=False)
222 magical_powers
= relationship("CreaturePower3")
224 class CreaturePower3(Base3
):
225 __tablename__
= "creature_power"
227 id = Column(Integer
, primary_key
=True)
229 Integer
, ForeignKey('creature.id'), nullable
=False, index
=True)
230 name
= Column(Unicode
)
231 description
= Column(Unicode
)
232 hitpower
= Column(Float
, nullable
=False)
235 __tablename__
= "level"
237 id = Column(Unicode
, primary_key
=True)
238 name
= Column(Unicode
)
239 description
= Column(Unicode
)
241 class LevelExit3(Base3
):
242 __tablename__
= "level_exit"
244 id = Column(Integer
, primary_key
=True)
245 name
= Column(Unicode
)
247 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
249 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
252 SET3_MODELS
= [Creature3
, CreaturePower3
, Level3
, LevelExit3
]
253 SET3_MIGRATIONS
= FULL_MIGRATIONS
256 @RegisterMigration(4, FULL_MIGRATIONS
)
257 def creature_num_legs_to_num_limbs(db_conn
):
259 Turns out we're tracking all sorts of limbs, not "legs"
260 specifically. Humans would be 4 here, for instance. So we
263 metadata
= MetaData(bind
=db_conn
.bind
)
264 creature_table
= Table(
265 'creature', metadata
,
266 autoload
=True, autoload_with
=db_conn
.bind
)
267 creature_table
.c
.num_legs
.alter(name
=u
"num_limbs")
270 @RegisterMigration(5, FULL_MIGRATIONS
)
271 def level_exit_index_from_and_to_level(db_conn
):
273 Index the from and to levels of the level exit table.
275 metadata
= MetaData(bind
=db_conn
.bind
)
277 'level_exit', metadata
,
278 autoload
=True, autoload_with
=db_conn
.bind
)
279 Index('ix_level_exit_from_level',
280 level_exit
.c
.from_level
).create(db_conn
.bind
)
281 Index('ix_level_exit_to_level',
282 level_exit
.c
.to_level
).create(db_conn
.bind
)
285 @RegisterMigration(6, FULL_MIGRATIONS
)
286 def creature_power_index_creature(db_conn
):
288 Index our foreign key relationship to the creatures
290 metadata
= MetaData(bind
=db_conn
.bind
)
291 creature_power
= Table(
292 'creature_power', metadata
,
293 autoload
=True, autoload_with
=db_conn
.bind
)
294 Index('ix_creature_power_creature',
295 creature_power
.c
.creature
).create(db_conn
.bind
)
298 @RegisterMigration(7, FULL_MIGRATIONS
)
299 def creature_power_hitpower_to_float(db_conn
):
301 Convert hitpower column on creature power table from integer to
304 Turns out we want super precise values of how much hitpower there
307 metadata
= MetaData(bind
=db_conn
.bind
)
309 # We have to access the creature table so sqlalchemy can make the
310 # foreign key relationship
311 creature_table
= Table(
312 'creature', metadata
,
313 autoload
=True, autoload_with
=db_conn
.bind
)
315 creature_power
= Table(
316 'creature_power', metadata
,
317 Column('id', Integer
, primary_key
=True),
318 Column('creature', Integer
,
319 ForeignKey('creature.id'), nullable
=False,
321 Column('name', Unicode
),
322 Column('description', Unicode
),
323 Column('hitpower', Integer
, nullable
=False))
325 creature_power
.c
.hitpower
.alter(type=Float
)
328 @RegisterMigration(8, FULL_MIGRATIONS
)
329 def creature_power_name_creature_unique(db_conn
):
331 Add a unique constraint to name and creature on creature_power.
333 We don't want multiple creature powers with the same name per creature!
335 # Note: We don't actually check to see if this constraint is set
336 # up because at present there's no way to do so in sqlalchemy :\
338 metadata
= MetaData(bind
=db_conn
.bind
)
340 creature_power
= Table(
341 'creature_power', metadata
,
342 autoload
=True, autoload_with
=db_conn
.bind
)
344 cons
= changeset
.constraint
.UniqueConstraint(
345 'name', 'creature', table
=creature_power
)
350 def _insert_migration1_objects(session
):
352 Test objects to insert for the first set of things
356 [Creature1(name
=u
'centipede',
359 Creature1(name
=u
'wolf',
362 # don't ask me what a wizardsnake is.
363 Creature1(name
=u
'wizardsnake',
369 [Level1(id=u
'necroplex',
370 name
=u
'The Necroplex',
371 description
=u
'A complex full of pure deathzone.',
373 u
'deathwell': u
'evilstorm',
374 u
'portal': u
'central_park'}),
375 Level1(id=u
'evilstorm',
377 description
=u
'A storm full of pure evil.',
378 exits
={}), # you can't escape the evilstorm
379 Level1(id=u
'central_park',
380 name
=u
'Central Park, NY, NY',
381 description
=u
"New York's friendly Central Park.",
383 u
'portal': u
'necroplex'})])
388 def _insert_migration2_objects(session
):
390 Test objects to insert for the second set of things
403 description
=u
"A blast of icy breath!",
407 description
=u
"A frightening stare, for sure!",
414 name
=u
'death_rattle',
415 description
=u
'A rattle... of DEATH!',
418 name
=u
'sneaky_stare',
419 description
=u
"The sneakiest stare you've ever seen!",
422 name
=u
'slithery_smoke',
423 description
=u
"A blast of slithery, slithery smoke.",
426 name
=u
'treacherous_tremors',
427 description
=u
"The ground shakes beneath footed animals!",
432 [Level2(id=u
'necroplex',
433 name
=u
'The Necroplex',
434 description
=u
'A complex full of pure deathzone.'),
435 Level2(id=u
'evilstorm',
437 description
=u
'A storm full of pure evil.',
438 exits
=[]), # you can't escape the evilstorm
439 Level2(id=u
'central_park',
440 name
=u
'Central Park, NY, NY',
441 description
=u
"New York's friendly Central Park.")])
445 [LevelExit2(name
=u
'deathwell',
446 from_level
=u
'necroplex',
447 to_level
=u
'evilstorm'),
448 LevelExit2(name
=u
'portal',
449 from_level
=u
'necroplex',
450 to_level
=u
'central_park')])
452 # there are no evilstorm exits because there is no exit from the
457 [LevelExit2(name
=u
'portal',
458 from_level
=u
'central_park',
459 to_level
=u
'necroplex')])
464 def _insert_migration3_objects(session
):
466 Test objects to insert for the third set of things
479 description
=u
"A blast of icy breath!",
483 description
=u
"A frightening stare, for sure!",
490 name
=u
'death_rattle',
491 description
=u
'A rattle... of DEATH!',
494 name
=u
'sneaky_stare',
495 description
=u
"The sneakiest stare you've ever seen!",
498 name
=u
'slithery_smoke',
499 description
=u
"A blast of slithery, slithery smoke.",
502 name
=u
'treacherous_tremors',
503 description
=u
"The ground shakes beneath footed animals!",
505 # annnnnd one more to test a floating point hitpower
512 description
=u
'Smitten by holy wrath!',
517 [Level3(id=u
'necroplex',
518 name
=u
'The Necroplex',
519 description
=u
'A complex full of pure deathzone.'),
520 Level3(id=u
'evilstorm',
522 description
=u
'A storm full of pure evil.',
523 exits
=[]), # you can't escape the evilstorm
524 Level3(id=u
'central_park',
525 name
=u
'Central Park, NY, NY',
526 description
=u
"New York's friendly Central Park.")])
530 [LevelExit3(name
=u
'deathwell',
531 from_level
=u
'necroplex',
532 to_level
=u
'evilstorm'),
533 LevelExit3(name
=u
'portal',
534 from_level
=u
'necroplex',
535 to_level
=u
'central_park')])
537 # there are no evilstorm exits because there is no exit from the
542 [LevelExit3(name
=u
'portal',
543 from_level
=u
'central_park',
544 to_level
=u
'necroplex')])
548 def create_test_engine():
549 from sqlalchemy
import create_engine
550 engine
= create_engine('sqlite:///:memory:', echo
=False)
551 Session
= sessionmaker(bind
=engine
)
552 return engine
, Session
555 def assert_col_type(column
, this_class
):
556 assert isinstance(column
.type, this_class
)
559 def _get_level3_exits(session
, level
):
561 [(level_exit
.name
, level_exit
.to_level
)
563 session
.query(LevelExit3
).filter_by(from_level
=level
.id)])
566 def test_set1_to_set3():
567 # Create / connect to database
568 # ----------------------------
570 engine
, Session
= create_test_engine()
572 # Create tables by migrating on empty initial set
573 # -----------------------------------------------
575 printer
= CollectingPrinter()
576 migration_manager
= MigrationManager(
577 u
'__main__', SET1_MODELS
, SET1_FOUNDATIONS
, SET1_MIGRATIONS
, Session(),
580 # Check latest migration and database current migration
581 assert migration_manager
.latest_migration
== 0
582 assert migration_manager
.database_current_migration
== None
584 result
= migration_manager
.init_or_migrate()
586 # Make sure output was "inited"
587 assert result
== u
'inited'
589 assert printer
.combined_string
== (
590 "-> Initializing main mediagoblin tables... done.\n" + \
591 " + Laying foundations for Creature1 table\n" )
592 # Check version in database
593 assert migration_manager
.latest_migration
== 0
594 assert migration_manager
.database_current_migration
== 0
596 # Install the initial set
597 # -----------------------
599 _insert_migration1_objects(Session())
601 # Try to "re-migrate" with same manager settings... nothing should happen
602 migration_manager
= MigrationManager(
603 u
'__main__', SET1_MODELS
, SET1_FOUNDATIONS
, SET1_MIGRATIONS
,
605 assert migration_manager
.init_or_migrate() == None
607 # Check version in database
608 assert migration_manager
.latest_migration
== 0
609 assert migration_manager
.database_current_migration
== 0
611 # Sanity check a few things in the database...
612 metadata
= MetaData(bind
=engine
)
614 # Check the structure of the creature table
615 creature_table
= Table(
616 'creature', metadata
,
617 autoload
=True, autoload_with
=engine
)
618 assert set(creature_table
.c
.keys()) == set(
619 ['id', 'name', 'num_legs', 'is_demon'])
620 assert_col_type(creature_table
.c
.id, Integer
)
621 assert_col_type(creature_table
.c
.name
, VARCHAR
)
622 assert creature_table
.c
.name
.nullable
is False
623 #assert creature_table.c.name.index is True
624 #assert creature_table.c.name.unique is True
625 assert_col_type(creature_table
.c
.num_legs
, Integer
)
626 assert creature_table
.c
.num_legs
.nullable
is False
627 assert_col_type(creature_table
.c
.is_demon
, Boolean
)
629 # Check the structure of the level table
632 autoload
=True, autoload_with
=engine
)
633 assert set(level_table
.c
.keys()) == set(
634 ['id', 'name', 'description', 'exits'])
635 assert_col_type(level_table
.c
.id, VARCHAR
)
636 assert level_table
.c
.id.primary_key
is True
637 assert_col_type(level_table
.c
.name
, VARCHAR
)
638 assert_col_type(level_table
.c
.description
, VARCHAR
)
639 # Skipping exits... Not sure if we can detect pickletype, not a
640 # big deal regardless.
642 # Now check to see if stuff seems to be in there.
645 creature
= session
.query(Creature1
).filter_by(
646 name
=u
'centipede').one()
647 assert creature
.num_legs
== 100
648 assert creature
.is_demon
== False
650 creature
= session
.query(Creature1
).filter_by(
652 assert creature
.num_legs
== 4
653 assert creature
.is_demon
== False
655 creature
= session
.query(Creature1
).filter_by(
656 name
=u
'wizardsnake').one()
657 assert creature
.num_legs
== 0
658 assert creature
.is_demon
== True
660 level
= session
.query(Level1
).filter_by(
661 id=u
'necroplex').one()
662 assert level
.name
== u
'The Necroplex'
663 assert level
.description
== u
'A complex full of pure deathzone.'
664 assert level
.exits
== {
665 'deathwell': 'evilstorm',
666 'portal': 'central_park'}
668 level
= session
.query(Level1
).filter_by(
669 id=u
'evilstorm').one()
670 assert level
.name
== u
'Evil Storm'
671 assert level
.description
== u
'A storm full of pure evil.'
672 assert level
.exits
== {} # You still can't escape the evilstorm!
674 level
= session
.query(Level1
).filter_by(
675 id=u
'central_park').one()
676 assert level
.name
== u
'Central Park, NY, NY'
677 assert level
.description
== u
"New York's friendly Central Park."
678 assert level
.exits
== {
679 'portal': 'necroplex'}
681 # Create new migration manager, but make sure the db migration
682 # isn't said to be updated yet
683 printer
= CollectingPrinter()
684 migration_manager
= MigrationManager(
685 u
'__main__', SET3_MODELS
, SET3_MIGRATIONS
, Session(),
688 assert migration_manager
.latest_migration
== 8
689 assert migration_manager
.database_current_migration
== 0
692 result
= migration_manager
.init_or_migrate()
694 # Make sure result was "migrated"
695 assert result
== u
'migrated'
697 # TODO: Check output to user
698 assert printer
.combined_string
== """\
699 -> Updating main mediagoblin tables:
700 + Running migration 1, "creature_remove_is_demon"... done.
701 + Running migration 2, "creature_powers_new_table"... done.
702 + Running migration 3, "level_exits_new_table"... done.
703 + Running migration 4, "creature_num_legs_to_num_limbs"... done.
704 + Running migration 5, "level_exit_index_from_and_to_level"... done.
705 + Running migration 6, "creature_power_index_creature"... done.
706 + Running migration 7, "creature_power_hitpower_to_float"... done.
707 + Running migration 8, "creature_power_name_creature_unique"... done.
710 # Make sure version matches expected
711 migration_manager
= MigrationManager(
712 u
'__main__', SET3_MODELS
, SET3_MIGRATIONS
, Session(),
714 assert migration_manager
.latest_migration
== 8
715 assert migration_manager
.database_current_migration
== 8
717 # Check all things in database match expected
719 # Check the creature table
720 metadata
= MetaData(bind
=engine
)
721 creature_table
= Table(
722 'creature', metadata
,
723 autoload
=True, autoload_with
=engine
)
724 # assert set(creature_table.c.keys()) == set(
725 # ['id', 'name', 'num_limbs'])
726 assert set(creature_table
.c
.keys()) == set(
727 [u
'id', 'name', u
'num_limbs', u
'is_demon'])
728 assert_col_type(creature_table
.c
.id, Integer
)
729 assert_col_type(creature_table
.c
.name
, VARCHAR
)
730 assert creature_table
.c
.name
.nullable
is False
731 #assert creature_table.c.name.index is True
732 #assert creature_table.c.name.unique is True
733 assert_col_type(creature_table
.c
.num_limbs
, Integer
)
734 assert creature_table
.c
.num_limbs
.nullable
is False
736 # Check the CreaturePower table
737 creature_power_table
= Table(
738 'creature_power', metadata
,
739 autoload
=True, autoload_with
=engine
)
740 assert set(creature_power_table
.c
.keys()) == set(
741 ['id', 'creature', 'name', 'description', 'hitpower'])
742 assert_col_type(creature_power_table
.c
.id, Integer
)
743 assert_col_type(creature_power_table
.c
.creature
, Integer
)
744 assert creature_power_table
.c
.creature
.nullable
is False
745 assert_col_type(creature_power_table
.c
.name
, VARCHAR
)
746 assert_col_type(creature_power_table
.c
.description
, VARCHAR
)
747 assert_col_type(creature_power_table
.c
.hitpower
, Float
)
748 assert creature_power_table
.c
.hitpower
.nullable
is False
750 # Check the structure of the level table
753 autoload
=True, autoload_with
=engine
)
754 assert set(level_table
.c
.keys()) == set(
755 ['id', 'name', 'description'])
756 assert_col_type(level_table
.c
.id, VARCHAR
)
757 assert level_table
.c
.id.primary_key
is True
758 assert_col_type(level_table
.c
.name
, VARCHAR
)
759 assert_col_type(level_table
.c
.description
, VARCHAR
)
761 # Check the structure of the level_exits table
762 level_exit_table
= Table(
763 'level_exit', metadata
,
764 autoload
=True, autoload_with
=engine
)
765 assert set(level_exit_table
.c
.keys()) == set(
766 ['id', 'name', 'from_level', 'to_level'])
767 assert_col_type(level_exit_table
.c
.id, Integer
)
768 assert_col_type(level_exit_table
.c
.name
, VARCHAR
)
769 assert_col_type(level_exit_table
.c
.from_level
, VARCHAR
)
770 assert level_exit_table
.c
.from_level
.nullable
is False
771 #assert level_exit_table.c.from_level.index is True
772 assert_col_type(level_exit_table
.c
.to_level
, VARCHAR
)
773 assert level_exit_table
.c
.to_level
.nullable
is False
774 #assert level_exit_table.c.to_level.index is True
776 # Now check to see if stuff seems to be in there.
778 creature
= session
.query(Creature3
).filter_by(
779 name
=u
'centipede').one()
780 assert creature
.num_limbs
== 100.0
781 assert creature
.magical_powers
== []
783 creature
= session
.query(Creature3
).filter_by(
785 assert creature
.num_limbs
== 4.0
786 assert creature
.magical_powers
== []
788 creature
= session
.query(Creature3
).filter_by(
789 name
=u
'wizardsnake').one()
790 assert creature
.num_limbs
== 0.0
791 assert creature
.magical_powers
== []
793 level
= session
.query(Level3
).filter_by(
794 id=u
'necroplex').one()
795 assert level
.name
== u
'The Necroplex'
796 assert level
.description
== u
'A complex full of pure deathzone.'
797 level_exits
= _get_level3_exits(session
, level
)
798 assert level_exits
== {
799 u
'deathwell': u
'evilstorm',
800 u
'portal': u
'central_park'}
802 level
= session
.query(Level3
).filter_by(
803 id=u
'evilstorm').one()
804 assert level
.name
== u
'Evil Storm'
805 assert level
.description
== u
'A storm full of pure evil.'
806 level_exits
= _get_level3_exits(session
, level
)
807 assert level_exits
== {} # You still can't escape the evilstorm!
809 level
= session
.query(Level3
).filter_by(
810 id=u
'central_park').one()
811 assert level
.name
== u
'Central Park, NY, NY'
812 assert level
.description
== u
"New York's friendly Central Park."
813 level_exits
= _get_level3_exits(session
, level
)
814 assert level_exits
== {
815 'portal': 'necroplex'}
818 #def test_set2_to_set3():
819 # Create / connect to database
820 # Create tables by migrating on empty initial set
822 # Install the initial set
823 # Check version in database
824 # Sanity check a few things in the database
827 # Make sure version matches expected
828 # Check all things in database match expected
832 #def test_set1_to_set2_to_set3():
833 # Create / connect to database
834 # Create tables by migrating on empty initial set
836 # Install the initial set
837 # Check version in database
838 # Sanity check a few things in the database
841 # Make sure version matches expected
842 # Check all things in database match expected
845 # Make sure version matches expected again
846 # Check all things in database match expected again
849 # creature_table = Table(
850 # 'creature', metadata,
851 # autoload=True, autoload_with=db_conn.bind)
852 # assert set(creature_table.c.keys()) == set(
853 # ['id', 'name', 'num_legs'])
854 # assert_col_type(creature_table.c.id, Integer)
855 # assert_col_type(creature_table.c.name, VARCHAR)
856 # assert creature_table.c.name.nullable is False
857 # assert creature_table.c.name.index is True
858 # assert creature_table.c.name.unique is True
859 # assert_col_type(creature_table.c.num_legs, Integer)
860 # assert creature_table.c.num_legs.nullable is False
862 # # Check the CreaturePower table
863 # creature_power_table = Table(
864 # 'creature_power', metadata,
865 # autoload=True, autoload_with=db_conn.bind)
866 # assert set(creature_power_table.c.keys()) == set(
867 # ['id', 'creature', 'name', 'description', 'hitpower'])
868 # assert_col_type(creature_power_table.c.id, Integer)
869 # assert_col_type(creature_power_table.c.creature, Integer)
870 # assert creature_power_table.c.creature.nullable is False
871 # assert_col_type(creature_power_table.c.name, VARCHAR)
872 # assert_col_type(creature_power_table.c.description, VARCHAR)
873 # assert_col_type(creature_power_table.c.hitpower, Integer)
874 # assert creature_power_table.c.hitpower.nullable is False
876 # # Check the structure of the level table
877 # level_table = Table(
879 # autoload=True, autoload_with=db_conn.bind)
880 # assert set(level_table.c.keys()) == set(
881 # ['id', 'name', 'description'])
882 # assert_col_type(level_table.c.id, VARCHAR)
883 # assert level_table.c.id.primary_key is True
884 # assert_col_type(level_table.c.name, VARCHAR)
885 # assert_col_type(level_table.c.description, VARCHAR)
887 # # Check the structure of the level_exits table
888 # level_exit_table = Table(
889 # 'level_exit', metadata,
890 # autoload=True, autoload_with=db_conn.bind)
891 # assert set(level_exit_table.c.keys()) == set(
892 # ['id', 'name', 'from_level', 'to_level'])
893 # assert_col_type(level_exit_table.c.id, Integer)
894 # assert_col_type(level_exit_table.c.name, VARCHAR)
895 # assert_col_type(level_exit_table.c.from_level, VARCHAR)
896 # assert level_exit_table.c.from_level.nullable is False
897 # assert_col_type(level_exit_table.c.to_level, VARCHAR)