diff options
Diffstat (limited to 'networking-odl/networking_odl/tests/unit/common/test_utils.py')
-rw-r--r-- | networking-odl/networking_odl/tests/unit/common/test_utils.py | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/networking-odl/networking_odl/tests/unit/common/test_utils.py b/networking-odl/networking_odl/tests/unit/common/test_utils.py new file mode 100644 index 0000000..dcfb50e --- /dev/null +++ b/networking-odl/networking_odl/tests/unit/common/test_utils.py @@ -0,0 +1,156 @@ +# 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 +from networking_odl.common import utils + + +class TestGetAddressesByName(base.DietTestCase): + + # pylint: disable=protected-access, unused-argument + + def setUp(self): + super(TestGetAddressesByName, self).setUp() + self.clear_cache() + self.addCleanup(self.clear_cache) + time = self.patch( + utils.cache, 'time', clock=mock.Mock(return_value=0.0)) + self.clock = time.clock + socket = self.patch(utils, 'socket') + self.getaddrinfo = socket.getaddrinfo + + def patch(self, target, name, *args, **kwargs): + context = mock.patch.object(target, name, *args, **kwargs) + mocked = context.start() + self.addCleanup(context.stop) + return mocked + + def clear_cache(self): + utils._addresses_by_name_cache.clear() + + def test_get_addresses_by_valid_name(self): + self.getaddrinfo.return_value = [ + (2, 1, 6, '', ('127.0.0.1', 0)), + (2, 2, 17, '', ('127.0.0.1', 0)), + (2, 3, 0, '', ('127.0.0.1', 0)), + (2, 1, 6, '', ('10.237.214.247', 0)), + (2, 2, 17, '', ('10.237.214.247', 0)), + (2, 3, 0, '', ('10.237.214.247', 0))] + + # When valid host name is requested + result = utils.get_addresses_by_name('some_host_name') + + # Then correct addresses are returned + self.assertEqual(('127.0.0.1', '10.237.214.247'), result) + + # Then fetched addresses are cached + self.assertEqual(result, utils.get_addresses_by_name('some_host_name')) + + # Then addresses are fetched only once + self.getaddrinfo.assert_called_once_with('some_host_name', None) + + def test_get_addresses_by_valid_name_when_cache_expires(self): + self.getaddrinfo.return_value = [ + (2, 1, 6, '', ('127.0.0.1', 0)), + (2, 2, 17, '', ('127.0.0.1', 0)), + (2, 3, 0, '', ('127.0.0.1', 0)), + (2, 1, 6, '', ('10.237.214.247', 0)), + (2, 2, 17, '', ('10.237.214.247', 0)), + (2, 3, 0, '', ('10.237.214.247', 0))] + + # When valid host name is requested + result1 = utils.get_addresses_by_name('some_host_name') + + # and after a long time + self.clock.return_value = 1.0e6 + + # When valid host name is requested + result2 = utils.get_addresses_by_name('some_host_name') + + # Then correct addresses are returned + self.assertEqual(('127.0.0.1', '10.237.214.247'), result1) + self.assertEqual(('127.0.0.1', '10.237.214.247'), result2) + + # Then addresses are fetched twice + self.getaddrinfo.assert_has_calls( + [mock.call('some_host_name', None), + mock.call('some_host_name', None)]) + + @mock.patch.object(cache, 'LOG') + def test_get_addresses_by_invalid_name(self, cache_logger): + + # Given addresses resolution is failing + given_error = RuntimeError("I don't know him!") + + def failing_getaddrinfo(name, service): + raise given_error + + self.getaddrinfo.side_effect = failing_getaddrinfo + + # When invalid name is requested + self.assertRaises( + RuntimeError, utils.get_addresses_by_name, 'some_host_name') + + # When invalid name is requested again + self.assertRaises( + RuntimeError, utils.get_addresses_by_name, 'some_host_name') + + # Then result is fetched only once + self.getaddrinfo.assert_has_calls( + [mock.call('some_host_name', None)]) + cache_logger.warning.assert_has_calls( + [mock.call( + 'Error fetching values for keys: %r', "'some_host_name'", + exc_info=(RuntimeError, given_error, mock.ANY)), + mock.call( + 'Error fetching values for keys: %r', "'some_host_name'", + exc_info=(RuntimeError, given_error, mock.ANY))]) + + @mock.patch.object(cache, 'LOG') + def test_get_addresses_failing_when_expired_in_cache(self, cache_logger): + self.getaddrinfo.return_value = [ + (2, 1, 6, '', ('127.0.0.1', 0)), + (2, 2, 17, '', ('127.0.0.1', 0)), + (2, 3, 0, '', ('127.0.0.1', 0)), + (2, 1, 6, '', ('10.237.214.247', 0)), + (2, 2, 17, '', ('10.237.214.247', 0)), + (2, 3, 0, '', ('10.237.214.247', 0))] + + # Given valid result is in chache but expired + utils.get_addresses_by_name('some_host_name') + self.clock.return_value = 1.0e6 + + # Given addresses resolution is now failing + given_error = RuntimeError("This is top secret.") + + def failing_getaddrinfo(name, service): + raise given_error + + self.getaddrinfo.side_effect = failing_getaddrinfo + + self.assertRaises( + RuntimeError, utils.get_addresses_by_name, 'some_host_name') + + # Then result is fetched more times + self.getaddrinfo.assert_has_calls( + [mock.call('some_host_name', None), + mock.call('some_host_name', None)]) + cache_logger.warning.assert_called_once_with( + 'Error fetching values for keys: %r', "'some_host_name'", + exc_info=(RuntimeError, given_error, mock.ANY)) |