Centralize sqlite FK constraint enforcement
There's a TODO in the code to centralize foreign key constraint
enforcement for sqlite for unit and functional tests and we're missing
enforcement of FK constraints in a couple of test classes that should
have it.
This resolves the TODO and turns on FK constraint enforcement where it
is missing. Do this to enhance testing in preparation for a proposed
change to the database archiving logic later in this patch series.
Conflicts:
nova/test.py
NOTE(melwitt): The conflicts are because of the following changes not
in Victoria:
* Ib2c406327fef2fb4868d8050fc476a7d17706e23 (Remove six.moves)
* Ide65686cf02463045f5c32771ca949802b19636f (Remove
six.binary_type/integer_types/string_types)
Change-Id: Idcf026d020e63e4e6ece1db46e4cdc7b7742b76f
(cherry picked from commit 172024db71
)
This commit is contained in:
parent
24595b6ca9
commit
382d64ea36
18
nova/test.py
18
nova/test.py
|
@ -51,10 +51,12 @@ from oslotest import base
|
||||||
from oslotest import mock_fixture
|
from oslotest import mock_fixture
|
||||||
import six
|
import six
|
||||||
from six.moves import builtins
|
from six.moves import builtins
|
||||||
|
from sqlalchemy.dialects import sqlite
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
from nova.compute import rpcapi as compute_rpcapi
|
from nova.compute import rpcapi as compute_rpcapi
|
||||||
from nova import context
|
from nova import context
|
||||||
|
from nova.db.sqlalchemy import api as sqlalchemy_api
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.objects import base as objects_base
|
from nova.objects import base as objects_base
|
||||||
|
@ -376,6 +378,22 @@ class TestCase(base.BaseTestCase):
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
CONF.set_override(k, v, group)
|
CONF.set_override(k, v, group)
|
||||||
|
|
||||||
|
def enforce_fk_constraints(self, engine=None):
|
||||||
|
if engine is None:
|
||||||
|
engine = sqlalchemy_api.get_engine()
|
||||||
|
dialect = engine.url.get_dialect()
|
||||||
|
if dialect == sqlite.dialect:
|
||||||
|
# We're seeing issues with foreign key support in SQLite 3.6.20
|
||||||
|
# SQLAlchemy doesn't support it at all with < SQLite 3.6.19
|
||||||
|
# It works fine in SQLite 3.7.
|
||||||
|
# So return early to skip this test if running SQLite < 3.7
|
||||||
|
import sqlite3
|
||||||
|
tup = sqlite3.sqlite_version_info
|
||||||
|
if tup[0] < 3 or (tup[0] == 3 and tup[1] < 7):
|
||||||
|
self.skipTest(
|
||||||
|
'sqlite version too old for reliable SQLA foreign_keys')
|
||||||
|
engine.connect().execute("PRAGMA foreign_keys = ON")
|
||||||
|
|
||||||
def start_service(self, name, host=None, cell_name=None, **kwargs):
|
def start_service(self, name, host=None, cell_name=None, **kwargs):
|
||||||
# Disallow starting multiple scheduler services
|
# Disallow starting multiple scheduler services
|
||||||
if name == 'scheduler' and self._service_fixture_count[name]:
|
if name == 'scheduler' and self._service_fixture_count[name]:
|
||||||
|
|
|
@ -17,7 +17,6 @@ import re
|
||||||
|
|
||||||
from dateutil import parser as dateutil_parser
|
from dateutil import parser as dateutil_parser
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from sqlalchemy.dialects import sqlite
|
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from sqlalchemy import MetaData
|
from sqlalchemy import MetaData
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
|
@ -33,22 +32,7 @@ class TestDatabaseArchive(integrated_helpers._IntegratedTestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestDatabaseArchive, self).setUp()
|
super(TestDatabaseArchive, self).setUp()
|
||||||
# TODO(mriedem): pull this out so we can re-use it in
|
self.enforce_fk_constraints()
|
||||||
# test_archive_deleted_rows_fk_constraint
|
|
||||||
# SQLite doesn't enforce foreign key constraints without a pragma.
|
|
||||||
engine = sqlalchemy_api.get_engine()
|
|
||||||
dialect = engine.url.get_dialect()
|
|
||||||
if dialect == sqlite.dialect:
|
|
||||||
# We're seeing issues with foreign key support in SQLite 3.6.20
|
|
||||||
# SQLAlchemy doesn't support it at all with < SQLite 3.6.19
|
|
||||||
# It works fine in SQLite 3.7.
|
|
||||||
# So return early to skip this test if running SQLite < 3.7
|
|
||||||
import sqlite3
|
|
||||||
tup = sqlite3.sqlite_version_info
|
|
||||||
if tup[0] < 3 or (tup[0] == 3 and tup[1] < 7):
|
|
||||||
self.skipTest(
|
|
||||||
'sqlite version too old for reliable SQLA foreign_keys')
|
|
||||||
engine.connect().execute("PRAGMA foreign_keys = ON")
|
|
||||||
|
|
||||||
def test_archive_deleted_rows(self):
|
def test_archive_deleted_rows(self):
|
||||||
# Boots a server, deletes it, and then tries to archive it.
|
# Boots a server, deletes it, and then tries to archive it.
|
||||||
|
|
|
@ -1767,6 +1767,7 @@ class TestDBArchiveDeletedRows(integrated_helpers._IntegratedTestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestDBArchiveDeletedRows, self).setUp()
|
super(TestDBArchiveDeletedRows, self).setUp()
|
||||||
|
self.enforce_fk_constraints()
|
||||||
self.cli = manage.DbCommands()
|
self.cli = manage.DbCommands()
|
||||||
self.output = StringIO()
|
self.output = StringIO()
|
||||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output))
|
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output))
|
||||||
|
@ -1812,6 +1813,7 @@ class TestDBArchiveDeletedRowsMultiCell(integrated_helpers.InstanceHelperMixin,
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestDBArchiveDeletedRowsMultiCell, self).setUp()
|
super(TestDBArchiveDeletedRowsMultiCell, self).setUp()
|
||||||
|
self.enforce_fk_constraints()
|
||||||
self.useFixture(nova_fixtures.NeutronFixture(self))
|
self.useFixture(nova_fixtures.NeutronFixture(self))
|
||||||
self.useFixture(nova_fixtures.GlanceFixture(self))
|
self.useFixture(nova_fixtures.GlanceFixture(self))
|
||||||
self.useFixture(func_fixtures.PlacementFixture())
|
self.useFixture(func_fixtures.PlacementFixture())
|
||||||
|
|
|
@ -39,7 +39,6 @@ from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
from sqlalchemy import Column
|
from sqlalchemy import Column
|
||||||
from sqlalchemy.dialects import sqlite
|
|
||||||
from sqlalchemy.exc import OperationalError
|
from sqlalchemy.exc import OperationalError
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy import inspect
|
from sqlalchemy import inspect
|
||||||
|
@ -6440,18 +6439,7 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
|
|
||||||
def _check_sqlite_version_less_than_3_7(self):
|
def _check_sqlite_version_less_than_3_7(self):
|
||||||
# SQLite doesn't enforce foreign key constraints without a pragma.
|
# SQLite doesn't enforce foreign key constraints without a pragma.
|
||||||
dialect = self.engine.url.get_dialect()
|
self.enforce_fk_constraints(engine=self.engine)
|
||||||
if dialect == sqlite.dialect:
|
|
||||||
# We're seeing issues with foreign key support in SQLite 3.6.20
|
|
||||||
# SQLAlchemy doesn't support it at all with < SQLite 3.6.19
|
|
||||||
# It works fine in SQLite 3.7.
|
|
||||||
# So return early to skip this test if running SQLite < 3.7
|
|
||||||
import sqlite3
|
|
||||||
tup = sqlite3.sqlite_version_info
|
|
||||||
if tup[0] < 3 or (tup[0] == 3 and tup[1] < 7):
|
|
||||||
self.skipTest(
|
|
||||||
'sqlite version too old for reliable SQLA foreign_keys')
|
|
||||||
self.conn.execute("PRAGMA foreign_keys = ON")
|
|
||||||
|
|
||||||
def test_archive_deleted_rows_for_migrations(self):
|
def test_archive_deleted_rows_for_migrations(self):
|
||||||
# migrations.instance_uuid depends on instances.uuid
|
# migrations.instance_uuid depends on instances.uuid
|
||||||
|
|
Loading…
Reference in New Issue