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/>.
21 from sqlalchemy
import (
22 Table
, Column
, MetaData
, Index
,
23 Integer
, Float
, Unicode
, UnicodeText
, DateTime
, Boolean
,
24 ForeignKey
, UniqueConstraint
, PickleType
, VARCHAR
)
25 from sqlalchemy
.orm
import sessionmaker
, relationship
26 from sqlalchemy
.ext
.declarative
import declarative_base
27 from sqlalchemy
.sql
import select
, insert
28 from migrate
import changeset
30 from mediagoblin
.db
.base
import GMGTableBase
31 from mediagoblin
.db
.migration_tools
import MigrationManager
, RegisterMigration
32 from mediagoblin
.tools
.common
import CollectingPrinter
35 # This one will get filled with local migrations
39 #######################################################
40 # Migration set 1: Define initial models, no migrations
41 #######################################################
43 Base1
= declarative_base(cls
=GMGTableBase
)
45 class Creature1(Base1
):
46 __tablename__
= "creature"
48 id = Column(Integer
, primary_key
=True)
49 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
50 num_legs
= Column(Integer
, nullable
=False)
51 is_demon
= Column(Boolean
)
54 __tablename__
= "level"
56 id = Column(Unicode
, primary_key
=True)
57 name
= Column(Unicode
)
58 description
= Column(Unicode
)
59 exits
= Column(PickleType
)
61 SET1_MODELS
= [Creature1
, Level1
]
63 FOUNDATIONS
= {Creature1
:[{'name':u
'goblin','num_legs':2,'is_demon':False},
64 {'name':u
'cerberus','num_legs':4,'is_demon':True}]
69 #######################################################
70 # Migration set 2: A few migrations and new model
71 #######################################################
73 Base2
= declarative_base(cls
=GMGTableBase
)
75 class Creature2(Base2
):
76 __tablename__
= "creature"
78 id = Column(Integer
, primary_key
=True)
79 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
80 num_legs
= Column(Integer
, nullable
=False)
81 magical_powers
= relationship("CreaturePower2")
83 class CreaturePower2(Base2
):
84 __tablename__
= "creature_power"
86 id = Column(Integer
, primary_key
=True)
88 Integer
, ForeignKey('creature.id'), nullable
=False)
89 name
= Column(Unicode
)
90 description
= Column(Unicode
)
91 hitpower
= Column(Integer
, nullable
=False)
94 __tablename__
= "level"
96 id = Column(Unicode
, primary_key
=True)
97 name
= Column(Unicode
)
98 description
= Column(Unicode
)
100 class LevelExit2(Base2
):
101 __tablename__
= "level_exit"
103 id = Column(Integer
, primary_key
=True)
104 name
= Column(Unicode
)
106 Unicode
, ForeignKey('level.id'), nullable
=False)
108 Unicode
, ForeignKey('level.id'), nullable
=False)
110 SET2_MODELS
= [Creature2
, CreaturePower2
, Level2
, LevelExit2
]
113 @RegisterMigration(1, FULL_MIGRATIONS
)
114 def creature_remove_is_demon(db_conn
):
116 Remove the is_demon field from the creature model. We don't need
119 # :( Commented out 'cuz of:
120 # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242
122 # metadata = MetaData(bind=db_conn.bind)
123 # creature_table = Table(
124 # 'creature', metadata,
125 # autoload=True, autoload_with=db_conn.bind)
126 # creature_table.drop_column('is_demon')
130 @RegisterMigration(2, FULL_MIGRATIONS
)
131 def creature_powers_new_table(db_conn
):
133 Add a new table for creature powers. Nothing needs to go in it
134 yet though as there wasn't anything that previously held this
137 metadata
= MetaData(bind
=db_conn
.bind
)
139 # We have to access the creature table so sqlalchemy can make the
140 # foreign key relationship
141 creature_table
= Table(
142 'creature', metadata
,
143 autoload
=True, autoload_with
=db_conn
.bind
)
145 creature_powers
= Table(
146 'creature_power', metadata
,
147 Column('id', Integer
, primary_key
=True),
149 Integer
, ForeignKey('creature.id'), nullable
=False),
150 Column('name', Unicode
),
151 Column('description', Unicode
),
152 Column('hitpower', Integer
, nullable
=False))
153 metadata
.create_all(db_conn
.bind
)
156 @RegisterMigration(3, FULL_MIGRATIONS
)
157 def level_exits_new_table(db_conn
):
159 Make a new table for level exits and move the previously pickled
160 stuff over to here (then drop the old unneeded table)
162 # First, create the table
163 # -----------------------
164 metadata
= MetaData(bind
=db_conn
.bind
)
166 # Minimal representation of level table.
167 # Not auto-introspecting here because of pickle table. I'm not
168 # sure sqlalchemy can auto-introspect pickle columns.
171 Column('id', Unicode
, primary_key
=True),
172 Column('name', Unicode
),
173 Column('description', Unicode
),
174 Column('exits', PickleType
))
177 'level_exit', metadata
,
178 Column('id', Integer
, primary_key
=True),
179 Column('name', Unicode
),
181 Unicode
, ForeignKey('level.id'), nullable
=False),
183 Unicode
, ForeignKey('level.id'), nullable
=False))
184 metadata
.create_all(db_conn
.bind
)
186 # And now, convert all the old exit pickles to new level exits
187 # ------------------------------------------------------------
189 # query over and insert
190 result
= db_conn
.execute(
191 select([levels
], levels
.c
.exits
!=None))
195 for exit_name
, to_level
in six
.iteritems(level
['exits']):
196 # Insert the level exit
198 level_exits
.insert().values(
203 # Finally, drop the old level exits pickle table
204 # ----------------------------------------------
205 levels
.drop_column('exits')
208 # A hack! At this point we freeze-fame and get just a partial list of
211 SET2_MIGRATIONS
= copy
.copy(FULL_MIGRATIONS
)
213 #######################################################
214 # Migration set 3: Final migrations
215 #######################################################
217 Base3
= declarative_base(cls
=GMGTableBase
)
219 class Creature3(Base3
):
220 __tablename__
= "creature"
222 id = Column(Integer
, primary_key
=True)
223 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
224 num_limbs
= Column(Integer
, nullable
=False)
225 magical_powers
= relationship("CreaturePower3")
227 class CreaturePower3(Base3
):
228 __tablename__
= "creature_power"
230 id = Column(Integer
, primary_key
=True)
232 Integer
, ForeignKey('creature.id'), nullable
=False, index
=True)
233 name
= Column(Unicode
)
234 description
= Column(Unicode
)
235 hitpower
= Column(Float
, nullable
=False)
238 __tablename__
= "level"
240 id = Column(Unicode
, primary_key
=True)
241 name
= Column(Unicode
)
242 description
= Column(Unicode
)
244 class LevelExit3(Base3
):
245 __tablename__
= "level_exit"
247 id = Column(Integer
, primary_key
=True)
248 name
= Column(Unicode
)
250 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
252 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
255 SET3_MODELS
= [Creature3
, CreaturePower3
, Level3
, LevelExit3
]
256 SET3_MIGRATIONS
= FULL_MIGRATIONS
259 @RegisterMigration(4, FULL_MIGRATIONS
)
260 def creature_num_legs_to_num_limbs(db_conn
):
262 Turns out we're tracking all sorts of limbs, not "legs"
263 specifically. Humans would be 4 here, for instance. So we
266 metadata
= MetaData(bind
=db_conn
.bind
)
267 creature_table
= Table(
268 'creature', metadata
,
269 autoload
=True, autoload_with
=db_conn
.bind
)
270 creature_table
.c
.num_legs
.alter(name
=u
"num_limbs")
273 @RegisterMigration(5, FULL_MIGRATIONS
)
274 def level_exit_index_from_and_to_level(db_conn
):
276 Index the from and to levels of the level exit table.
278 metadata
= MetaData(bind
=db_conn
.bind
)
280 'level_exit', metadata
,
281 autoload
=True, autoload_with
=db_conn
.bind
)
282 Index('ix_level_exit_from_level',
283 level_exit
.c
.from_level
).create(db_conn
.bind
)
284 Index('ix_level_exit_to_level',
285 level_exit
.c
.to_level
).create(db_conn
.bind
)
288 @RegisterMigration(6, FULL_MIGRATIONS
)
289 def creature_power_index_creature(db_conn
):
291 Index our foreign key relationship to the creatures
293 metadata
= MetaData(bind
=db_conn
.bind
)
294 creature_power
= Table(
295 'creature_power', metadata
,
296 autoload
=True, autoload_with
=db_conn
.bind
)
297 Index('ix_creature_power_creature',
298 creature_power
.c
.creature
).create(db_conn
.bind
)
301 @RegisterMigration(7, FULL_MIGRATIONS
)
302 def creature_power_hitpower_to_float(db_conn
):
304 Convert hitpower column on creature power table from integer to
307 Turns out we want super precise values of how much hitpower there
310 metadata
= MetaData(bind
=db_conn
.bind
)
312 # We have to access the creature table so sqlalchemy can make the
313 # foreign key relationship
314 creature_table
= Table(
315 'creature', metadata
,
316 autoload
=True, autoload_with
=db_conn
.bind
)
318 creature_power
= Table(
319 'creature_power', metadata
,
320 Column('id', Integer
, primary_key
=True),
321 Column('creature', Integer
,
322 ForeignKey('creature.id'), nullable
=False,
324 Column('name', Unicode
),
325 Column('description', Unicode
),
326 Column('hitpower', Integer
, nullable
=False))
328 creature_power
.c
.hitpower
.alter(type=Float
)
331 @RegisterMigration(8, FULL_MIGRATIONS
)
332 def creature_power_name_creature_unique(db_conn
):
334 Add a unique constraint to name and creature on creature_power.
336 We don't want multiple creature powers with the same name per creature!
338 # Note: We don't actually check to see if this constraint is set
339 # up because at present there's no way to do so in sqlalchemy :\
341 metadata
= MetaData(bind
=db_conn
.bind
)
343 creature_power
= Table(
344 'creature_power', metadata
,
345 autoload
=True, autoload_with
=db_conn
.bind
)
347 cons
= changeset
.constraint
.UniqueConstraint(
348 'name', 'creature', table
=creature_power
)
353 def _insert_migration1_objects(session
):
355 Test objects to insert for the first set of things
359 [Creature1(name
=u
'centipede',
362 Creature1(name
=u
'wolf',
365 # don't ask me what a wizardsnake is.
366 Creature1(name
=u
'wizardsnake',
372 [Level1(id=u
'necroplex',
373 name
=u
'The Necroplex',
374 description
=u
'A complex full of pure deathzone.',
376 u
'deathwell': u
'evilstorm',
377 u
'portal': u
'central_park'}),
378 Level1(id=u
'evilstorm',
380 description
=u
'A storm full of pure evil.',
381 exits
={}), # you can't escape the evilstorm
382 Level1(id=u
'central_park',
383 name
=u
'Central Park, NY, NY',
384 description
=u
"New York's friendly Central Park.",
386 u
'portal': u
'necroplex'})])
391 def _insert_migration2_objects(session
):
393 Test objects to insert for the second set of things
406 description
=u
"A blast of icy breath!",
410 description
=u
"A frightening stare, for sure!",
417 name
=u
'death_rattle',
418 description
=u
'A rattle... of DEATH!',
421 name
=u
'sneaky_stare',
422 description
=u
"The sneakiest stare you've ever seen!",
425 name
=u
'slithery_smoke',
426 description
=u
"A blast of slithery, slithery smoke.",
429 name
=u
'treacherous_tremors',
430 description
=u
"The ground shakes beneath footed animals!",
435 [Level2(id=u
'necroplex',
436 name
=u
'The Necroplex',
437 description
=u
'A complex full of pure deathzone.'),
438 Level2(id=u
'evilstorm',
440 description
=u
'A storm full of pure evil.',
441 exits
=[]), # you can't escape the evilstorm
442 Level2(id=u
'central_park',
443 name
=u
'Central Park, NY, NY',
444 description
=u
"New York's friendly Central Park.")])
448 [LevelExit2(name
=u
'deathwell',
449 from_level
=u
'necroplex',
450 to_level
=u
'evilstorm'),
451 LevelExit2(name
=u
'portal',
452 from_level
=u
'necroplex',
453 to_level
=u
'central_park')])
455 # there are no evilstorm exits because there is no exit from the
460 [LevelExit2(name
=u
'portal',
461 from_level
=u
'central_park',
462 to_level
=u
'necroplex')])
467 def _insert_migration3_objects(session
):
469 Test objects to insert for the third set of things
482 description
=u
"A blast of icy breath!",
486 description
=u
"A frightening stare, for sure!",
493 name
=u
'death_rattle',
494 description
=u
'A rattle... of DEATH!',
497 name
=u
'sneaky_stare',
498 description
=u
"The sneakiest stare you've ever seen!",
501 name
=u
'slithery_smoke',
502 description
=u
"A blast of slithery, slithery smoke.",
505 name
=u
'treacherous_tremors',
506 description
=u
"The ground shakes beneath footed animals!",
508 # annnnnd one more to test a floating point hitpower
515 description
=u
'Smitten by holy wrath!',
520 [Level3(id=u
'necroplex',
521 name
=u
'The Necroplex',
522 description
=u
'A complex full of pure deathzone.'),
523 Level3(id=u
'evilstorm',
525 description
=u
'A storm full of pure evil.',
526 exits
=[]), # you can't escape the evilstorm
527 Level3(id=u
'central_park',
528 name
=u
'Central Park, NY, NY',
529 description
=u
"New York's friendly Central Park.")])
533 [LevelExit3(name
=u
'deathwell',
534 from_level
=u
'necroplex',
535 to_level
=u
'evilstorm'),
536 LevelExit3(name
=u
'portal',
537 from_level
=u
'necroplex',
538 to_level
=u
'central_park')])
540 # there are no evilstorm exits because there is no exit from the
545 [LevelExit3(name
=u
'portal',
546 from_level
=u
'central_park',
547 to_level
=u
'necroplex')])
551 def create_test_engine():
552 from sqlalchemy
import create_engine
553 engine
= create_engine('sqlite:///:memory:', echo
=False)
554 Session
= sessionmaker(bind
=engine
)
555 return engine
, Session
558 def assert_col_type(column
, this_class
):
559 assert isinstance(column
.type, this_class
)
562 def _get_level3_exits(session
, level
):
564 [(level_exit
.name
, level_exit
.to_level
)
566 session
.query(LevelExit3
).filter_by(from_level
=level
.id)])
569 def test_set1_to_set3():
570 # Create / connect to database
571 # ----------------------------
573 engine
, Session
= create_test_engine()
575 # Create tables by migrating on empty initial set
576 # -----------------------------------------------
578 printer
= CollectingPrinter()
579 migration_manager
= MigrationManager(
580 u
'__main__', SET1_MODELS
, FOUNDATIONS
, SET1_MIGRATIONS
, Session(),
583 # Check latest migration and database current migration
584 assert migration_manager
.latest_migration
== 0
585 assert migration_manager
.database_current_migration
== None
587 result
= migration_manager
.init_or_migrate()
589 # Make sure output was "inited"
590 assert result
== u
'inited'
592 assert printer
.combined_string
== (
593 "-> Initializing main mediagoblin tables... done.\n" + \
594 " + Laying foundations for Creature1 table\n" )
595 # Check version in database
596 assert migration_manager
.latest_migration
== 0
597 assert migration_manager
.database_current_migration
== 0
600 # Install the initial set
601 # -----------------------
603 _insert_migration1_objects(Session())
605 # Try to "re-migrate" with same manager settings... nothing should happen
606 migration_manager
= MigrationManager(
607 u
'__main__', SET1_MODELS
, FOUNDATIONS
, SET1_MIGRATIONS
,
609 assert migration_manager
.init_or_migrate() == None
611 # Check version in database
612 assert migration_manager
.latest_migration
== 0
613 assert migration_manager
.database_current_migration
== 0
615 # Sanity check a few things in the database...
616 metadata
= MetaData(bind
=engine
)
618 # Check the structure of the creature table
619 creature_table
= Table(
620 'creature', metadata
,
621 autoload
=True, autoload_with
=engine
)
622 assert set(creature_table
.c
.keys()) == set(
623 ['id', 'name', 'num_legs', 'is_demon'])
624 assert_col_type(creature_table
.c
.id, Integer
)
625 assert_col_type(creature_table
.c
.name
, VARCHAR
)
626 assert creature_table
.c
.name
.nullable
is False
627 #assert creature_table.c.name.index is True
628 #assert creature_table.c.name.unique is True
629 assert_col_type(creature_table
.c
.num_legs
, Integer
)
630 assert creature_table
.c
.num_legs
.nullable
is False
631 assert_col_type(creature_table
.c
.is_demon
, Boolean
)
633 # Check the structure of the level table
636 autoload
=True, autoload_with
=engine
)
637 assert set(level_table
.c
.keys()) == set(
638 ['id', 'name', 'description', 'exits'])
639 assert_col_type(level_table
.c
.id, VARCHAR
)
640 assert level_table
.c
.id.primary_key
is True
641 assert_col_type(level_table
.c
.name
, VARCHAR
)
642 assert_col_type(level_table
.c
.description
, VARCHAR
)
643 # Skipping exits... Not sure if we can detect pickletype, not a
644 # big deal regardless.
646 # Now check to see if stuff seems to be in there.
649 # Check the creation of the foundation rows on the creature table
650 creature
= session
.query(Creature1
).filter_by(
651 name
=u
'goblin').one()
652 assert creature
.num_legs
== 2
653 assert creature
.is_demon
== False
655 creature
= session
.query(Creature1
).filter_by(
656 name
=u
'cerberus').one()
657 assert creature
.num_legs
== 4
658 assert creature
.is_demon
== True
661 # Check the creation of the inserted rows on the creature and levels tables
663 creature
= session
.query(Creature1
).filter_by(
664 name
=u
'centipede').one()
665 assert creature
.num_legs
== 100
666 assert creature
.is_demon
== False
668 creature
= session
.query(Creature1
).filter_by(
670 assert creature
.num_legs
== 4
671 assert creature
.is_demon
== False
673 creature
= session
.query(Creature1
).filter_by(
674 name
=u
'wizardsnake').one()
675 assert creature
.num_legs
== 0
676 assert creature
.is_demon
== True
678 level
= session
.query(Level1
).filter_by(
679 id=u
'necroplex').one()
680 assert level
.name
== u
'The Necroplex'
681 assert level
.description
== u
'A complex full of pure deathzone.'
682 assert level
.exits
== {
683 'deathwell': 'evilstorm',
684 'portal': 'central_park'}
686 level
= session
.query(Level1
).filter_by(
687 id=u
'evilstorm').one()
688 assert level
.name
== u
'Evil Storm'
689 assert level
.description
== u
'A storm full of pure evil.'
690 assert level
.exits
== {} # You still can't escape the evilstorm!
692 level
= session
.query(Level1
).filter_by(
693 id=u
'central_park').one()
694 assert level
.name
== u
'Central Park, NY, NY'
695 assert level
.description
== u
"New York's friendly Central Park."
696 assert level
.exits
== {
697 'portal': 'necroplex'}
699 # Create new migration manager, but make sure the db migration
700 # isn't said to be updated yet
701 printer
= CollectingPrinter()
702 migration_manager
= MigrationManager(
703 u
'__main__', SET3_MODELS
, FOUNDATIONS
, SET3_MIGRATIONS
, Session(),
706 assert migration_manager
.latest_migration
== 8
707 assert migration_manager
.database_current_migration
== 0
710 result
= migration_manager
.init_or_migrate()
712 # Make sure result was "migrated"
713 assert result
== u
'migrated'
715 # TODO: Check output to user
716 assert printer
.combined_string
== """\
717 -> Updating main mediagoblin tables:
718 + Running migration 1, "creature_remove_is_demon"... done.
719 + Running migration 2, "creature_powers_new_table"... done.
720 + Running migration 3, "level_exits_new_table"... done.
721 + Running migration 4, "creature_num_legs_to_num_limbs"... done.
722 + Running migration 5, "level_exit_index_from_and_to_level"... done.
723 + Running migration 6, "creature_power_index_creature"... done.
724 + Running migration 7, "creature_power_hitpower_to_float"... done.
725 + Running migration 8, "creature_power_name_creature_unique"... done.
728 # Make sure version matches expected
729 migration_manager
= MigrationManager(
730 u
'__main__', SET3_MODELS
, FOUNDATIONS
, SET3_MIGRATIONS
, Session(),
732 assert migration_manager
.latest_migration
== 8
733 assert migration_manager
.database_current_migration
== 8
735 # Check all things in database match expected
737 # Check the creature table
738 metadata
= MetaData(bind
=engine
)
739 creature_table
= Table(
740 'creature', metadata
,
741 autoload
=True, autoload_with
=engine
)
742 # assert set(creature_table.c.keys()) == set(
743 # ['id', 'name', 'num_limbs'])
744 assert set(creature_table
.c
.keys()) == set(
745 [u
'id', 'name', u
'num_limbs', u
'is_demon'])
746 assert_col_type(creature_table
.c
.id, Integer
)
747 assert_col_type(creature_table
.c
.name
, VARCHAR
)
748 assert creature_table
.c
.name
.nullable
is False
749 #assert creature_table.c.name.index is True
750 #assert creature_table.c.name.unique is True
751 assert_col_type(creature_table
.c
.num_limbs
, Integer
)
752 assert creature_table
.c
.num_limbs
.nullable
is False
754 # Check the CreaturePower table
755 creature_power_table
= Table(
756 'creature_power', metadata
,
757 autoload
=True, autoload_with
=engine
)
758 assert set(creature_power_table
.c
.keys()) == set(
759 ['id', 'creature', 'name', 'description', 'hitpower'])
760 assert_col_type(creature_power_table
.c
.id, Integer
)
761 assert_col_type(creature_power_table
.c
.creature
, Integer
)
762 assert creature_power_table
.c
.creature
.nullable
is False
763 assert_col_type(creature_power_table
.c
.name
, VARCHAR
)
764 assert_col_type(creature_power_table
.c
.description
, VARCHAR
)
765 assert_col_type(creature_power_table
.c
.hitpower
, Float
)
766 assert creature_power_table
.c
.hitpower
.nullable
is False
768 # Check the structure of the level table
771 autoload
=True, autoload_with
=engine
)
772 assert set(level_table
.c
.keys()) == set(
773 ['id', 'name', 'description'])
774 assert_col_type(level_table
.c
.id, VARCHAR
)
775 assert level_table
.c
.id.primary_key
is True
776 assert_col_type(level_table
.c
.name
, VARCHAR
)
777 assert_col_type(level_table
.c
.description
, VARCHAR
)
779 # Check the structure of the level_exits table
780 level_exit_table
= Table(
781 'level_exit', metadata
,
782 autoload
=True, autoload_with
=engine
)
783 assert set(level_exit_table
.c
.keys()) == set(
784 ['id', 'name', 'from_level', 'to_level'])
785 assert_col_type(level_exit_table
.c
.id, Integer
)
786 assert_col_type(level_exit_table
.c
.name
, VARCHAR
)
787 assert_col_type(level_exit_table
.c
.from_level
, VARCHAR
)
788 assert level_exit_table
.c
.from_level
.nullable
is False
789 #assert level_exit_table.c.from_level.index is True
790 assert_col_type(level_exit_table
.c
.to_level
, VARCHAR
)
791 assert level_exit_table
.c
.to_level
.nullable
is False
792 #assert level_exit_table.c.to_level.index is True
794 # Now check to see if stuff seems to be in there.
798 # Start with making sure that the foundations did not run again
799 assert session
.query(Creature3
).filter_by(
800 name
=u
'goblin').count() == 1
801 assert session
.query(Creature3
).filter_by(
802 name
=u
'cerberus').count() == 1
804 # Then make sure the models have been migrated correctly
805 creature
= session
.query(Creature3
).filter_by(
806 name
=u
'centipede').one()
807 assert creature
.num_limbs
== 100.0
808 assert creature
.magical_powers
== []
810 creature
= session
.query(Creature3
).filter_by(
812 assert creature
.num_limbs
== 4.0
813 assert creature
.magical_powers
== []
815 creature
= session
.query(Creature3
).filter_by(
816 name
=u
'wizardsnake').one()
817 assert creature
.num_limbs
== 0.0
818 assert creature
.magical_powers
== []
820 level
= session
.query(Level3
).filter_by(
821 id=u
'necroplex').one()
822 assert level
.name
== u
'The Necroplex'
823 assert level
.description
== u
'A complex full of pure deathzone.'
824 level_exits
= _get_level3_exits(session
, level
)
825 assert level_exits
== {
826 u
'deathwell': u
'evilstorm',
827 u
'portal': u
'central_park'}
829 level
= session
.query(Level3
).filter_by(
830 id=u
'evilstorm').one()
831 assert level
.name
== u
'Evil Storm'
832 assert level
.description
== u
'A storm full of pure evil.'
833 level_exits
= _get_level3_exits(session
, level
)
834 assert level_exits
== {} # You still can't escape the evilstorm!
836 level
= session
.query(Level3
).filter_by(
837 id=u
'central_park').one()
838 assert level
.name
== u
'Central Park, NY, NY'
839 assert level
.description
== u
"New York's friendly Central Park."
840 level_exits
= _get_level3_exits(session
, level
)
841 assert level_exits
== {
842 'portal': 'necroplex'}
845 #def test_set2_to_set3():
846 # Create / connect to database
847 # Create tables by migrating on empty initial set
849 # Install the initial set
850 # Check version in database
851 # Sanity check a few things in the database
854 # Make sure version matches expected
855 # Check all things in database match expected
859 #def test_set1_to_set2_to_set3():
860 # Create / connect to database
861 # Create tables by migrating on empty initial set
863 # Install the initial set
864 # Check version in database
865 # Sanity check a few things in the database
868 # Make sure version matches expected
869 # Check all things in database match expected
872 # Make sure version matches expected again
873 # Check all things in database match expected again
876 # creature_table = Table(
877 # 'creature', metadata,
878 # autoload=True, autoload_with=db_conn.bind)
879 # assert set(creature_table.c.keys()) == set(
880 # ['id', 'name', 'num_legs'])
881 # assert_col_type(creature_table.c.id, Integer)
882 # assert_col_type(creature_table.c.name, VARCHAR)
883 # assert creature_table.c.name.nullable is False
884 # assert creature_table.c.name.index is True
885 # assert creature_table.c.name.unique is True
886 # assert_col_type(creature_table.c.num_legs, Integer)
887 # assert creature_table.c.num_legs.nullable is False
889 # # Check the CreaturePower table
890 # creature_power_table = Table(
891 # 'creature_power', metadata,
892 # autoload=True, autoload_with=db_conn.bind)
893 # assert set(creature_power_table.c.keys()) == set(
894 # ['id', 'creature', 'name', 'description', 'hitpower'])
895 # assert_col_type(creature_power_table.c.id, Integer)
896 # assert_col_type(creature_power_table.c.creature, Integer)
897 # assert creature_power_table.c.creature.nullable is False
898 # assert_col_type(creature_power_table.c.name, VARCHAR)
899 # assert_col_type(creature_power_table.c.description, VARCHAR)
900 # assert_col_type(creature_power_table.c.hitpower, Integer)
901 # assert creature_power_table.c.hitpower.nullable is False
903 # # Check the structure of the level table
904 # level_table = Table(
906 # autoload=True, autoload_with=db_conn.bind)
907 # assert set(level_table.c.keys()) == set(
908 # ['id', 'name', 'description'])
909 # assert_col_type(level_table.c.id, VARCHAR)
910 # assert level_table.c.id.primary_key is True
911 # assert_col_type(level_table.c.name, VARCHAR)
912 # assert_col_type(level_table.c.description, VARCHAR)
914 # # Check the structure of the level_exits table
915 # level_exit_table = Table(
916 # 'level_exit', metadata,
917 # autoload=True, autoload_with=db_conn.bind)
918 # assert set(level_exit_table.c.keys()) == set(
919 # ['id', 'name', 'from_level', 'to_level'])
920 # assert_col_type(level_exit_table.c.id, Integer)
921 # assert_col_type(level_exit_table.c.name, VARCHAR)
922 # assert_col_type(level_exit_table.c.from_level, VARCHAR)
923 # assert level_exit_table.c.from_level.nullable is False
924 # assert_col_type(level_exit_table.c.to_level, VARCHAR)