def test_delete_recipe_task_results_for_deleted_job(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/22.sql')) # populate test jobs connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'bz1322700-and-bz1337790-migration-setup.sql')) # run migration upgrade_db(self.migration_metadata) # Job one's recipe task results should not be deleted self.assertEquals( self.migration_session.query(RecipeTaskResult).filter_by(recipe_task_id=1).count(), 1) # Job one's log recipe task results should not be deleted self.assertEquals( self.migration_session.query(LogRecipeTaskResult).filter_by(recipe_task_result_id=1).count(), 1) # Job two's recipe task results should be deleted self.assertEquals( self.migration_session.query(RecipeTaskResult).filter_by(recipe_task_id=2).count(), 0) # Job two's log recipe task results should be deleted self.assertEquals( self.migration_session.query(LogRecipeTaskResult).filter_by(recipe_task_result_id=2).count(), 0)
def test_Installing_status_is_mapped_on_downgrade(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/22.sql')) upgrade_db(self.migration_metadata) # create a job in Installing state connection.execute( "INSERT INTO job (owner_id, retention_tag_id, dirty_version, clean_version, status) " "VALUES (1, 1, '', '', 'Installing')") connection.execute( "INSERT INTO recipe_set (job_id, queue_time, waived, status) " "VALUES (1, '2015-11-09 17:03:04', FALSE, 'Installing')") connection.execute( "INSERT INTO recipe (type, recipe_set_id, autopick_random, status) " "VALUES ('machine_recipe', 1, FALSE, 'Installing')") # run the downgrade downgrade_db(self.migration_metadata, '22') # status should be Running so that it works with 22.x with self.migration_metadata.bind.connect() as connection: self.assertEquals( connection.scalar('SELECT status FROM job WHERE id = 1'), u'Running') self.assertEquals( connection.scalar('SELECT status FROM recipe_set WHERE id = 1'), u'Running') self.assertEquals( connection.scalar('SELECT status FROM recipe WHERE id = 1'), u'Running')
def test_redhat_production_20130304(self): connection = self.migration_metadata.bind.connect() connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/redhat-production-20130304.sql')) upgrade_db(self.migration_metadata) self.check_migrated_schema() downgrade_db(self.migration_metadata, 'base')
def test_clear_removed_users_from_groups(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/21.sql')) # bob is in the colonel group connection.execute( "INSERT INTO tg_user (user_id, user_name, display_name, email_address, disabled, removed) " "VALUES (2, 'bob', 'Bob', '*****@*****.**', 1, '2015-12-01 15:43:28')") connection.execute( "INSERT INTO tg_group (group_id, group_name, display_name, ldap) " "VALUES (3, 'colonel', 'Colonel', 0)") connection.execute( "INSERT INTO user_group (user_id, group_id, is_owner) " "VALUES (2, 3, 1)") # run migration upgrade_db(self.migration_metadata) colonel = self.migration_session.query(Group).get(3) # check that bob is removed from the group bob = self.migration_session.query(User).get(2) self.assertNotIn(colonel, bob.groups) self.assertNotIn(bob, colonel.users) self.assertEqual(colonel.activity[0].field_name, u'User') self.assertEqual(colonel.activity[0].action, u'Removed') self.assertEqual(colonel.activity[0].old_value, u'bob') self.assertEqual(colonel.activity[0].service, u'Migration') self.assertEqual(colonel.activity[0].user.user_name, u'admin')
def test_redhat_production_20140820(self): with self.migration_engine.connect() as connection: connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/redhat-production-20140820.sql')) upgrade_db(self.migration_metadata) self.check_migrated_schema() downgrade_db(self.migration_metadata, 'base')
def test_migrate_recipe_set_comments_and_waived_from_nacked(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/21.sql')) # job owned by admin, with a recipe set which has been nacked and commented connection.execute( "INSERT INTO job (owner_id, retention_tag_id, dirty_version, clean_version) " "VALUES (1, 1, '', '')") connection.execute( "INSERT INTO recipe_set (job_id, queue_time) " "VALUES (1, '2015-11-05 16:31:01')") connection.execute( "INSERT INTO recipe_set_nacked (recipe_set_id, response_id, comment, created) " "VALUES (1, 2, 'it broke', '2015-11-05 16:32:40')") # run migration upgrade_db(self.migration_metadata) # check that the comment row was created comments = self.migration_session.query(RecipeSetComment).all() self.assertEqual(len(comments), 1) self.assertEqual(comments[0].recipe_set_id, 1) self.assertEqual(comments[0].comment, u'it broke') self.assertEqual(comments[0].user.user_name, u'admin') self.assertEqual(comments[0].created, datetime.datetime(2015, 11, 5, 16, 32, 40)) # check that the recipe set is waived recipeset = self.migration_session.query(RecipeSet).first() self.assertEqual(recipeset.waived, True)
def test_check_db(self): with self.migration_engine.connect() as connection: connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/21.sql')) self.assertTrue(check_db(self.migration_metadata, '171c07fb4970')) self.assertFalse(check_db(self.migration_metadata, 'head')) upgrade_db(self.migration_metadata) self.assertTrue(check_db(self.migration_metadata, 'head'))
def test_already_upgraded(self): connection = self.migration_metadata.bind.connect() connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/0.17.sql')) upgrade_db(self.migration_metadata) # Upgrading an already-upgraded database should be a no-op. upgrade_db(self.migration_metadata) self.check_migrated_schema()
def test_redhat_production_20120216(self): connection = self.migration_metadata.bind.connect() connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/redhat-production-20120216.sql')) raise unittest.SkipTest('Database migrations are not implemented ' 'far enough into the past yet') upgrade_db(self.migration_metadata) self.check_migrated_schema() downgrade_db(self.migration_metadata, 'base')
def test_full_downgrade_then_upgrade(self): # The point is to test that the complete *downgrade* sequence is valid, # by then upgrading again and making sure we still have a correct schema. connection = self.migration_metadata.bind.connect() connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/0.11.sql')) upgrade_db(self.migration_metadata) downgrade_db(self.migration_metadata, 'base') upgrade_db(self.migration_metadata) self.check_migrated_schema()
def test_migrate_system_groups_to_pools(self): connection = self.migration_metadata.bind.connect() # create the DB schema for beaker 19 connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/19.sql')) # populate synthetic data into relevant tables connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (1, "test.fqdn.name", "2015-01-01", 1, 1, 1, 1)') connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (2, "test1.fqdn.name", "2015-01-01", 1, 1, 1, 1)') connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (3, "test2.fqdn.name", "2015-01-01", 1, 1, 1, 1)') connection.execute('INSERT INTO tg_group(group_id, group_name, ldap) VALUES (3, "group1", FALSE)') connection.execute('INSERT INTO tg_group(group_id, group_name, ldap) VALUES (4, "group2", FALSE)') connection.execute('INSERT INTO system_group(system_id, group_id) VALUES (1, 3)') connection.execute('INSERT INTO system_group(system_id, group_id) VALUES (2, 3)') connection.execute('INSERT INTO system_group(system_id, group_id) VALUES (1, 4)') connection.execute('INSERT INTO system_group(system_id, group_id) VALUES (3, 4)') # Migrate to system pools upgrade_db(self.migration_metadata) # check data for system_pool created_pools = self.migration_session.query(SystemPool).all() self.assertItemsEqual(['group1', 'group2'], [pool.name for pool in created_pools]) self.assertItemsEqual(['Pool migrated from group group1', 'Pool migrated from group group2'], [pool.description for pool in created_pools]) expected_system_pool_owners = { u'group1': u'group1', u'group2': u'group2', } for pool in expected_system_pool_owners.keys(): p = self.migration_session.query(SystemPool).filter(SystemPool.name == pool).one() self.assertEquals(p.owning_group, self.migration_session.query(Group).filter(Group.group_name == pool).one()) expected_system_pools_map = { u'test.fqdn.name': [u'group1', u'group2'], u'test1.fqdn.name': [u'group1'], u'test2.fqdn.name': [u'group2'], } for system in expected_system_pools_map.keys(): s = self.migration_session.query(System).filter(System.fqdn == system).one() self.assertItemsEqual([p.name for p in s.pools], expected_system_pools_map[system]) min_user_id = min([user.id for user in self.migration_session.query(User).all()]) for pool in created_pools: self.assertEquals(pool.activity[-1].action, u'Created') self.assertEquals(pool.activity[-1].field_name, u'Pool') self.assertEquals(pool.activity[-1].user.user_id, min_user_id) self.assertEquals(pool.activity[-1].new_value, pool.name) self.assertEquals(pool.activity[-1].service, u'Migration')
def test_migrate_ldap_groups(self): group_name = u'my_ldap_group' with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/21.sql')) connection.execute( "INSERT INTO tg_group (group_name, ldap) " "VALUES ('%s', 1)" % group_name) # run migration upgrade_db(self.migration_metadata) # check that the group row was created group = self.migration_session.query(Group)\ .filter(Group.group_name == group_name).one() self.assertEqual(group.group_name, group_name) self.assertEqual(group.membership_type, GroupMembershipType.ldap)
def test_clear_meaningless_system_activities(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/20.sql')) connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (1, "test.fqdn.name", "2015-12-15", 1, 1, 1, 1)') connection.execute("INSERT INTO activity " "(id, user_id, created, type, field_name, service, action, old_value, new_value) " "VALUES (1, NULL, '2015-12-15 01:11:56', 'system_activity', 'System Acess Policy', " "'HTTP', 'changed', 'Custom Access Policy', 'Custom access policy')") connection.execute("INSERT INTO system_activity (id, system_id) " "VALUES (1, 1)") # run migration upgrade_db(self.migration_metadata) # check that systtem activity and activity have been deleted self.assertEquals( self.migration_session.query(SystemActivity).filter_by(id=1).count(), 0)
def test_clear_removed_users_from_access_policies(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/21.sql')) # fred is in a custom access policy (1) and a pool access policy (2) connection.execute( "INSERT INTO tg_user (user_id, user_name, display_name, email_address, disabled, removed) " "VALUES (2, 'fred', 'Fred', '*****@*****.**', 1, '2015-12-01 17:18:56')") connection.execute("INSERT INTO system_access_policy (id) VALUES (1)") connection.execute( "INSERT INTO system_access_policy_rule (policy_id, user_id, group_id, permission) " "VALUES (1, 2, NULL, 'reserve')") connection.execute("INSERT INTO system " "(id, fqdn, date_added, owner_id, type, status, kernel_type_id, " " custom_access_policy_id, active_access_policy_id) " "VALUES (1, 'test.example.invalid', '2015-01-01', 1, 'Machine', 'Automated', 1, 1, 1)") connection.execute("INSERT INTO system_access_policy (id) VALUES (2)") connection.execute( "INSERT INTO system_access_policy_rule (policy_id, user_id, group_id, permission) " "VALUES (2, 2, NULL, 'loan_self')") connection.execute( "INSERT INTO system_pool (id, name, owning_user_id, access_policy_id) " "VALUES (1, 'colonel-hard-wear', 1, 2)") # run migration upgrade_db(self.migration_metadata) # check that fred is removed from the system access policy system = self.migration_session.query(System).get(1) self.assertEqual([], system.custom_access_policy.rules) self.assertEqual(system.activity[0].field_name, u'Access Policy Rule') self.assertEqual(system.activity[0].action, u'Removed') self.assertEqual(system.activity[0].old_value, u'<grant reserve to fred>') self.assertEqual(system.activity[0].service, u'Migration') self.assertEqual(system.activity[0].user.user_name, u'admin') # check that fred is removed from the pool access policy pool = self.migration_session.query(SystemPool).get(1) self.assertEqual([], pool.access_policy.rules) self.assertEqual(pool.activity[0].field_name, u'Access Policy Rule') self.assertEqual(pool.activity[0].action, u'Removed') self.assertEqual(pool.activity[0].old_value, u'<grant loan_self to fred>') self.assertEqual(pool.activity[0].service, u'Migration') self.assertEqual(pool.activity[0].user.user_name, u'admin')
def test_migrate_system_access_policies_to_custom_access_policies(self): connection = self.migration_metadata.bind.connect() # create the DB schema for beaker 19 connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/19.sql')) # populate synthetic data into relevant tables connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (1, "test.fqdn.name", "2015-01-01", 1, 1, 1, 1)') connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (2, "test1.fqdn.name", "2015-01-01", 1, 1, 1, 1)') connection.execute('INSERT INTO system(id, fqdn, date_added, owner_id, type, status, kernel_type_id) VALUES (3, "test2.fqdn.name", "2015-01-01", 1, 1, 1, 1)') connection.execute('INSERT INTO system_access_policy(id, system_id) VALUES (1, 2)') connection.execute('INSERT INTO system_access_policy(id, system_id) VALUES (2, 1)') connection.execute('INSERT INTO system_access_policy(id, system_id) VALUES (3, 3)') # Migrate upgrade_db(self.migration_metadata) # check the data has been migrated successfully systems = self.migration_session.query(System).all() expected_system_policy_map = { 'test.fqdn.name':2, 'test1.fqdn.name':1, 'test2.fqdn.name':3 } for s in systems: self.assertEquals(s.custom_access_policy_id, expected_system_policy_map[s.fqdn]) self.assertEquals(s.active_access_policy_id, expected_system_policy_map[s.fqdn]) # downgrade test downgrade_db(self.migration_metadata, '1c444555ea3d') # XXX self.metadata.reflect() isn't for some reason detecting # the schema changes migration_metadata = sqlalchemy.MetaData(bind=self.migration_engine) migration_metadata.reflect() self.assertIn('system_id', migration_metadata.tables['system_access_policy'].columns.keys()) self.assertNotIn('system_access_policy_id', migration_metadata.tables['system_pool'].columns.keys())
def test_migrate_recipe_reviewed_status_from_nacked(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/21.sql')) # job owned by admin, with a recipe set which has been acked connection.execute( "INSERT INTO job (owner_id, retention_tag_id, dirty_version, clean_version) " "VALUES (1, 1, '', '')") connection.execute( "INSERT INTO recipe_set (job_id, queue_time) " "VALUES (1, '2015-11-09 17:03:04')") connection.execute( "INSERT INTO recipe (type, recipe_set_id, autopick_random) " "VALUES ('machine_recipe', 1, FALSE)") connection.execute( "INSERT INTO recipe_set_nacked (recipe_set_id, response_id, comment, created) " "VALUES (1, 1, NULL, '2015-11-09 17:32:03')") # run migration upgrade_db(self.migration_metadata) # check that the recipe is marked as reviewed by admin recipe = self.migration_session.query(Recipe).get(1) self.assertEqual(recipe.get_reviewed_state(User.by_user_name(u'admin')), True)
def test_delete_duplicate_osmajor_install_options(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/20.sql')) # RedHatEnterpriseLinux6 has duplicate rows in osmajor_install_options, # RedHatEnterpriseLinux7 just has one row connection.execute( "INSERT INTO osmajor (id, osmajor) " "VALUES (1, 'RedHatEnterpriseLinux6')") connection.execute( "INSERT INTO osmajor_install_options (osmajor_id, arch_id, ks_meta) " "VALUES (1, NULL, 'testone'), (1, NULL, 'testtwo')") connection.execute( "INSERT INTO osmajor (id, osmajor) " "VALUES (2, 'RedHatEnterpriseLinux7')") connection.execute( "INSERT INTO osmajor_install_options (osmajor_id, arch_id, ks_meta) " "VALUES (2, NULL, 'testthree')") # run migration upgrade_db(self.migration_metadata) # check that there is only one row per osmajor-arch combination row_counts = self.migration_session.query(OSMajorInstallOptions.osmajor_id, OSMajorInstallOptions.arch_id, func.count())\ .group_by(OSMajorInstallOptions.osmajor_id, OSMajorInstallOptions.arch_id) for osmajor_id, arch_id, count in row_counts: self.assertEquals(count, 1, 'Expected to find only one row in osmajor_install_options ' 'for osmajor_id %s, arch_id %s' % (osmajor_id, arch_id)) # check that the most recent install options are kept, older ones are deleted installopts = self.migration_session.query(OSMajorInstallOptions)\ .join(OSMajorInstallOptions.osmajor)\ .filter(OSMajor.osmajor == u'RedHatEnterpriseLinux6', OSMajorInstallOptions.arch == None)\ .one() self.assertEquals(installopts.ks_meta, u'testtwo')
def test_delete_orphaned_system_access_policies(self): connection = self.migration_metadata.bind.connect() # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/20.sql')) # access policy 1 is referenced, access policy 2 is an orphan connection.execute("INSERT INTO system_access_policy (id) VALUES (1)") connection.execute("INSERT INTO system_access_policy_rule " "(policy_id, user_id, group_id, permission) " "VALUES (1, NULL, NULL, 'view')") connection.execute("INSERT INTO system " "(fqdn, date_added, owner_id, type, status, kernel_type_id, " " custom_access_policy_id, active_access_policy_id) " "VALUES ('test.example.invalid', '2015-01-01', 1, 1, 1, 1, 1, 1)") connection.execute("INSERT INTO system_access_policy (id) VALUES (2)") connection.execute("INSERT INTO system_access_policy_rule " "(policy_id, user_id, group_id, permission) " "VALUES (2, NULL, NULL, 'view')") # run migration upgrade_db(self.migration_metadata) # check that access policy 2 has been deleted self.assertEquals( self.migration_session.query(SystemAccessPolicy).filter_by(id=2).count(), 0)
def test_delete_orphaned_system_access_policies(self): with self.migration_metadata.bind.connect() as connection: # populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/20.sql')) # access policy 1 is referenced, access policy 2 is an orphan connection.execute("INSERT INTO system_access_policy (id) VALUES (1)") connection.execute("INSERT INTO system_access_policy_rule " "(policy_id, user_id, group_id, permission) " "VALUES (1, NULL, NULL, 'view')") connection.execute("INSERT INTO system " "(fqdn, date_added, owner_id, type, status, kernel_type_id, " " custom_access_policy_id, active_access_policy_id) " "VALUES ('test.example.invalid', '2015-01-01', 1, 1, 1, 1, 1, 1)") connection.execute("INSERT INTO system_access_policy (id) VALUES (2)") connection.execute("INSERT INTO system_access_policy_rule " "(policy_id, user_id, group_id, permission) " "VALUES (2, NULL, NULL, 'view')") # run migration upgrade_db(self.migration_metadata) # check that access policy 2 has been deleted self.assertEquals( self.migration_session.query(SystemAccessPolicy).filter_by(id=2).count(), 0)
def test_from_017(self): connection = self.migration_metadata.bind.connect() connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/0.17.sql')) upgrade_db(self.migration_metadata) self.check_migrated_schema()
def test_from_23(self): with self.migration_engine.connect() as connection: connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/23.sql')) upgrade_db(self.migration_metadata) self.check_migrated_schema()
def test_populate_installation_from_recipe_resource(self): with self.migration_metadata.bind.connect() as connection: # Populate empty database connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'database-dumps/22.sql')) # Populate test data for migration connection.execute(pkg_resources.resource_string('bkr.inttest.server', 'bz991245-migration-setup.sql')) # Run migration upgrade_db(self.migration_metadata) # Check that installation has been populated for recipe 1 (system_resource) recipe = self.migration_session.query(Recipe).get(1) self.assertEqual(recipe.installation.distro_tree.distro.name, u'distro') self.assertEqual(recipe.installation.kernel_options, u'') # populated below self.assertEqual(recipe.installation.rendered_kickstart.kickstart, u'lol') self.assertEqual(recipe.installation.system.fqdn, u'test.fqdn.name') self.assertEqual(recipe.installation.rebooted, datetime.datetime(2016, 2, 16, 1, 0, 5)) self.assertEqual(recipe.installation.install_started, datetime.datetime(2016, 2, 16, 1, 1, 0)) self.assertEqual(recipe.installation.install_finished, datetime.datetime(2016, 2, 16, 1, 20, 0)) self.assertEqual(recipe.installation.postinstall_finished, datetime.datetime(2016, 2, 16, 1, 21, 0)) self.assertEqual(recipe.installation.created, datetime.datetime(2016, 2, 16, 1, 0, 0)) self.migration_session.close() # Run online data migration (two batches) migration = DataMigration(name=u'commands-for-recipe-installations') finished = migration.migrate_one_batch(self.migration_metadata.bind) self.assertFalse(finished) finished = migration.migrate_one_batch(self.migration_metadata.bind) self.assertTrue(finished) # Check that commands have been associated with their installation recipe = self.migration_session.query(Recipe).get(1) self.assertEqual(recipe.installation.kernel_options, u'ks=lol') installation_cmd = self.migration_session.query(CommandActivity).get(1) self.assertEqual(installation_cmd.installation, recipe.installation) manual_cmd = self.migration_session.query(CommandActivity).get(2) self.assertEqual(manual_cmd.installation, None) reprovision_cmd = self.migration_session.query(CommandActivity).get(3) self.assertEqual(reprovision_cmd.installation, None) # Check that installation has been populated for recipe 2 (guest_resource) recipe = self.migration_session.query(Recipe).get(2) self.assertEqual(recipe.installation.distro_tree.distro.name, u'distro') self.assertEqual(recipe.installation.kernel_options, u'') self.assertEqual(recipe.installation.rendered_kickstart.kickstart, u'lol2') self.assertIsNone(recipe.installation.system) self.assertIsNone(recipe.installation.rebooted) self.assertEqual(recipe.installation.install_started, datetime.datetime(2016, 2, 16, 1, 31, 0)) self.assertEqual(recipe.installation.install_finished, datetime.datetime(2016, 2, 16, 1, 40, 0)) self.assertEqual(recipe.installation.postinstall_finished, datetime.datetime(2016, 2, 16, 1, 41, 0)) self.assertEqual(recipe.installation.created, datetime.datetime(2016, 2, 16, 1, 0, 0)) # Check that installation has been populated for recipes 3 and 4 # (host and guest that never started) recipe = self.migration_session.query(Recipe).get(3) self.assertEqual(recipe.installation.created, datetime.datetime(2016, 2, 17, 0, 0, 0)) recipe = self.migration_session.query(Recipe).get(4) self.assertEqual(recipe.installation.created, datetime.datetime(2016, 2, 17, 0, 0, 0))