Merge "Add sqlalchemy migration utils.check_shadow_table method"
This commit is contained in:
@@ -18,16 +18,24 @@
|
|||||||
from migrate.changeset import UniqueConstraint
|
from migrate.changeset import UniqueConstraint
|
||||||
from sqlalchemy import Integer, DateTime, String
|
from sqlalchemy import Integer, DateTime, String
|
||||||
from sqlalchemy import MetaData, Table, Column
|
from sqlalchemy import MetaData, Table, Column
|
||||||
|
from sqlalchemy.exc import NoSuchTableError
|
||||||
from sqlalchemy.exc import SAWarning
|
from sqlalchemy.exc import SAWarning
|
||||||
from sqlalchemy.sql import select
|
from sqlalchemy.sql import select
|
||||||
from sqlalchemy.types import UserDefinedType
|
from sqlalchemy.types import UserDefinedType
|
||||||
|
|
||||||
|
from nova.db.sqlalchemy import api as db
|
||||||
from nova.db.sqlalchemy import utils
|
from nova.db.sqlalchemy import utils
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.tests import test_migrations
|
from nova.tests import test_migrations
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
class CustomType(UserDefinedType):
|
||||||
|
"""Dummy column type for testing unsupported types."""
|
||||||
|
def get_col_spec(self):
|
||||||
|
return "CustomType"
|
||||||
|
|
||||||
|
|
||||||
class TestMigrationUtils(test_migrations.BaseMigrationTestCase):
|
class TestMigrationUtils(test_migrations.BaseMigrationTestCase):
|
||||||
"""Class for testing utils that are used in db migrations."""
|
"""Class for testing utils that are used in db migrations."""
|
||||||
|
|
||||||
@@ -75,11 +83,6 @@ class TestMigrationUtils(test_migrations.BaseMigrationTestCase):
|
|||||||
|
|
||||||
def test_util_drop_unique_constraint_with_not_supported_sqlite_type(self):
|
def test_util_drop_unique_constraint_with_not_supported_sqlite_type(self):
|
||||||
|
|
||||||
class CustomType(UserDefinedType):
|
|
||||||
"""Dummy column type for testing unsupported types."""
|
|
||||||
def get_col_spec(self):
|
|
||||||
return "CustomType"
|
|
||||||
|
|
||||||
table_name = "__test_tmp_table__"
|
table_name = "__test_tmp_table__"
|
||||||
uc_name = 'uniq_foo'
|
uc_name = 'uniq_foo'
|
||||||
values = [
|
values = [
|
||||||
@@ -235,3 +238,77 @@ class TestMigrationUtils(test_migrations.BaseMigrationTestCase):
|
|||||||
len(values) - len(row_ids))
|
len(values) - len(row_ids))
|
||||||
for value in soft_deleted_values:
|
for value in soft_deleted_values:
|
||||||
self.assertTrue(value['id'] in deleted_rows_ids)
|
self.assertTrue(value['id'] in deleted_rows_ids)
|
||||||
|
|
||||||
|
def test_check_shadow_table(self):
|
||||||
|
table_name = 'abc'
|
||||||
|
for key, engine in self.engines.items():
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = engine
|
||||||
|
|
||||||
|
table = Table(table_name, meta,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('a', Integer),
|
||||||
|
Column('c', String(256)))
|
||||||
|
table.create()
|
||||||
|
|
||||||
|
#check missing shadow table
|
||||||
|
self.assertRaises(NoSuchTableError,
|
||||||
|
utils.check_shadow_table, engine, table_name)
|
||||||
|
|
||||||
|
shadow_table = Table(db._SHADOW_TABLE_PREFIX + table_name, meta,
|
||||||
|
Column('id', Integer),
|
||||||
|
Column('a', Integer))
|
||||||
|
shadow_table.create()
|
||||||
|
|
||||||
|
# check missing column
|
||||||
|
self.assertRaises(exception.NovaException,
|
||||||
|
utils.check_shadow_table, engine, table_name)
|
||||||
|
|
||||||
|
# check when all is ok
|
||||||
|
c = Column('c', String(256))
|
||||||
|
shadow_table.create_column(c)
|
||||||
|
self.assertTrue(utils.check_shadow_table(engine, table_name))
|
||||||
|
|
||||||
|
# check extra column
|
||||||
|
d = Column('d', Integer)
|
||||||
|
shadow_table.create_column(d)
|
||||||
|
self.assertRaises(exception.NovaException,
|
||||||
|
utils.check_shadow_table, engine, table_name)
|
||||||
|
|
||||||
|
def test_check_shadow_table_different_types(self):
|
||||||
|
table_name = 'abc'
|
||||||
|
for key, engine in self.engines.items():
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = engine
|
||||||
|
|
||||||
|
table = Table(table_name, meta,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('a', Integer))
|
||||||
|
table.create()
|
||||||
|
|
||||||
|
shadow_table = Table(db._SHADOW_TABLE_PREFIX + table_name, meta,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('a', String(256)))
|
||||||
|
shadow_table.create()
|
||||||
|
self.assertRaises(exception.NovaException,
|
||||||
|
utils.check_shadow_table, engine, table_name)
|
||||||
|
|
||||||
|
def test_check_shadow_table_with_unsupported_type(self):
|
||||||
|
table_name = 'abc'
|
||||||
|
for key, engine in self.engines.items():
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = engine
|
||||||
|
|
||||||
|
table = Table(table_name, meta,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('a', Integer),
|
||||||
|
Column('c', CustomType))
|
||||||
|
table.create()
|
||||||
|
|
||||||
|
shadow_table = Table(db._SHADOW_TABLE_PREFIX + table_name, meta,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('a', Integer),
|
||||||
|
Column('c', CustomType))
|
||||||
|
shadow_table.create()
|
||||||
|
|
||||||
|
self.assertTrue(utils.check_shadow_table(engine, table_name))
|
||||||
|
@@ -56,6 +56,7 @@ from sqlalchemy.dialects import postgresql
|
|||||||
from sqlalchemy.dialects import sqlite
|
from sqlalchemy.dialects import sqlite
|
||||||
import sqlalchemy.exc
|
import sqlalchemy.exc
|
||||||
|
|
||||||
|
from nova.db.sqlalchemy import api as db
|
||||||
import nova.db.sqlalchemy.migrate_repo
|
import nova.db.sqlalchemy.migrate_repo
|
||||||
from nova.openstack.common import lockutils
|
from nova.openstack.common import lockutils
|
||||||
from nova.openstack.common import log as logging
|
from nova.openstack.common import log as logging
|
||||||
@@ -855,13 +856,13 @@ class TestNovaMigrations(BaseMigrationTestCase, CommonTestsMixIn):
|
|||||||
meta.reflect(engine)
|
meta.reflect(engine)
|
||||||
table_names = set(meta.tables.keys())
|
table_names = set(meta.tables.keys())
|
||||||
for table_name in table_names:
|
for table_name in table_names:
|
||||||
if table_name.startswith("shadow_"):
|
if table_name.startswith(db._SHADOW_TABLE_PREFIX):
|
||||||
shadow_name = table_name
|
shadow_name = table_name
|
||||||
base_name = table_name.replace("shadow_", "")
|
base_name = table_name.replace(db._SHADOW_TABLE_PREFIX, "")
|
||||||
self.assertIn(base_name, table_names)
|
self.assertIn(base_name, table_names)
|
||||||
else:
|
else:
|
||||||
base_name = table_name
|
base_name = table_name
|
||||||
shadow_name = "shadow_" + table_name
|
shadow_name = db._SHADOW_TABLE_PREFIX + table_name
|
||||||
self.assertIn(shadow_name, table_names)
|
self.assertIn(shadow_name, table_names)
|
||||||
shadow_table = get_table(engine, shadow_name)
|
shadow_table = get_table(engine, shadow_name)
|
||||||
base_table = get_table(engine, base_name)
|
base_table = get_table(engine, base_name)
|
||||||
|
Reference in New Issue
Block a user