diff --git a/dragonflow/tests/database/__init__.py b/dragonflow/tests/database/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dragonflow/tests/database/_dummy_db_driver.py b/dragonflow/tests/database/_dummy_db_driver.py new file mode 100644 index 000000000..6b7973ba9 --- /dev/null +++ b/dragonflow/tests/database/_dummy_db_driver.py @@ -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 diff --git a/dragonflow/tests/database/test_db_api.py b/dragonflow/tests/database/test_db_api.py new file mode 100644 index 000000000..bf5f0cd53 --- /dev/null +++ b/dragonflow/tests/database/test_db_api.py @@ -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()) diff --git a/dragonflow/tests/fullstack/test_db_api.py b/dragonflow/tests/fullstack/test_db_api.py index 31f865a6b..e97749300 100644 --- a/dragonflow/tests/fullstack/test_db_api.py +++ b/dragonflow/tests/fullstack/test_db_api.py @@ -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()) diff --git a/dragonflow/tests/unit/test_db_api.py b/dragonflow/tests/unit/test_db_api.py new file mode 100644 index 000000000..82dbe52f0 --- /dev/null +++ b/dragonflow/tests/unit/test_db_api.py @@ -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) diff --git a/setup.cfg b/setup.cfg index 5c7c406a0..8a430f470 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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 =