Cleaning test DB without Alembic migrations

On the Fuel CI we have no rights to drop and create DB.
In the tests we are downgrading and upgrading DB schema by Alembic
migrations. In case of adding migrations in one review we had
all other reviews broken due to Alembic failures on attempt to
downgrade DB schema.
As fix we are fallback to the cleaning DB without migrations
in case of Alembic error on the schema downgrade.

Change-Id: I65faf43c28427594495c67696ca190e7fe29f083
Closes-Bug: #1556876
This commit is contained in:
Alexander Kislitsky 2016-03-14 17:29:06 +03:00 committed by Bulat Gaifullin
parent e9ec2111a7
commit ea6263af70
2 changed files with 88 additions and 8 deletions

View File

@ -68,20 +68,57 @@ class BaseTest(TestCase):
class DbTest(BaseTest):
def get_migrations_dir(self):
return os.path.join(os.path.dirname(__file__),
'..', 'api', 'db', 'migrations')
def setUp(self):
super(DbTest, self).setUp()
# Connection must be closed before DB migration
db.session.close()
# Cleaning all changes from the previous test
db.session.rollback()
# Cleaning DB. It useful in case of tests failure
directory = os.path.join(os.path.dirname(__file__),
'..', 'api', 'db', 'migrations')
directory = self.get_migrations_dir()
with app.app_context():
try:
flask_migrate.downgrade(directory=directory,
revision='base')
except CommandError:
# Workaround for the first migration
pass
except CommandError as e:
app.logger.debug("DB migration downgrade failed: %s", e)
self.clean_db()
flask_migrate.upgrade(directory=directory)
def clean_db(self):
app.logger.debug("Cleaning DB without Alembic")
# Removing tables
tables = db.session.execute(
"SELECT table_name FROM information_schema.tables "
"WHERE table_schema = 'public'")
table_names = list(item[0] for item in tables)
if table_names:
app.logger.debug("Removing tables: %s", table_names)
db.session.execute(
"DROP TABLE {0} CASCADE".format(','.join(table_names)))
# Removing sequences
sequences = list(item[0] for item in db.session.execute(
"SELECT relname FROM pg_class WHERE relkind='S'"))
sequence_names = list(item[0] for item in sequences)
if sequence_names:
app.logger.debug("Removing sequences: %s", sequence_names)
db.session.execute(
"DROP SEQUENCE {0}".format(','.join(sequences)))
# Removing enums
enums = db.session.execute(
"SELECT t.typname FROM pg_type t JOIN pg_catalog.pg_namespace n "
"ON n.oid = t.typnamespace WHERE n.nspname='public'")
enum_names = list(item[0] for item in enums)
if enum_names:
app.logger.debug("Removing types: %s", enum_names)
db.session.execute(
"DROP TYPE {0}".format(','.join(enum_names)))
# Committing DDL changes
db.session.commit()

View File

@ -0,0 +1,43 @@
# Copyright 2016 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from alembic.util import CommandError
import flask_migrate
from collector.test.base import DbTest
from collector.api.app import app
from collector.api.app import db
class TestMigration(DbTest):
def test_clean_db(self):
# Crashing alembic versions history
db.session.execute("UPDATE alembic_version SET version_num='x'")
db.session.commit()
migrations_dir = self.get_migrations_dir()
with app.app_context():
# Checking migrations are broken
self.assertRaises(
CommandError, flask_migrate.downgrade,
directory=migrations_dir, revision='base'
)
self.clean_db()
# Checking migrations flow is fixed
flask_migrate.downgrade(directory=migrations_dir, revision='base')
flask_migrate.upgrade(directory=migrations_dir)