Add an in-memory NB database driver
This driver can be used by unit tests to have an NB databse that looks and feels 'real'. Change-Id: I9aeb242e3151f452c1130d8b300e6958e64874f4
This commit is contained in:
parent
caa5e9a86f
commit
c5ed2128f5
0
dragonflow/tests/database/__init__.py
Normal file
0
dragonflow/tests/database/__init__.py
Normal file
84
dragonflow/tests/database/_dummy_db_driver.py
Normal file
84
dragonflow/tests/database/_dummy_db_driver.py
Normal file
@ -0,0 +1,84 @@
|
||||
# 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.
|
||||
|
||||
import collections
|
||||
import threading
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from dragonflow.common import exceptions as df_exceptions
|
||||
from dragonflow.db import db_api
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class _DummyDbDriver(db_api.DbApi):
|
||||
def __init__(self):
|
||||
super(_DummyDbDriver, self).__init__()
|
||||
self._db = collections.defaultdict(dict)
|
||||
self._unique_keys = collections.defaultdict(int)
|
||||
self._unique_keys_lock = threading.Lock()
|
||||
|
||||
def initialize(self, db_ip, db_port, **args):
|
||||
# Do nothing. Initialized automatically in construction
|
||||
pass
|
||||
|
||||
def create_table(self, table):
|
||||
# Do nothing. Database is defaultdict
|
||||
pass
|
||||
|
||||
def delete_table(self, table):
|
||||
self._db.pop(table, None)
|
||||
|
||||
def get_key(self, table, key, topic=None):
|
||||
try:
|
||||
table_dict = self._db[table]
|
||||
return table_dict[key]
|
||||
except KeyError:
|
||||
raise df_exceptions.DBKeyNotFound(key=key)
|
||||
|
||||
def set_key(self, table, key, value, topic=None):
|
||||
# This will raise exception if the key isn't found
|
||||
self.get_key(table, key, topic)
|
||||
table_dict = self._db[table]
|
||||
table_dict[key] = value
|
||||
|
||||
def create_key(self, table, key, value, topic=None):
|
||||
table_dict = self._db[table]
|
||||
table_dict[key] = value
|
||||
|
||||
def delete_key(self, table, key, topic=None):
|
||||
table_dict = self._db[table]
|
||||
del table_dict[key]
|
||||
|
||||
def get_all_entries(self, table, topic=None):
|
||||
table_dict = self._db[table]
|
||||
return [value for value in table_dict.values()]
|
||||
|
||||
def get_all_keys(self, table, topic=None):
|
||||
table_dict = self._db[table]
|
||||
return [key for key in table_dict.keys()]
|
||||
|
||||
def allocate_unique_key(self, table):
|
||||
with self._unique_keys_lock:
|
||||
unique_key = self._unique_keys[table] + 1
|
||||
self._unique_keys[table] = unique_key
|
||||
return unique_key
|
||||
|
||||
def process_ha(self):
|
||||
# Do nothing
|
||||
pass
|
||||
|
||||
def set_neutron_server(self, is_neutron_server):
|
||||
# Do nothing
|
||||
pass
|
94
dragonflow/tests/database/test_db_api.py
Normal file
94
dragonflow/tests/database/test_db_api.py
Normal file
@ -0,0 +1,94 @@
|
||||
# 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.
|
||||
|
||||
import functools
|
||||
import threading
|
||||
|
||||
from dragonflow.common import exceptions as df_exceptions
|
||||
from dragonflow.tests import base
|
||||
|
||||
|
||||
class TestDbApi(base.BaseTestCase):
|
||||
def test_simple_create_get(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.assertEqual('v1', self.driver.get_key('test_table', 'k1'))
|
||||
|
||||
def test_get_not_found(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.assertRaises(df_exceptions.DBKeyNotFound,
|
||||
functools.partial(self.driver.get_key,
|
||||
'test_table', 'k1'))
|
||||
|
||||
def test_delete_key(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.driver.delete_key('test_table', 'k1')
|
||||
self.assertRaises(df_exceptions.DBKeyNotFound,
|
||||
functools.partial(self.driver.get_key,
|
||||
'test_table', 'k1'))
|
||||
self.assertEqual('v2', self.driver.get_key('test_table', 'k2'))
|
||||
|
||||
def test_delete_table(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.delete_table('test_table')
|
||||
self.assertRaises(df_exceptions.DBKeyNotFound,
|
||||
functools.partial(self.driver.get_key,
|
||||
'test_table', 'k1'))
|
||||
|
||||
def test_set_key(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.assertEqual('v1', self.driver.get_key('test_table', 'k1'))
|
||||
self.driver.set_key('test_table', 'k1', 'v1_2')
|
||||
self.assertEqual('v1_2', self.driver.get_key('test_table', 'k1'))
|
||||
self.assertEqual('v2', self.driver.get_key('test_table', 'k2'))
|
||||
|
||||
def test_get_all_entries(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.assertEqual([], self.driver.get_all_entries('test_table'))
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.assertItemsEqual(['v1', 'v2'],
|
||||
self.driver.get_all_entries('test_table'))
|
||||
|
||||
def test_get_all_keys(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.assertEqual([], self.driver.get_all_keys('test_table'))
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.assertItemsEqual(['k1', 'k2'],
|
||||
self.driver.get_all_keys('test_table'))
|
||||
|
||||
def test_allocate_unique_key(self):
|
||||
unique_keys = [0, 0]
|
||||
|
||||
def get_unique_key(idx):
|
||||
unique_keys[idx] = self.driver.allocate_unique_key('test_table')
|
||||
thread1 = threading.Thread(target=functools.partial(get_unique_key, 0))
|
||||
thread2 = threading.Thread(target=functools.partial(get_unique_key, 1))
|
||||
thread1.start()
|
||||
thread2.start()
|
||||
thread1.join(5)
|
||||
thread2.join(5)
|
||||
self.assertNotEqual(unique_keys[0], unique_keys[1])
|
||||
self.assertFalse(thread1.is_alive())
|
||||
self.assertFalse(thread2.is_alive())
|
@ -10,16 +10,13 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import threading
|
||||
|
||||
from dragonflow.common import exceptions as df_exceptions
|
||||
from dragonflow.common import utils as df_utils
|
||||
from dragonflow import conf as cfg
|
||||
from dragonflow.tests.database import test_db_api
|
||||
from dragonflow.tests.fullstack import test_base
|
||||
|
||||
|
||||
class TestDbApi(test_base.DFTestBase):
|
||||
class TestDbApi(test_base.DFTestBase, test_db_api.TestDbApi):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDbApi, self).setUp()
|
||||
@ -29,78 +26,3 @@ class TestDbApi(test_base.DFTestBase):
|
||||
self.driver.initialize(cfg.CONF.df.remote_db_ip,
|
||||
cfg.CONF.df.remote_db_port,
|
||||
config=cfg.CONF.df)
|
||||
|
||||
def test_simple_create_get(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.assertEqual('v1', self.driver.get_key('test_table', 'k1'))
|
||||
|
||||
def test_get_not_found(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.assertRaises(df_exceptions.DBKeyNotFound,
|
||||
functools.partial(self.driver.get_key,
|
||||
'test_table', 'k1'))
|
||||
|
||||
def test_delete_key(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.driver.delete_key('test_table', 'k1')
|
||||
self.assertRaises(df_exceptions.DBKeyNotFound,
|
||||
functools.partial(self.driver.get_key,
|
||||
'test_table', 'k1'))
|
||||
self.assertEqual('v2', self.driver.get_key('test_table', 'k2'))
|
||||
|
||||
def test_delete_table(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.delete_table('test_table')
|
||||
self.assertRaises(df_exceptions.DBKeyNotFound,
|
||||
functools.partial(self.driver.get_key,
|
||||
'test_table', 'k1'))
|
||||
|
||||
def test_set_key(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.assertEqual('v1', self.driver.get_key('test_table', 'k1'))
|
||||
self.driver.set_key('test_table', 'k1', 'v1_2')
|
||||
self.assertEqual('v1_2', self.driver.get_key('test_table', 'k1'))
|
||||
self.assertEqual('v2', self.driver.get_key('test_table', 'k2'))
|
||||
|
||||
def test_get_all_entries(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.assertEqual([], self.driver.get_all_entries('test_table'))
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.assertItemsEqual(['v1', 'v2'],
|
||||
self.driver.get_all_entries('test_table'))
|
||||
|
||||
def test_get_all_keys(self):
|
||||
self.driver.create_table('test_table')
|
||||
self.addCleanup(self.driver.delete_table, 'test_table')
|
||||
self.assertEqual([], self.driver.get_all_keys('test_table'))
|
||||
self.driver.create_key('test_table', 'k1', 'v1')
|
||||
self.driver.create_key('test_table', 'k2', 'v2')
|
||||
self.assertItemsEqual(['k1', 'k2'],
|
||||
self.driver.get_all_keys('test_table'))
|
||||
|
||||
def test_allocate_unique_key(self):
|
||||
unique_keys = [0, 0]
|
||||
|
||||
def get_unique_key(idx):
|
||||
unique_keys[idx] = self.driver.allocate_unique_key('test_table')
|
||||
thread1 = threading.Thread(target=functools.partial(get_unique_key, 0))
|
||||
thread2 = threading.Thread(target=functools.partial(get_unique_key, 1))
|
||||
thread1.start()
|
||||
thread2.start()
|
||||
thread1.join(5)
|
||||
thread2.join(5)
|
||||
self.assertNotEqual(unique_keys[0], unique_keys[1])
|
||||
self.assertFalse(thread1.is_alive())
|
||||
self.assertFalse(thread2.is_alive())
|
||||
|
23
dragonflow/tests/unit/test_db_api.py
Normal file
23
dragonflow/tests/unit/test_db_api.py
Normal file
@ -0,0 +1,23 @@
|
||||
# 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 dragonflow.common import utils as df_utils
|
||||
from dragonflow.tests.database import test_db_api
|
||||
|
||||
|
||||
class TestDbApi(test_db_api.TestDbApi):
|
||||
def setUp(self):
|
||||
super(TestDbApi, self).setUp()
|
||||
self.driver = df_utils.load_driver(
|
||||
'_dummy_nb_db_driver',
|
||||
df_utils.DF_NB_DB_DRIVER_NAMESPACE)
|
||||
self.driver.initialize(None, None, config=None)
|
@ -72,6 +72,7 @@ dragonflow.nb_db_driver =
|
||||
zookeeper_nb_db_driver = dragonflow.db.drivers.zookeeper_db_driver:ZookeeperDbDriver
|
||||
redis_nb_db_driver = dragonflow.db.drivers.redis_db_driver:RedisDbDriver
|
||||
cassandra_nb_db_driver = dragonflow.db.drivers.cassandra_db_driver:CassandraDbDriver
|
||||
_dummy_nb_db_driver = dragonflow.tests.database._dummy_db_driver:_DummyDbDriver
|
||||
dragonflow.neutron_notifier_driver =
|
||||
nb_api_neutron_notifier_driver = dragonflow.db.pubsub_drivers.nb_api_neutron_notifier:NbApiNeutronNotifier
|
||||
neutron.service_plugins =
|
||||
|
Loading…
Reference in New Issue
Block a user