From c3b2c2a9a22bac5cf17813c589444d3abebaa23b Mon Sep 17 00:00:00 2001 From: Wojciech Dec Date: Tue, 16 Aug 2016 19:27:01 +0200 Subject: Adding Mitaka networking-old module with the ODL topology based port binding resolution mechanism from https://review.openstack.org/333186 Change-Id: I10d400aac9bb639c146527f0f93e6925cb74d9de Signed-off-by: Wojciech Dec --- .../networking_odl/tests/unit/common/test_cache.py | 242 +++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 networking-odl/networking_odl/tests/unit/common/test_cache.py (limited to 'networking-odl/networking_odl/tests/unit/common/test_cache.py') diff --git a/networking-odl/networking_odl/tests/unit/common/test_cache.py b/networking-odl/networking_odl/tests/unit/common/test_cache.py new file mode 100644 index 0000000..b702455 --- /dev/null +++ b/networking-odl/networking_odl/tests/unit/common/test_cache.py @@ -0,0 +1,242 @@ +# Copyright (c) 2015 OpenStack Foundation +# All Rights Reserved. +# +# 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 mock + +from neutron.tests import base + +from networking_odl.common import cache + + +class TestCache(base.DietTestCase): + + def test_init_with_callable(self): + + def given_fetch_method(): + pass + + cache.Cache(given_fetch_method) + + def test_init_without_callable(self): + self.assertRaises(TypeError, lambda: cache.Cache(object())) + + def test_fecth_once(self): + value = 'value' + + given_fetch_method = mock.Mock(return_value=iter([('key', value)])) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + result = given_cache.fetch('key', 60.0) + + # Result is returned + self.assertIs(value, result) + + # Then fetch method is called once + given_fetch_method.assert_called_once_with(('key',)) + + def test_fecth_with_no_result(self): + given_fetch_method = mock.Mock(return_value=iter([])) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + try: + given_cache.fetch('key', 60.0) + except cache.CacheFetchError as error: + given_fetch_method.assert_called_once_with(('key',)) + self.assertRaises(KeyError, error.reraise_cause) + else: + self.fail('Expecting CacheFetchError to be raised.') + + @mock.patch.object(cache, 'LOG') + def test_fecth_with_failure(self, logger): + # pylint: disable=unused-argument + + given_error = RuntimeError("It doesn't work like this!") + + def failing_function(keys): + raise given_error + + given_fetch_method = mock.Mock(side_effect=failing_function) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + try: + given_cache.fetch('key', 60.0) + except cache.CacheFetchError as error: + given_fetch_method.assert_called_once_with(('key',)) + self.assertRaises(RuntimeError, error.reraise_cause) + else: + self.fail('Expecting CacheFetchError to be raised.') + logger.warning.assert_called_once_with( + 'Error fetching values for keys: %r', "'key'", + exc_info=(type(given_error), given_error, mock.ANY)) + + def test_fecth_again_after_clear(self): + value1 = 'value1' + value2 = 'value2' + given_fetch_method = mock.Mock( + side_effect=[iter([('key', value1)]), + iter([('key', value2)])]) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + result1 = given_cache.fetch('key', 60.0) + + # When cache is cleared + given_cache.clear() + + # When value with same key is fetched again + result2 = given_cache.fetch('key', 0.0) + + # Then first result is returned + self.assertIs(value1, result1) + + # Then fetch method is called twice + self.assertEqual( + [mock.call(('key',)), mock.call(('key',))], + given_fetch_method.mock_calls) + + # Then second result is returned + self.assertIs(value2, result2) + + def test_fecth_again_before_timeout(self): + value1 = 'value1' + value2 = 'value2' + given_fetch_method = mock.Mock( + side_effect=[iter([('key', value1)]), + iter([('key', value2)])]) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + result1 = given_cache.fetch('key', 1.0) + + # When value with same key is fetched again and cached entry is not + # expired + result2 = given_cache.fetch('key', 0.0) + + # First result is returned + self.assertIs(value1, result1) + + # Then fetch method is called once + given_fetch_method.assert_called_once_with(('key',)) + + # Then first result is returned twice + self.assertIs(value1, result2) + + def test_fecth_again_after_timeout(self): + value1 = 'value1' + value2 = 'value2' + given_fetch_method = mock.Mock( + side_effect=[iter([('key', value1)]), + iter([('key', value2)])]) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + result1 = given_cache.fetch('key', 0.0) + + # When value with same key is fetched again and cached entry is + # expired + result2 = given_cache.fetch('key', 0.0) + + # Then first result is returned + self.assertIs(value1, result1) + + # Then fetch method is called twice + self.assertEqual( + [mock.call(('key',)), mock.call(('key',))], + given_fetch_method.mock_calls) + + # Then second result is returned + self.assertIs(value2, result2) + + def test_fecth_two_values_yielding_both_before_timeout(self): + value1 = 'value1' + value2 = 'value2' + given_fetch_method = mock.Mock( + return_value=iter([('key1', value1), + ('key2', value2)])) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + result1 = given_cache.fetch('key1', 60.0) + + # When value with another key is fetched and cached entry is not + # expired + result2 = given_cache.fetch('key2', 60.0) + + # Then first result is returned + self.assertIs(value1, result1) + + # Then fetch method is called once + given_fetch_method.assert_called_once_with(('key1',)) + + # Then second result is returned + self.assertIs(value2, result2) + + def test_fecth_two_values_yielding_both_after_timeout(self): + value1 = 'value1' + value2 = 'value2' + given_fetch_method = mock.Mock( + return_value=[('key1', value1), ('key2', value2)]) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + result1 = given_cache.fetch('key1', 0.0) + + # When value with another key is fetched and cached entry is + # expired + result2 = given_cache.fetch('key2', 0.0) + + # Then first result is returned + self.assertIs(value1, result1) + + # Then fetch method is called twice + self.assertEqual( + [mock.call(('key1',)), mock.call(('key2',))], + given_fetch_method.mock_calls) + + # Then second result is returned + self.assertIs(value2, result2) + + def test_fecth_all_with_multiple_entries(self): + given_fetch_method = mock.Mock( + return_value=iter([('key', 'value1'), + ('key', 'value2')])) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + results = list(given_cache.fetch_all(['key'], 0.0)) + + # Then fetch method is once + given_fetch_method.assert_called_once_with(('key',)) + + # Then both results are yield in the right order + self.assertEqual([('key', 'value1'), ('key', 'value2')], results) + + def test_fecth_all_with_repeated_entries(self): + entry = ('key', 'value') + given_fetch_method = mock.Mock( + return_value=iter([entry, entry, entry])) + given_cache = cache.Cache(given_fetch_method) + + # When value with key is fetched + results = list(given_cache.fetch_all(['key'], 0.0)) + + # Then fetch method is once + given_fetch_method.assert_called_once_with(('key',)) + + # Then results are yield in the right order + self.assertEqual([entry, entry, entry], results) -- cgit 1.2.3-korg