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/>.
20 pytestmark
= pytest
.mark
.skipif(six
.PY3
, reason
='needs sqlalchemy.migrate')
24 from sqlalchemy
import (
25 Table
, Column
, MetaData
, Index
,
26 Integer
, Float
, Unicode
, UnicodeText
, DateTime
, Boolean
,
27 ForeignKey
, UniqueConstraint
, PickleType
, VARCHAR
)
28 from sqlalchemy
.orm
import sessionmaker
, relationship
29 from sqlalchemy
.ext
.declarative
import declarative_base
30 from sqlalchemy
.sql
import select
, insert
32 from migrate
import changeset
34 from mediagoblin
.db
.base
import GMGTableBase
35 from mediagoblin
.db
.migration_tools
import MigrationManager
, RegisterMigration
36 from mediagoblin
.tools
.common
import CollectingPrinter
39 # This one will get filled with local migrations
43 #######################################################
44 # Migration set 1: Define initial models, no migrations
45 #######################################################
47 Base1
= declarative_base(cls
=GMGTableBase
)
49 class Creature1(Base1
):
50 __tablename__
= "creature"
52 id = Column(Integer
, primary_key
=True)
53 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
54 num_legs
= Column(Integer
, nullable
=False)
55 is_demon
= Column(Boolean
)
58 __tablename__
= "level"
60 id = Column(Unicode
, primary_key
=True)
61 name
= Column(Unicode
)
62 description
= Column(Unicode
)
63 exits
= Column(PickleType
)
65 SET1_MODELS
= [Creature1
, Level1
]
67 FOUNDATIONS
= {Creature1
:[{'name':u
'goblin','num_legs':2,'is_demon':False},
68 {'name':u
'cerberus','num_legs':4,'is_demon':True}]
73 #######################################################
74 # Migration set 2: A few migrations and new model
75 #######################################################
77 Base2
= declarative_base(cls
=GMGTableBase
)
79 class Creature2(Base2
):
80 __tablename__
= "creature"
82 id = Column(Integer
, primary_key
=True)
83 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
84 num_legs
= Column(Integer
, nullable
=False)
85 magical_powers
= relationship("CreaturePower2")
87 class CreaturePower2(Base2
):
88 __tablename__
= "creature_power"
90 id = Column(Integer
, primary_key
=True)
92 Integer
, ForeignKey('creature.id'), nullable
=False)
93 name
= Column(Unicode
)
94 description
= Column(Unicode
)
95 hitpower
= Column(Integer
, nullable
=False)
98 __tablename__
= "level"
100 id = Column(Unicode
, primary_key
=True)
101 name
= Column(Unicode
)
102 description
= Column(Unicode
)
104 class LevelExit2(Base2
):
105 __tablename__
= "level_exit"
107 id = Column(Integer
, primary_key
=True)
108 name
= Column(Unicode
)
110 Unicode
, ForeignKey('level.id'), nullable
=False)
112 Unicode
, ForeignKey('level.id'), nullable
=False)
114 SET2_MODELS
= [Creature2
, CreaturePower2
, Level2
, LevelExit2
]
117 @RegisterMigration(1, FULL_MIGRATIONS
)
118 def creature_remove_is_demon(db_conn
):
120 Remove the is_demon field from the creature model. We don't need
123 # :( Commented out 'cuz of:
124 # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242
126 # metadata = MetaData(bind=db_conn.bind)
127 # creature_table = Table(
128 # 'creature', metadata,
129 # autoload=True, autoload_with=db_conn.bind)
130 # creature_table.drop_column('is_demon')
134 @RegisterMigration(2, FULL_MIGRATIONS
)
135 def creature_powers_new_table(db_conn
):
137 Add a new table for creature powers. Nothing needs to go in it
138 yet though as there wasn't anything that previously held this
141 metadata
= MetaData(bind
=db_conn
.bind
)
143 # We have to access the creature table so sqlalchemy can make the
144 # foreign key relationship
145 creature_table
= Table(
146 'creature', metadata
,
147 autoload
=True, autoload_with
=db_conn
.bind
)
149 creature_powers
= Table(
150 'creature_power', metadata
,
151 Column('id', Integer
, primary_key
=True),
153 Integer
, ForeignKey('creature.id'), nullable
=False),
154 Column('name', Unicode
),
155 Column('description', Unicode
),
156 Column('hitpower', Integer
, nullable
=False))
157 metadata
.create_all(db_conn
.bind
)
160 @RegisterMigration(3, FULL_MIGRATIONS
)
161 def level_exits_new_table(db_conn
):
163 Make a new table for level exits and move the previously pickled
164 stuff over to here (then drop the old unneeded table)
166 # First, create the table
167 # -----------------------
168 metadata
= MetaData(bind
=db_conn
.bind
)
170 # Minimal representation of level table.
171 # Not auto-introspecting here because of pickle table. I'm not
172 # sure sqlalchemy can auto-introspect pickle columns.
175 Column('id', Unicode
, primary_key
=True),
176 Column('name', Unicode
),
177 Column('description', Unicode
),
178 Column('exits', PickleType
))
181 'level_exit', metadata
,
182 Column('id', Integer
, primary_key
=True),
183 Column('name', Unicode
),
185 Unicode
, ForeignKey('level.id'), nullable
=False),
187 Unicode
, ForeignKey('level.id'), nullable
=False))
188 metadata
.create_all(db_conn
.bind
)
190 # And now, convert all the old exit pickles to new level exits
191 # ------------------------------------------------------------
193 # query over and insert
194 result
= db_conn
.execute(
195 select([levels
], levels
.c
.exits
!=None))
199 for exit_name
, to_level
in six
.iteritems(level
['exits']):
200 # Insert the level exit
202 level_exits
.insert().values(
207 # Finally, drop the old level exits pickle table
208 # ----------------------------------------------
209 levels
.drop_column('exits')
212 # A hack! At this point we freeze-fame and get just a partial list of
215 SET2_MIGRATIONS
= copy
.copy(FULL_MIGRATIONS
)
217 #######################################################
218 # Migration set 3: Final migrations
219 #######################################################
221 Base3
= declarative_base(cls
=GMGTableBase
)
223 class Creature3(Base3
):
224 __tablename__
= "creature"
226 id = Column(Integer
, primary_key
=True)
227 name
= Column(Unicode
, unique
=True, nullable
=False, index
=True)
228 num_limbs
= Column(Integer
, nullable
=False)
229 magical_powers
= relationship("CreaturePower3")
231 class CreaturePower3(Base3
):
232 __tablename__
= "creature_power"
234 id = Column(Integer
, primary_key
=True)
236 Integer
, ForeignKey('creature.id'), nullable
=False, index
=True)
237 name
= Column(Unicode
)
238 description
= Column(Unicode
)
239 hitpower
= Column(Float
, nullable
=False)
242 __tablename__
= "level"
244 id = Column(Unicode
, primary_key
=True)
245 name
= Column(Unicode
)
246 description
= Column(Unicode
)
248 class LevelExit3(Base3
):
249 __tablename__
= "level_exit"
251 id = Column(Integer
, primary_key
=True)
252 name
= Column(Unicode
)
254 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
256 Unicode
, ForeignKey('level.id'), nullable
=False, index
=True)
259 SET3_MODELS
= [Creature3
, CreaturePower3
, Level3
, LevelExit3
]
260 SET3_MIGRATIONS
= FULL_MIGRATIONS
263 @RegisterMigration(4, FULL_MIGRATIONS
)
264 def creature_num_legs_to_num_limbs(db_conn
):
266 Turns out we're tracking all sorts of limbs, not "legs"
267 specifically. Humans would be 4 here, for instance. So we
270 metadata
= MetaData(bind
=db_conn
.bind
)
271 creature_table
= Table(
272 'creature', metadata
,
273 autoload
=True, autoload_with
=db_conn
.bind
)
274 creature_table
.c
.num_legs
.alter(name
=u
"num_limbs")
277 @RegisterMigration(5, FULL_MIGRATIONS
)
278 def level_exit_index_from_and_to_level(db_conn
):
280 Index the from and to levels of the level exit table.
282 metadata
= MetaData(bind
=db_conn
.bind
)
284 'level_exit', metadata
,
285 autoload
=True, autoload_with
=db_conn
.bind
)
286 Index('ix_level_exit_from_level',
287 level_exit
.c
.from_level
).create(db_conn
.bind
)
288 Index('ix_level_exit_to_level',
289 level_exit
.c
.to_level
).create(db_conn
.bind
)
292 @RegisterMigration(6, FULL_MIGRATIONS
)
293 def creature_power_index_creature(db_conn
):
295 Index our foreign key relationship to the creatures
297 metadata
= MetaData(bind
=db_conn
.bind
)
298 creature_power
= Table(
299 'creature_power', metadata
,
300 autoload
=True, autoload_with
=db_conn
.bind
)
301 Index('ix_creature_power_creature',
302 creature_power
.c
.creature
).create(db_conn
.bind
)
305 @RegisterMigration(7, FULL_MIGRATIONS
)
306 def creature_power_hitpower_to_float(db_conn
):
308 Convert hitpower column on creature power table from integer to
311 Turns out we want super precise values of how much hitpower there
314 metadata
= MetaData(bind
=db_conn
.bind
)
316 # We have to access the creature table so sqlalchemy can make the
317 # foreign key relationship
318 creature_table
= Table(
319 'creature', metadata
,
320 autoload
=True, autoload_with
=db_conn
.bind
)
322 creature_power
= Table(
323 'creature_power', metadata
,
324 Column('id', Integer
, primary_key
=True),
325 Column('creature', Integer
,
326 ForeignKey('creature.id'), nullable
=False,
328 Column('name', Unicode
),
329 Column('description', Unicode
),
330 Column('hitpower', Integer
, nullable
=False))
332 creature_power
.c
.hitpower
.alter(type=Float
)
335 @RegisterMigration(8, FULL_MIGRATIONS
)
336 def creature_power_name_creature_unique(db_conn
):
338 Add a unique constraint to name and creature on creature_power.
340 We don't want multiple creature powers with the same name per creature!
342 # Note: We don't actually check to see if this constraint is set
343 # up because at present there's no way to do so in sqlalchemy :\
345 metadata
= MetaData(bind
=db_conn
.bind
)
347 creature_power
= Table(
348 'creature_power', metadata
,
349 autoload
=True, autoload_with
=db_conn
.bind
)
351 cons
= changeset
.constraint
.UniqueConstraint(
352 'name', 'creature', table
=creature_power
)
357 def _insert_migration1_objects(session
):
359 Test objects to insert for the first set of things
363 [Creature1(name
=u
'centipede',
366 Creature1(name
=u
'wolf',
369 # don't ask me what a wizardsnake is.
370 Creature1(name
=u
'wizardsnake',
376 [Level1(id=u
'necroplex',
377 name
=u
'The Necroplex',
378 description
=u
'A complex full of pure deathzone.',
380 u
'deathwell': u
'evilstorm',
381 u
'portal': u
'central_park'}),
382 Level1(id=u
'evilstorm',
384 description
=u
'A storm full of pure evil.',
385 exits
={}), # you can't escape the evilstorm
386 Level1(id=u
'central_park',
387 name
=u
'Central Park, NY, NY',
388 description
=u
"New York's friendly Central Park.",
390 u
'portal': u
'necroplex'})])
395 def _insert_migration2_objects(session
):
397 Test objects to insert for the second set of things
410 description
=u
"A blast of icy breath!",
414 description
=u
"A frightening stare, for sure!",
421 name
=u
'death_rattle',
422 description
=u
'A rattle... of DEATH!',
425 name
=u
'sneaky_stare',
426 description
=u
"The sneakiest stare you've ever seen!",
429 name
=u
'slithery_smoke',
430 description
=u
"A blast of slithery, slithery smoke.",
433 name
=u
'treacherous_tremors',
434 description
=u
"The ground shakes beneath footed animals!",
439 [Level2(id=u
'necroplex',
440 name
=u
'The Necroplex',
441 description
=u
'A complex full of pure deathzone.'),
442 Level2(id=u
'evilstorm',
444 description
=u
'A storm full of pure evil.',
445 exits
=[]), # you can't escape the evilstorm
446 Level2(id=u
'central_park',
447 name
=u
'Central Park, NY, NY',
448 description
=u
"New York's friendly Central Park.")])
452 [LevelExit2(name
=u
'deathwell',
453 from_level
=u
'necroplex',
454 to_level
=u
'evilstorm'),
455 LevelExit2(name
=u
'portal',
456 from_level
=u
'necroplex',
457 to_level
=u
'central_park')])
459 # there are no evilstorm exits because there is no exit from the
464 [LevelExit2(name
=u
'portal',
465 from_level
=u
'central_park',
466 to_level
=u
'necroplex')])
471 def _insert_migration3_objects(session
):
473 Test objects to insert for the third set of things
486 description
=u
"A blast of icy breath!",
490 description
=u
"A frightening stare, for sure!",
497 name
=u
'death_rattle',
498 description
=u
'A rattle... of DEATH!',
501 name
=u
'sneaky_stare',
502 description
=u
"The sneakiest stare you've ever seen!",
505 name
=u
'slithery_smoke',
506 description
=u
"A blast of slithery, slithery smoke.",
509 name
=u
'treacherous_tremors',
510 description
=u
"The ground shakes beneath footed animals!",
512 # annnnnd one more to test a floating point hitpower
519 description
=u
'Smitten by holy wrath!',
524 [Level3(id=u
'necroplex',
525 name
=u
'The Necroplex',
526 description
=u
'A complex full of pure deathzone.'),
527 Level3(id=u
'evilstorm',
529 description
=u
'A storm full of pure evil.',
530 exits
=[]), # you can't escape the evilstorm
531 Level3(id=u
'central_park',
532 name
=u
'Central Park, NY, NY',
533 description
=u
"New York's friendly Central Park.")])
537 [LevelExit3(name
=u
'deathwell',
538 from_level
=u
'necroplex',
539 to_level
=u
'evilstorm'),
540 LevelExit3(name
=u
'portal',
541 from_level
=u
'necroplex',
542 to_level
=u
'central_park')])
544 # there are no evilstorm exits because there is no exit from the
549 [LevelExit3(name
=u
'portal',
550 from_level
=u
'central_park',
551 to_level
=u
'necroplex')])
555 def create_test_engine():
556 from sqlalchemy
import create_engine
557 engine
= create_engine('sqlite:///:memory:', echo
=False)
558 Session
= sessionmaker(bind
=engine
)
559 return engine
, Session
562 def assert_col_type(column
, this_class
):
563 assert isinstance(column
.type, this_class
)
566 def _get_level3_exits(session
, level
):
568 [(level_exit
.name
, level_exit
.to_level
)
570 session
.query(LevelExit3
).filter_by(from_level
=level
.id)])
573 def test_set1_to_set3():
574 # Create / connect to database
575 # ----------------------------
577 engine
, Session
= create_test_engine()
579 # Create tables by migrating on empty initial set
580 # -----------------------------------------------
582 printer
= CollectingPrinter()
583 migration_manager
= MigrationManager(
584 u
'__main__', SET1_MODELS
, FOUNDATIONS
, SET1_MIGRATIONS
, Session(),
587 # Check latest migration and database current migration
588 assert migration_manager
.latest_migration
== 0
589 assert migration_manager
.database_current_migration
== None
591 result
= migration_manager
.init_or_migrate()
593 # Make sure output was "inited"
594 assert result
== u
'inited'
596 assert printer
.combined_string
== (
597 "-> Initializing main mediagoblin tables... done.\n" + \
598 " + Laying foundations for Creature1 table\n" )
599 # Check version in database
600 assert migration_manager
.latest_migration
== 0
601 assert migration_manager
.database_current_migration
== 0
604 # Install the initial set
605 # -----------------------
607 _insert_migration1_objects(Session())
609 # Try to "re-migrate" with same manager settings... nothing should happen
610 migration_manager
= MigrationManager(
611 u
'__main__', SET1_MODELS
, FOUNDATIONS
, SET1_MIGRATIONS
,
613 assert migration_manager
.init_or_migrate() == None
615 # Check version in database
616 assert migration_manager
.latest_migration
== 0
617 assert migration_manager
.database_current_migration
== 0
619 # Sanity check a few things in the database...
620 metadata
= MetaData(bind
=engine
)
622 # Check the structure of the creature table
623 creature_table
= Table(
624 'creature', metadata
,
625 autoload
=True, autoload_with
=engine
)
626 assert set(creature_table
.c
.keys()) == set(
627 ['id', 'name', 'num_legs', 'is_demon'])
628 assert_col_type(creature_table
.c
.id, Integer
)
629 assert_col_type(creature_table
.c
.name
, VARCHAR
)
630 assert creature_table
.c
.name
.nullable
is False
631 #assert creature_table.c.name.index is True
632 #assert creature_table.c.name.unique is True
633 assert_col_type(creature_table
.c
.num_legs
, Integer
)
634 assert creature_table
.c
.num_legs
.nullable
is False
635 assert_col_type(creature_table
.c
.is_demon
, Boolean
)
637 # Check the structure of the level table
640 autoload
=True, autoload_with
=engine
)
641 assert set(level_table
.c
.keys()) == set(
642 ['id', 'name', 'description', 'exits'])
643 assert_col_type(level_table
.c
.id, VARCHAR
)
644 assert level_table
.c
.id.primary_key
is True
645 assert_col_type(level_table
.c
.name
, VARCHAR
)
646 assert_col_type(level_table
.c
.description
, VARCHAR
)
647 # Skipping exits... Not sure if we can detect pickletype, not a
648 # big deal regardless.
650 # Now check to see if stuff seems to be in there.
653 # Check the creation of the foundation rows on the creature table
654 creature
= session
.query(Creature1
).filter_by(
655 name
=u
'goblin').one()
656 assert creature
.num_legs
== 2
657 assert creature
.is_demon
== False
659 creature
= session
.query(Creature1
).filter_by(
660 name
=u
'cerberus').one()
661 assert creature
.num_legs
== 4
662 assert creature
.is_demon
== True
665 # Check the creation of the inserted rows on the creature and levels tables
667 creature
= session
.query(Creature1
).filter_by(
668 name
=u
'centipede').one()
669 assert creature
.num_legs
== 100
670 assert creature
.is_demon
== False
672 creature
= session
.query(Creature1
).filter_by(
674 assert creature
.num_legs
== 4
675 assert creature
.is_demon
== False
677 creature
= session
.query(Creature1
).filter_by(
678 name
=u
'wizardsnake').one()
679 assert creature
.num_legs
== 0
680 assert creature
.is_demon
== True
682 level
= session
.query(Level1
).filter_by(
683 id=u
'necroplex').one()
684 assert level
.name
== u
'The Necroplex'
685 assert level
.description
== u
'A complex full of pure deathzone.'
686 assert level
.exits
== {
687 'deathwell': 'evilstorm',
688 'portal': 'central_park'}
690 level
= session
.query(Level1
).filter_by(
691 id=u
'evilstorm').one()
692 assert level
.name
== u
'Evil Storm'
693 assert level
.description
== u
'A storm full of pure evil.'
694 assert level
.exits
== {} # You still can't escape the evilstorm!
696 level
= session
.query(Level1
).filter_by(
697 id=u
'central_park').one()
698 assert level
.name
== u
'Central Park, NY, NY'
699 assert level
.description
== u
"New York's friendly Central Park."
700 assert level
.exits
== {
701 'portal': 'necroplex'}
703 # Create new migration manager, but make sure the db migration
704 # isn't said to be updated yet
705 printer
= CollectingPrinter()
706 migration_manager
= MigrationManager(
707 u
'__main__', SET3_MODELS
, FOUNDATIONS
, SET3_MIGRATIONS
, Session(),
710 assert migration_manager
.latest_migration
== 8
711 assert migration_manager
.database_current_migration
== 0
714 result
= migration_manager
.init_or_migrate()
716 # Make sure result was "migrated"
717 assert result
== u
'migrated'
719 # TODO: Check output to user
720 assert printer
.combined_string
== """\
721 -> Updating main mediagoblin tables:
722 + Running migration 1, "creature_remove_is_demon"... done.
723 + Running migration 2, "creature_powers_new_table"... done.
724 + Running migration 3, "level_exits_new_table"... done.
725 + Running migration 4, "creature_num_legs_to_num_limbs"... done.
726 + Running migration 5, "level_exit_index_from_and_to_level"... done.
727 + Running migration 6, "creature_power_index_creature"... done.
728 + Running migration 7, "creature_power_hitpower_to_float"... done.
729 + Running migration 8, "creature_power_name_creature_unique"... done.
732 # Make sure version matches expected
733 migration_manager
= MigrationManager(
734 u
'__main__', SET3_MODELS
, FOUNDATIONS
, SET3_MIGRATIONS
, Session(),
736 assert migration_manager
.latest_migration
== 8
737 assert migration_manager
.database_current_migration
== 8
739 # Check all things in database match expected
741 # Check the creature table
742 metadata
= MetaData(bind
=engine
)
743 creature_table
= Table(
744 'creature', metadata
,
745 autoload
=True, autoload_with
=engine
)
746 # assert set(creature_table.c.keys()) == set(
747 # ['id', 'name', 'num_limbs'])
748 assert set(creature_table
.c
.keys()) == set(
749 [u
'id', 'name', u
'num_limbs', u
'is_demon'])
750 assert_col_type(creature_table
.c
.id, Integer
)
751 assert_col_type(creature_table
.c
.name
, VARCHAR
)
752 assert creature_table
.c
.name
.nullable
is False
753 #assert creature_table.c.name.index is True
754 #assert creature_table.c.name.unique is True
755 assert_col_type(creature_table
.c
.num_limbs
, Integer
)
756 assert creature_table
.c
.num_limbs
.nullable
is False
758 # Check the CreaturePower table
759 creature_power_table
= Table(
760 'creature_power', metadata
,
761 autoload
=True, autoload_with
=engine
)
762 assert set(creature_power_table
.c
.keys()) == set(
763 ['id', 'creature', 'name', 'description', 'hitpower'])
764 assert_col_type(creature_power_table
.c
.id, Integer
)
765 assert_col_type(creature_power_table
.c
.creature
, Integer
)
766 assert creature_power_table
.c
.creature
.nullable
is False
767 assert_col_type(creature_power_table
.c
.name
, VARCHAR
)
768 assert_col_type(creature_power_table
.c
.description
, VARCHAR
)
769 assert_col_type(creature_power_table
.c
.hitpower
, Float
)
770 assert creature_power_table
.c
.hitpower
.nullable
is False
772 # Check the structure of the level table
775 autoload
=True, autoload_with
=engine
)
776 assert set(level_table
.c
.keys()) == set(
777 ['id', 'name', 'description'])
778 assert_col_type(level_table
.c
.id, VARCHAR
)
779 assert level_table
.c
.id.primary_key
is True
780 assert_col_type(level_table
.c
.name
, VARCHAR
)
781 assert_col_type(level_table
.c
.description
, VARCHAR
)
783 # Check the structure of the level_exits table
784 level_exit_table
= Table(
785 'level_exit', metadata
,
786 autoload
=True, autoload_with
=engine
)
787 assert set(level_exit_table
.c
.keys()) == set(
788 ['id', 'name', 'from_level', 'to_level'])
789 assert_col_type(level_exit_table
.c
.id, Integer
)
790 assert_col_type(level_exit_table
.c
.name
, VARCHAR
)
791 assert_col_type(level_exit_table
.c
.from_level
, VARCHAR
)
792 assert level_exit_table
.c
.from_level
.nullable
is False
793 #assert level_exit_table.c.from_level.index is True
794 assert_col_type(level_exit_table
.c
.to_level
, VARCHAR
)
795 assert level_exit_table
.c
.to_level
.nullable
is False
796 #assert level_exit_table.c.to_level.index is True
798 # Now check to see if stuff seems to be in there.
802 # Start with making sure that the foundations did not run again
803 assert session
.query(Creature3
).filter_by(
804 name
=u
'goblin').count() == 1
805 assert session
.query(Creature3
).filter_by(
806 name
=u
'cerberus').count() == 1
808 # Then make sure the models have been migrated correctly
809 creature
= session
.query(Creature3
).filter_by(
810 name
=u
'centipede').one()
811 assert creature
.num_limbs
== 100.0
812 assert creature
.magical_powers
== []
814 creature
= session
.query(Creature3
).filter_by(
816 assert creature
.num_limbs
== 4.0
817 assert creature
.magical_powers
== []
819 creature
= session
.query(Creature3
).filter_by(
820 name
=u
'wizardsnake').one()
821 assert creature
.num_limbs
== 0.0
822 assert creature
.magical_powers
== []
824 level
= session
.query(Level3
).filter_by(
825 id=u
'necroplex').one()
826 assert level
.name
== u
'The Necroplex'
827 assert level
.description
== u
'A complex full of pure deathzone.'
828 level_exits
= _get_level3_exits(session
, level
)
829 assert level_exits
== {
830 u
'deathwell': u
'evilstorm',
831 u
'portal': u
'central_park'}
833 level
= session
.query(Level3
).filter_by(
834 id=u
'evilstorm').one()
835 assert level
.name
== u
'Evil Storm'
836 assert level
.description
== u
'A storm full of pure evil.'
837 level_exits
= _get_level3_exits(session
, level
)
838 assert level_exits
== {} # You still can't escape the evilstorm!
840 level
= session
.query(Level3
).filter_by(
841 id=u
'central_park').one()
842 assert level
.name
== u
'Central Park, NY, NY'
843 assert level
.description
== u
"New York's friendly Central Park."
844 level_exits
= _get_level3_exits(session
, level
)
845 assert level_exits
== {
846 'portal': 'necroplex'}
849 #def test_set2_to_set3():
850 # Create / connect to database
851 # Create tables by migrating on empty initial set
853 # Install the initial set
854 # Check version in database
855 # Sanity check a few things in the database
858 # Make sure version matches expected
859 # Check all things in database match expected
863 #def test_set1_to_set2_to_set3():
864 # Create / connect to database
865 # Create tables by migrating on empty initial set
867 # Install the initial set
868 # Check version in database
869 # Sanity check a few things in the database
872 # Make sure version matches expected
873 # Check all things in database match expected
876 # Make sure version matches expected again
877 # Check all things in database match expected again
880 # creature_table = Table(
881 # 'creature', metadata,
882 # autoload=True, autoload_with=db_conn.bind)
883 # assert set(creature_table.c.keys()) == set(
884 # ['id', 'name', 'num_legs'])
885 # assert_col_type(creature_table.c.id, Integer)
886 # assert_col_type(creature_table.c.name, VARCHAR)
887 # assert creature_table.c.name.nullable is False
888 # assert creature_table.c.name.index is True
889 # assert creature_table.c.name.unique is True
890 # assert_col_type(creature_table.c.num_legs, Integer)
891 # assert creature_table.c.num_legs.nullable is False
893 # # Check the CreaturePower table
894 # creature_power_table = Table(
895 # 'creature_power', metadata,
896 # autoload=True, autoload_with=db_conn.bind)
897 # assert set(creature_power_table.c.keys()) == set(
898 # ['id', 'creature', 'name', 'description', 'hitpower'])
899 # assert_col_type(creature_power_table.c.id, Integer)
900 # assert_col_type(creature_power_table.c.creature, Integer)
901 # assert creature_power_table.c.creature.nullable is False
902 # assert_col_type(creature_power_table.c.name, VARCHAR)
903 # assert_col_type(creature_power_table.c.description, VARCHAR)
904 # assert_col_type(creature_power_table.c.hitpower, Integer)
905 # assert creature_power_table.c.hitpower.nullable is False
907 # # Check the structure of the level table
908 # level_table = Table(
910 # autoload=True, autoload_with=db_conn.bind)
911 # assert set(level_table.c.keys()) == set(
912 # ['id', 'name', 'description'])
913 # assert_col_type(level_table.c.id, VARCHAR)
914 # assert level_table.c.id.primary_key is True
915 # assert_col_type(level_table.c.name, VARCHAR)
916 # assert_col_type(level_table.c.description, VARCHAR)
918 # # Check the structure of the level_exits table
919 # level_exit_table = Table(
920 # 'level_exit', metadata,
921 # autoload=True, autoload_with=db_conn.bind)
922 # assert set(level_exit_table.c.keys()) == set(
923 # ['id', 'name', 'from_level', 'to_level'])
924 # assert_col_type(level_exit_table.c.id, Integer)
925 # assert_col_type(level_exit_table.c.name, VARCHAR)
926 # assert_col_type(level_exit_table.c.from_level, VARCHAR)
927 # assert level_exit_table.c.from_level.nullable is False
928 # assert_col_type(level_exit_table.c.to_level, VARCHAR)