From f371b1af0269aaf3ad3de02f0ac65044a653733e Mon Sep 17 00:00:00 2001 From: Erik Olof Gunnar Andersson Date: Sat, 29 Jul 2023 22:11:43 +0200 Subject: [PATCH] Added unit test coverage for verify_project_id - Cleaned up code path to make it easier to read. - Added unit test coverage. Change-Id: I03d98e2ab950247fad73814e2ac03a96cda749b6 --- designate/common/keystone.py | 60 ++++++++++------- designate/tests/unit/common/test_keystone.py | 68 ++++++++++++++++++++ 2 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 designate/tests/unit/common/test_keystone.py diff --git a/designate/common/keystone.py b/designate/common/keystone.py index 41d7ec5a1..8681879df 100644 --- a/designate/common/keystone.py +++ b/designate/common/keystone.py @@ -32,48 +32,58 @@ def verify_project_id(context, project_id): """ session = ksa_loading.load_session_from_conf_options( - CONF, 'keystone', auth=context.get_auth_plugin()) - adap = ksa_loading.load_adapter_from_conf_options( + CONF, 'keystone', auth=context.get_auth_plugin() + ) + adapter = ksa_loading.load_adapter_from_conf_options( CONF, 'keystone', - session=session, min_version=(3, 0), max_version=(3, 'latest')) + session=session, min_version=(3, 0), max_version=(3, 'latest') + ) try: - resp = adap.get('/projects/%s' % project_id, raise_exc=False) + response = adapter.get('/projects/%s' % project_id, raise_exc=False) except kse.EndpointNotFound: LOG.error( - "Keystone identity service version 3.0 was not found. This might " - "be because your endpoint points to the v2.0 versioned endpoint " - "which is not supported. Please fix this.") + 'Keystone identity service version 3.0 was not found. This might ' + 'be because your endpoint points to the v2.0 versioned endpoint ' + 'which is not supported. Please fix this.' + ) raise exceptions.KeystoneCommunicationFailure( - _("KeystoneV3 endpoint not found")) + _('KeystoneV3 endpoint not found') + ) except kse.ClientException: # something is wrong, like there isn't a keystone v3 endpoint, # or nova isn't configured for the interface to talk to it; # we'll take the pass and default to everything being ok. - LOG.info("Unable to contact keystone to verify project_id") + LOG.info('Unable to contact keystone to verify project_id') return True - if resp: + if response.ok: # All is good with this 20x status return True - elif resp.status_code == 404: - # we got access, and we know this project is not there - raise exceptions.InvalidProject( - _("%s is not a valid project ID.") % project_id) - - elif resp.status_code == 403: + elif response.status_code == 403: # we don't have enough permission to verify this, so default # to "it's ok". LOG.info( - "Insufficient permissions for user %(user)s to verify " - "existence of project_id %(pid)s", - {"user": context.user_id, "pid": project_id}) + 'Insufficient permissions for user %(user)s to verify ' + 'existence of project_id %(pid)s', + { + 'user': context.user_id, + 'pid': project_id + } + ) return True + elif response.status_code == 404: + # we got access, and we know this project is not there + raise exceptions.InvalidProject( + _('%s is not a valid project ID.') % project_id + ) else: LOG.warning( - "Unexpected response from keystone trying to " - "verify project_id %(pid)s - resp: %(code)s %(content)s", - {"pid": project_id, - "code": resp.status_code, - "content": resp.content}) - # realize we did something wrong, but move on with a warning + 'Unexpected response from keystone trying to ' + 'verify project_id %(pid)s - response: %(code)s %(content)s', + { + 'pid': project_id, + 'code': response.status_code, + 'content': response.content + } + ) return True diff --git a/designate/tests/unit/common/test_keystone.py b/designate/tests/unit/common/test_keystone.py new file mode 100644 index 000000000..0341aa5b2 --- /dev/null +++ b/designate/tests/unit/common/test_keystone.py @@ -0,0 +1,68 @@ +# 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 unittest import mock + +from keystoneauth1 import exceptions as kse +import oslotest.base + +from designate.common import keystone +from designate import exceptions + + +class TestVerifyProjectid(oslotest.base.BaseTestCase): + def setUp(self): + super(TestVerifyProjectid, self).setUp() + + @mock.patch('keystoneauth1.adapter.Adapter.get') + def test_verify_project_id(self, mock_get): + mock_result = mock.Mock() + mock_result.ok = True + mock_result.status_code = 200 + mock_get.return_value = mock_result + self.assertTrue(keystone.verify_project_id(mock.Mock(), '1')) + + @mock.patch('keystoneauth1.adapter.Adapter.get') + def test_verify_project_id_request_returns_403(self, mock_get): + mock_result = mock.Mock() + mock_result.ok = False + mock_result.status_code = 403 + mock_get.return_value = mock_result + self.assertTrue(keystone.verify_project_id(mock.Mock(), '1')) + + @mock.patch('keystoneauth1.adapter.Adapter.get') + def test_verify_project_id_request_returns_404(self, mock_get): + mock_result = mock.Mock() + mock_result.ok = False + mock_result.status_code = 404 + mock_get.return_value = mock_result + self.assertRaisesRegex( + exceptions.InvalidProject, + '1 is not a valid project ID.', + keystone.verify_project_id, mock.Mock(), '1' + ) + + @mock.patch('keystoneauth1.adapter.Adapter.get') + def test_verify_project_id_request_returns_500(self, mock_get): + mock_result = mock.Mock() + mock_result.ok = False + mock_result.status_code = 500 + mock_get.return_value = mock_result + self.assertTrue(keystone.verify_project_id(mock.Mock(), '1')) + + @mock.patch('keystoneauth1.adapter.Adapter.get') + def test_verify_project_endpoint_not_found(self, mock_get): + mock_get.side_effect = kse.EndpointNotFound + self.assertRaisesRegex( + exceptions.KeystoneCommunicationFailure, + 'KeystoneV3 endpoint not found', + keystone.verify_project_id, mock.Mock(), '1' + )