From 35bcdcba60b13ed5e3f8105873e9ed6b1e8f9fbb Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Fri, 23 Feb 2024 10:04:29 -1000 Subject: [PATCH] ImagePolicyCommon: add unit tests for _get_response(), more... This brings unit test coverage for image_policy_common.py to 79% Also: Update docstring for _handle_post_put_delete_response to indicate that RETURN_CODE is not considered when determining the result and to better describe the logic. --- plugins/module_utils/image_policy/common.py | 6 +- .../fixtures/responses_ImagePolicyCommon.json | 49 ++++ .../test_image_policy_common.py | 262 ++++++++++++++++++ .../modules/dcnm/dcnm_image_policy/utils.py | 20 ++ 4 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 tests/unit/modules/dcnm/dcnm_image_policy/fixtures/responses_ImagePolicyCommon.json create mode 100644 tests/unit/modules/dcnm/dcnm_image_policy/test_image_policy_common.py diff --git a/plugins/module_utils/image_policy/common.py b/plugins/module_utils/image_policy/common.py index ecdfc814d..14cc4fcbd 100644 --- a/plugins/module_utils/image_policy/common.py +++ b/plugins/module_utils/image_policy/common.py @@ -178,14 +178,16 @@ def _handle_post_put_delete_response(self, response): Caller: - self.self._handle_response() - Handle POST, PUT responses from the controller. + Handle POST, PUT, DELETE responses from the controller. Returns: dict() with the following keys: - changed: - True if changes were made to by the controller + - ERROR key is not present + - MESSAGE == "OK" - False otherwise - success: - - False if RETURN_CODE != 200 or MESSAGE != "OK" + - False if MESSAGE != "OK" or ERROR key is present - True otherwise """ result = {} diff --git a/tests/unit/modules/dcnm/dcnm_image_policy/fixtures/responses_ImagePolicyCommon.json b/tests/unit/modules/dcnm/dcnm_image_policy/fixtures/responses_ImagePolicyCommon.json new file mode 100644 index 000000000..6c8c395f8 --- /dev/null +++ b/tests/unit/modules/dcnm/dcnm_image_policy/fixtures/responses_ImagePolicyCommon.json @@ -0,0 +1,49 @@ +{ + "TEST_NOTES": [ + "Mocked responses for ImagePolicyCreate unit tests.", + "tests/unit/modules/dcnm/dcnm_image_policy/test_image_policy_create.py" + ], + "test_image_policy_common_00020a": { + "DATA": "NA", + "MESSAGE": "OK", + "METHOD": "GET", + "REQUEST_PATH": "https://foo/bar/endpoint", + "RETURN_CODE": 200 + }, + "test_image_policy_common_00021a": { + "DATA": "NA", + "MESSAGE": "Not Found", + "METHOD": "GET", + "REQUEST_PATH": "https://foo/bar/endpoint", + "RETURN_CODE": 404 + }, + "test_image_policy_common_00022a": { + "DATA": "NA", + "MESSAGE": "Internal Server Error", + "METHOD": "GET", + "REQUEST_PATH": "https://foo/bar/endpoint", + "RETURN_CODE": 500 + }, + "test_image_policy_common_00030a": { + "DATA": "NA", + "MESSAGE": "OK", + "METHOD": "POST", + "REQUEST_PATH": "https://foo/bar/endpoint", + "RETURN_CODE": 200 + }, + "test_image_policy_common_00031a": { + "DATA": "NA", + "MESSAGE": "NOK", + "METHOD": "POST", + "REQUEST_PATH": "https://foo/bar/endpoint", + "RETURN_CODE": 200 + }, + "test_image_policy_common_00032a": { + "DATA": "NA", + "ERROR": "Oh no!", + "MESSAGE": "OK", + "METHOD": "POST", + "REQUEST_PATH": "https://foo/bar/endpoint", + "RETURN_CODE": 200 + } +} \ No newline at end of file diff --git a/tests/unit/modules/dcnm/dcnm_image_policy/test_image_policy_common.py b/tests/unit/modules/dcnm/dcnm_image_policy/test_image_policy_common.py new file mode 100644 index 000000000..f98d8d2b2 --- /dev/null +++ b/tests/unit/modules/dcnm/dcnm_image_policy/test_image_policy_common.py @@ -0,0 +1,262 @@ +# Copyright (c) 2024 Cisco and/or its affiliates. +# +# 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. + +# See the following regarding *_fixture imports +# https://pylint.pycqa.org/en/latest/user_guide/messages/warning/redefined-outer-name.html +# Due to the above, we also need to disable unused-import +# Also, fixtures need to use *args to match the signature of the function they are mocking +# pylint: disable=unused-import +# pylint: disable=redefined-outer-name +# pylint: disable=protected-access +# pylint: disable=unused-argument +# pylint: disable=invalid-name + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +__copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." +__author__ = "Allen Robel" + +import pytest +from ansible_collections.ansible.netcommon.tests.unit.modules.utils import \ + AnsibleFailJson +from ansible_collections.cisco.dcnm.plugins.module_utils.image_policy.endpoints import \ + ApiEndpoints +from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_image_policy.utils import ( + MockImagePolicies, does_not_raise, image_policy_common_fixture, + responses_image_policy_common) + + +def test_image_policy_common_00010(image_policy_common) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + + Summary + Verify that the class attributes are initialized to expected values + and that fail_json is not called. + + Test + - Class attributes are initialized to expected values + - fail_json is not called + """ + with does_not_raise(): + instance = image_policy_common + assert instance.class_name == "ImagePolicyCommon" + assert instance.changed is False + assert instance.failed is False + assert instance.response == [] + assert instance.response_current == {} + assert instance.result == [] + assert instance.result_current == {} + assert instance.diff == [] + assert instance.response_data == [] + + +def test_image_policy_common_00020(image_policy_common) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + - _handle_response() + - _handle_get_response() + + Summary + Verify that _handle_response() calls the appropriate methods when verb == GET + and response is successful (RETURN_CODE == 200) and that a proper result is + returned. + + Setup + - verb is set to GET + - response RETURN_CODE == 200 + - response MESSAGE == "OK" + + Test + - _handle_response() calls _handle_response_get() + - _handle_response_get() returns a proper result + - fail_json is not called + """ + key = "test_image_policy_common_00020a" + verb = "GET" + + with does_not_raise(): + instance = image_policy_common + result = instance._handle_response(responses_image_policy_common(key), verb) + assert result == {"success": True, "found": True} + + +def test_image_policy_common_00021(image_policy_common) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + - _handle_response() + - _handle_get_response() + + Summary + Verify that _handle_response() returns a proper result when verb == GET + and response is unsuccessful (RETURN_CODE == 404 and MESSAGE == "Not Found"). + + Setup + - verb is set to GET + - response RETURN_CODE == 404 + - response MESSAGE == "Not Found" + + Test + - _handle_response() calls _handle_response_get() + - _handle_response_get() returns a proper result + - fail_json is not called + """ + key = "test_image_policy_common_00021a" + verb = "GET" + + with does_not_raise(): + instance = image_policy_common + result = instance._handle_response(responses_image_policy_common(key), verb) + assert result == {"success": True, "found": False} + + +def test_image_policy_common_00022(image_policy_common) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + - _handle_response() + - _handle_get_response() + + Summary + Verify that _handle_response() returns a proper result when verb == GET + and response is unsuccessful (RETURN_CODE == 500 and MESSAGE == "Internal Server Error"). + + Setup + - verb is set to GET + - response RETURN_CODE == 500 + - response MESSAGE == "Internal Server Error" + + Test + - _handle_response() calls _handle_response_get() + - _handle_response_get() returns a proper result + - fail_json is not called + """ + key = "test_image_policy_common_00022a" + verb = "GET" + + with does_not_raise(): + instance = image_policy_common + result = instance._handle_response(responses_image_policy_common(key), verb) + assert result == {"success": False, "found": False} + + +@pytest.mark.parametrize("verb", ["POST", "PUT", "DELETE"]) +def test_image_policy_common_00030(image_policy_common, verb) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + - _handle_response() + - _handle_post_put_delete_response() + + Summary + Verify that _handle_response() calls the appropriate methods when verb == POST + and response is successful (MESSAGE = "OK") and that a proper result is + returned. + + Setup + - verb == POST + - response MESSAGE == "OK" + + Test + - _handle_response() calls _handle_post_put_delete_response() + - _handle_post_put_delete_response() returns a proper result + - fail_json is not called + + Discussion + RESULT_CODE is not checked or used in the code, so it is not tested. + """ + key = "test_image_policy_common_00030a" + + with does_not_raise(): + instance = image_policy_common + result = instance._handle_response(responses_image_policy_common(key), verb) + assert result == {"success": True, "changed": True} + + +@pytest.mark.parametrize("verb", ["POST", "PUT", "DELETE"]) +def test_image_policy_common_00031(image_policy_common, verb) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + - _handle_response() + - _handle_post_put_delete_response() + + Summary + Verify that _handle_response() calls the appropriate methods when verb == POST + and response is unsuccessful (MESSAGE != "OK") and that a proper result is + returned. + + Setup + - verb == POST + - response MESSAGE == "NOK" + + Test + - _handle_response() calls _handle_post_put_delete_response() + - _handle_post_put_delete_response() returns a proper result + - fail_json is not called + + Discussion + RESULT_CODE is not checked or used in the code, so it is not tested. + """ + key = "test_image_policy_common_00031a" + + with does_not_raise(): + instance = image_policy_common + result = instance._handle_response(responses_image_policy_common(key), verb) + assert result == {"success": False, "changed": False} + + +@pytest.mark.parametrize("verb", ["POST", "PUT", "DELETE"]) +def test_image_policy_common_00032(image_policy_common, verb) -> None: + """ + Classes and Methods + - ImagePolicyCommon + - __init__() + - _handle_response() + - _handle_post_put_delete_response() + + Summary + Verify that _handle_response() calls the appropriate methods when verb == POST + and response is unsuccessful (ERROR key is present) and that a proper result is + returned. + + Setup + - verb == POST + - response ERROR == "Oh no!" + + Test + - _handle_response() calls _handle_post_put_delete_response() + - _handle_post_put_delete_response() returns a proper result + - fail_json is not called + + Discussion + RESULT_CODE is not checked or used in the code, so it is not tested. + """ + key = "test_image_policy_common_00032a" + + with does_not_raise(): + instance = image_policy_common + result = instance._handle_response(responses_image_policy_common(key), verb) + assert result == {"success": False, "changed": False} diff --git a/tests/unit/modules/dcnm/dcnm_image_policy/utils.py b/tests/unit/modules/dcnm/dcnm_image_policy/utils.py index d32c948f5..6adac16e6 100644 --- a/tests/unit/modules/dcnm/dcnm_image_policy/utils.py +++ b/tests/unit/modules/dcnm/dcnm_image_policy/utils.py @@ -23,6 +23,8 @@ import pytest from ansible_collections.ansible.netcommon.tests.unit.modules.utils import \ AnsibleFailJson +from ansible_collections.cisco.dcnm.plugins.module_utils.image_policy.common import \ + ImagePolicyCommon from ansible_collections.cisco.dcnm.plugins.module_utils.image_policy.create import ( ImagePolicyCreate, ImagePolicyCreateBulk) from ansible_collections.cisco.dcnm.plugins.module_utils.image_policy.delete import \ @@ -186,6 +188,14 @@ def result_current(self): # https://pylint.pycqa.org/en/latest/user_guide/messages/warning/redefined-outer-name.html +@pytest.fixture(name="image_policy_common") +def image_policy_common_fixture(): + """ + mock ImagePolicyCommon + """ + return ImagePolicyCommon(MockAnsibleModule) + + @pytest.fixture(name="image_policy_create") def image_policy_create_fixture(): """ @@ -339,6 +349,16 @@ def responses_image_policies(key: str) -> Dict[str, str]: return data +def responses_image_policy_common(key: str) -> Dict[str, str]: + """ + Return responses for ImagePolicyCommon + """ + data_file = "responses_ImagePolicyCommon" + data = load_fixture(data_file).get(key) + print(f"{data_file}: {key} : {data}") + return data + + def responses_image_policy_create(key: str) -> Dict[str, str]: """ Return responses for ImagePolicyCreate