From f1cd01d3d7610d8e22dcadf09cdca4748d0313c9 Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 11:05:06 -1000 Subject: [PATCH 01/14] MaintenanceModeInfo: linting No functional changes in this commit. Run black and isort. --- plugins/module_utils/common/maintenance_mode_info.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/common/maintenance_mode_info.py b/plugins/module_utils/common/maintenance_mode_info.py index ded423897..73915ebb0 100644 --- a/plugins/module_utils/common/maintenance_mode_info.py +++ b/plugins/module_utils/common/maintenance_mode_info.py @@ -23,11 +23,11 @@ import inspect import logging +from ..fabric.fabric_details_v2 import FabricDetailsByName from .conversion import ConversionUtils from .exceptions import ControllerResponseError from .properties import Properties from .switch_details import SwitchDetails -from ..fabric.fabric_details_v2 import FabricDetailsByName @Properties.add_rest_send @@ -327,9 +327,7 @@ def _get(self, item): msg += "the controller." raise ValueError(msg) - return self.conversion.make_boolean( - self.conversion.make_none(self._info[self.filter].get(item)) - ) + return self.conversion.make_boolean(self.conversion.make_none(self._info[self.filter].get(item))) @property def filter(self): From 1fc4fb5701094a0742dbd7a7344642f732cb47d6 Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 11:06:55 -1000 Subject: [PATCH 02/14] MaintenanceMode: linting No functional changes in this commit. Run black and isort linters against MaintenanceMode. --- plugins/module_utils/common/maintenance_mode.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/plugins/module_utils/common/maintenance_mode.py b/plugins/module_utils/common/maintenance_mode.py index 00f4dce5f..27aee90cd 100644 --- a/plugins/module_utils/common/maintenance_mode.py +++ b/plugins/module_utils/common/maintenance_mode.py @@ -23,9 +23,7 @@ import inspect import logging -from .api.v1.lan_fabric.rest.control.fabrics.fabrics import ( - EpFabricConfigDeploy, EpMaintenanceModeDeploy, EpMaintenanceModeDisable, - EpMaintenanceModeEnable) +from .api.v1.lan_fabric.rest.control.fabrics.fabrics import EpFabricConfigDeploy, EpMaintenanceModeDeploy, EpMaintenanceModeDisable, EpMaintenanceModeEnable from .conversion import ConversionUtils from .exceptions import ControllerResponseError from .properties import Properties @@ -417,12 +415,8 @@ def change_system_mode(self) -> None: self.results.action = "change_sytem_mode" self.results.check_mode = self.check_mode self.results.state = self.state - self.results.response_current = copy.deepcopy( - self.rest_send.response_current - ) - self.results.result_current = copy.deepcopy( - self.rest_send.result_current - ) + self.results.response_current = copy.deepcopy(self.rest_send.response_current) + self.results.result_current = copy.deepcopy(self.rest_send.result_current) self.results.register_task_result() except (TypeError, ValueError) as error: raise ValueError(error) from error @@ -588,9 +582,7 @@ def deploy_switches(self) -> None: self.results.action = action self.results.check_mode = self.check_mode self.results.state = self.state - self.results.response_current = copy.deepcopy( - self.rest_send.response_current - ) + self.results.response_current = copy.deepcopy(self.rest_send.response_current) self.results.result_current = copy.deepcopy(self.rest_send.result_current) self.results.register_task_result() From bf1f2e173fd8f1bb876e9a8c9afce6974288e80c Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 11:08:41 -1000 Subject: [PATCH 03/14] dcnm_maintenance_mode.py: linting No functional changes in this commit. Run black and isort linters against dcnm_maintenance_mode.py. --- plugins/modules/dcnm_maintenance_mode.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/plugins/modules/dcnm_maintenance_mode.py b/plugins/modules/dcnm_maintenance_mode.py index f281904e0..c2265ab54 100644 --- a/plugins/modules/dcnm_maintenance_mode.py +++ b/plugins/modules/dcnm_maintenance_mode.py @@ -149,6 +149,7 @@ import logging from ansible.module_utils.basic import AnsibleModule + from ..module_utils.common.log_v2 import Log from ..module_utils.common.maintenance_mode import MaintenanceMode from ..module_utils.common.maintenance_mode_info import MaintenanceModeInfo @@ -917,9 +918,7 @@ def get_have(self): instance = MaintenanceModeInfo(self.params) instance.rest_send = self.rest_send instance.results = self.results - instance.config = [ - item["ip_address"] for item in self.config.get("switches", {}) - ] + instance.config = [item["ip_address"] for item in self.config.get("switches", {})] instance.refresh() except (TypeError, ValueError) as error: msg = f"{self.class_name}.{method_name}: " @@ -1212,9 +1211,7 @@ def get_have(self): try: self.maintenance_mode_info.rest_send = self.rest_send self.maintenance_mode_info.results = self.results - self.maintenance_mode_info.config = [ - item["ip_address"] for item in self.config.get("switches", {}) - ] + self.maintenance_mode_info.config = [item["ip_address"] for item in self.config.get("switches", {})] self.maintenance_mode_info.refresh() except (TypeError, ValueError) as error: msg = f"{self.class_name}.{method_name}: " @@ -1292,9 +1289,7 @@ def main(): "type": "str", } - ansible_module = AnsibleModule( - argument_spec=argument_spec, supports_check_mode=True - ) + ansible_module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) params = copy.deepcopy(ansible_module.params) params["check_mode"] = ansible_module.check_mode From 2f9bcd4b9051ca8a2a12ee96381c556ff9c28608 Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 11:10:56 -1000 Subject: [PATCH 04/14] UT: test_dcnm_maintenance_mode: linting No functional changes in this commit. Run black and isort linters against unit test files for dcnm_maintenance_mode. --- .../test_dcnm_maintenance_mode_common.py | 9 ++--- .../test_dcnm_maintenance_mode_merged.py | 34 ++++++++----------- .../test_dcnm_maintenance_mode_params_spec.py | 6 ++-- .../test_dcnm_maintenance_mode_query.py | 29 ++++++++-------- .../test_dcnm_maintenance_mode_want.py | 12 +++---- .../dcnm/dcnm_maintenance_mode/utils.py | 15 +++----- 6 files changed, 43 insertions(+), 62 deletions(-) diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py index 734cc5826..b3e38491f 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py @@ -29,12 +29,9 @@ import inspect import pytest -from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import \ - Common -from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import \ - ResponseGenerator -from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import ( - common_fixture, configs_common, does_not_raise, params) +from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import Common +from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import ResponseGenerator +from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import common_fixture, configs_common, does_not_raise, params def test_dcnm_maintenance_mode_common_00000(common) -> None: diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py index c4b43a40c..0fd42581c 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py @@ -30,22 +30,22 @@ import inspect import pytest -from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import \ - ResponseHandler -from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import \ - RestSend -from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import \ - Sender -from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import \ - Merged -from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import \ - ResponseGenerator +from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import ResponseHandler +from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import RestSend +from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import Sender +from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import Merged +from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import ResponseGenerator from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import ( - MockAnsibleModule, configs_merged, does_not_raise, params, - responses_ep_all_switches, responses_ep_fabrics, + MockAnsibleModule, + configs_merged, + does_not_raise, + params, + responses_ep_all_switches, + responses_ep_fabrics, responses_ep_maintenance_mode_deploy, responses_ep_maintenance_mode_disable, - responses_ep_maintenance_mode_enable) + responses_ep_maintenance_mode_enable, +) def test_dcnm_maintenance_mode_merged_00000() -> None: @@ -606,9 +606,7 @@ def responses(): instance.rest_send = rest_send instance.config = params_test.get("config") match = r"Merged\.fabric_deployment_disabled:\s+" - match += ( - r"The hosting fabric is in 'Deployment Disable' state for the switch with\s+" - ) + match += r"The hosting fabric is in 'Deployment Disable' state for the switch with\s+" match += r"ip_address 192\.168\.1\.2,\s+" match += r"serial_number FD2222222GA\.\s+" match += r"Review the 'Deployment Enable / Deployment Disable' setting on the controller at:\s+" @@ -902,9 +900,7 @@ def commit(self): match += r"Error detail:\s+" match += r"MockMaintenanceModeInfo\.refresh: Mocked ValueError\." with pytest.raises(ValueError, match=match): - monkeypatch.setattr( - instance, "maintenance_mode", MockMaintenanceMode(params_test) - ) + monkeypatch.setattr(instance, "maintenance_mode", MockMaintenanceMode(params_test)) instance.commit() assert len(instance.results.diff) == 2 diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py index 9b80c1456..e244eb49a 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py @@ -32,10 +32,8 @@ import copy import pytest -from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import \ - ParamsSpec -from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import ( - does_not_raise, params) +from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import ParamsSpec +from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import does_not_raise, params def test_dcnm_maintenance_mode_params_spec_00000() -> None: diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py index 934912b82..065c3101a 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py @@ -30,19 +30,19 @@ import inspect import pytest -from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import \ - ResponseHandler -from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import \ - RestSend -from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import \ - Sender -from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import \ - Query -from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import \ - ResponseGenerator +from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import ResponseHandler +from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import RestSend +from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import Sender +from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import Query +from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import ResponseGenerator from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import ( - MockAnsibleModule, configs_query, does_not_raise, params_query, - responses_ep_all_switches, responses_ep_fabrics) + MockAnsibleModule, + configs_query, + does_not_raise, + params_query, + responses_ep_all_switches, + responses_ep_fabrics, +) def test_dcnm_maintenance_mode_query_00000() -> None: @@ -350,6 +350,7 @@ class MockMaintenanceModeInfo: # pylint: disable=too-few-public-methods """ Mocked MaintenanceModeInfo class. """ + def __init__(self, *args): pass @@ -367,7 +368,5 @@ def refresh(self): match += r"Error detail: MockMaintenanceModeInfo\.refresh:\s+" match += r"Mocked ValueError\." with pytest.raises(ValueError, match=match): - monkeypatch.setattr( - instance, "maintenance_mode_info", MockMaintenanceModeInfo() - ) + monkeypatch.setattr(instance, "maintenance_mode_info", MockMaintenanceModeInfo()) instance.commit() diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py index 31d79f753..d9a79b926 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py @@ -30,14 +30,10 @@ import inspect import pytest -from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import ( - ParamsSpec, Want) -from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import \ - ResponseGenerator -from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.test_params_validate_v2 import \ - ParamsValidate -from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import ( - configs_want, does_not_raise, params) +from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import ParamsSpec, Want +from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import ResponseGenerator +from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.test_params_validate_v2 import ParamsValidate +from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.utils import configs_want, does_not_raise, params def test_dcnm_maintenance_mode_want_00000() -> None: diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py index 93245efd8..829316ab3 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py @@ -20,16 +20,11 @@ from contextlib import contextmanager import pytest -from ansible_collections.ansible.netcommon.tests.unit.modules.utils import \ - AnsibleFailJson -from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import \ - ResponseHandler -from ansible_collections.cisco.dcnm.plugins.module_utils.fabric.fabric_details_v2 import \ - FabricDetailsByName as FabricDetailsByNameV2 -from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import \ - Common -from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.fixture import \ - load_fixture +from ansible_collections.ansible.netcommon.tests.unit.modules.utils import AnsibleFailJson +from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import ResponseHandler +from ansible_collections.cisco.dcnm.plugins.module_utils.fabric.fabric_details_v2 import FabricDetailsByName as FabricDetailsByNameV2 +from ansible_collections.cisco.dcnm.plugins.modules.dcnm_maintenance_mode import Common +from ansible_collections.cisco.dcnm.tests.unit.modules.dcnm.dcnm_maintenance_mode.fixture import load_fixture params_query = { "state": "query", From ded7b59a334e02950e8348a6c90fbe599031886b Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 13:01:40 -1000 Subject: [PATCH 05/14] Update all docstrings to conform to Markdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes in this commit. This commit updates all docstrings to conform to the standards defined in CLAUDE.md (not in this repository). These standards include: 1. Structured headings # Summary ## Raises ### ValueError ## Other heading …etc 2. Single backticks around class, method, var, names, exception names, etc. --- .../module_utils/common/maintenance_mode.py | 406 +++-- .../common/maintenance_mode_info.py | 489 +++--- plugins/modules/dcnm_maintenance_mode.py | 612 ++++--- .../common/test_maintenance_mode.py | 982 ++++++----- .../common/test_maintenance_mode_info.py | 1446 ++++++++++------- 5 files changed, 2279 insertions(+), 1656 deletions(-) diff --git a/plugins/module_utils/common/maintenance_mode.py b/plugins/module_utils/common/maintenance_mode.py index 27aee90cd..49fc549c0 100644 --- a/plugins/module_utils/common/maintenance_mode.py +++ b/plugins/module_utils/common/maintenance_mode.py @@ -33,34 +33,34 @@ @Properties.add_results class MaintenanceMode: """ - ### Summary - - Modify the maintenance mode state of switches. - - Optionally deploy the changes. - - ### Raises - - ``ValueError`` in the following methods: - - __init__() if params is missing mandatory parameters - ``check_mode`` or ``state``. - - - ``ValueError`` in the following properties: - - ``config`` if config contains invalid content. - - ``commit`` if config, rest_send, or results are not set. - - ``commit`` if ``EpMaintenanceModeEnable`` or - ``EpMaintenanceModeDisable`` raise ``ValueError``. - - ``commit`` if either ``chance_system_mode()`` or - ``deploy_switches()`` raise ``ControllerResponseError``. - - - ``TypeError`` in the following properties: - - ``rest_send`` if value is not an instance of RestSend. - - ``results`` if value is not an instance of Results. - - ### Details - - Updates MaintenanceMode().results to reflect success/failure of - the operation on the controller. - - For switches that are to be deployed, initiates a per-fabric - bulk switch config-deploy. - - ### Example value for ``config`` in the ``Usage`` section below: + # Summary + + Modify the maintenance mode state of switches and optionally deploy the changes. + + ## Raises + + ### ValueError + + - `__init__()`: params is missing mandatory parameters `check_mode` or `state`. + - `config` property setter: config contains invalid content. + - `commit()`: config, rest_send, or results are not set. + - `commit()`: `EpMaintenanceModeEnable` or `EpMaintenanceModeDisable` raise `ValueError`. + - `commit()`: either `chance_system_mode()` or `deploy_switches()` raise `ControllerResponseError`. + + ### TypeError + + - `rest_send` property setter: value is not an instance of RestSend. + - `results` property setter: value is not an instance of Results. + + ## Details + + - Updates MaintenanceMode().results to reflect success/failure of + the operation on the controller. + - For switches that are to be deployed, initiates a per-fabric + bulk switch config-deploy. + + ## Example value for `config` in the `Usage` section below + ```json [ { @@ -80,16 +80,17 @@ class MaintenanceMode: ] ``` - ### Usage - - Where ``params`` is ``AnsibleModule.params`` - - Where ``config`` is a list of dicts, each containing the following: - - ``deploy``: ``bool``. If True, the switch maintenance mode - will be deployed. - - ``fabric_name``: ``str``. The name of the switch's hosting fabric. - - ``ip_address``: ``str``. The ip address of the switch. - - ``mode``: ``str``. The intended maintenance mode. Must be one of - "maintenance" or "normal". - - ``serial_number``: ``str``. The serial number of the switch. + ## Usage + + Where `params` is `AnsibleModule.params` and `config` is a list of dicts, + each containing the following: + + - `deploy`: `bool`. If True, the switch maintenance mode will be deployed. + - `fabric_name`: `str`. The name of the switch's hosting fabric. + - `ip_address`: `str`. The ip address of the switch. + - `mode`: `str`. The intended maintenance mode. Must be one of + "maintenance" or "normal". + - `serial_number`: `str`. The serial number of the switch. ```python instance = MaintenanceMode(params) @@ -151,20 +152,29 @@ def __init__(self, params): def verify_config_parameters(self, value) -> None: """ - ### Summary + # Summary + Verify that required parameters are present in config. - ### Raises - - ``TypeError`` if ``config`` is not a list. - - ``ValueError`` if ``config`` contains invalid content. - - ### NOTES - 1. See the following validation methods for details: - - verify_deploy() - - verify_fabric_name() - - verify_ip_address() - - verify_mode() - - verify_serial_number() + ## Raises + + ### TypeError + + - `config` is not a list. + + ### ValueError + + - `config` contains invalid content. + + ## Notes + + See the following validation methods for details: + + - verify_deploy() + - verify_fabric_name() + - verify_ip_address() + - verify_mode() + - verify_serial_number() """ method_name = inspect.stack()[0][3] if not isinstance(value, list): @@ -186,14 +196,19 @@ def verify_config_parameters(self, value) -> None: def verify_deploy(self, item) -> None: """ - ### Summary - Verify the ``deploy`` parameter. - - ### Raises - - ``ValueError`` if: - - ``deploy`` is not present. - - ``TypeError`` if: - - `deploy`` is not a boolean. + # Summary + + Verify the `deploy` parameter. + + ## Raises + + ### ValueError + + - `deploy` is not present. + + ### TypeError + + - `deploy` is not a boolean. """ method_name = inspect.stack()[0][3] if item.get("deploy", None) is None: @@ -209,13 +224,16 @@ def verify_deploy(self, item) -> None: def verify_fabric_name(self, item) -> None: """ - ### Summary - Validate the ``fabric_name`` parameter. + # Summary + + Validate the `fabric_name` parameter. + + ## Raises - ### Raises - - ``ValueError`` if: - - ``fabric_name`` is not present. - - ``fabric_name`` is not a valid fabric name. + ### ValueError + + - `fabric_name` is not present. + - `fabric_name` is not a valid fabric name. """ method_name = inspect.stack()[0][3] if item.get("fabric_name", None) is None: @@ -229,12 +247,15 @@ def verify_fabric_name(self, item) -> None: def verify_ip_address(self, item) -> None: """ - ### Summary - Validate the ``ip_address`` parameter. + # Summary + + Validate the `ip_address` parameter. + + ## Raises - ### Raises - - ``ValueError`` if: - - ``ip_address`` is not present. + ### ValueError + + - `ip_address` is not present. """ method_name = inspect.stack()[0][3] if item.get("ip_address", None) is None: @@ -244,13 +265,16 @@ def verify_ip_address(self, item) -> None: def verify_mode(self, item) -> None: """ - ### Summary - Validate the ``mode`` parameter. + # Summary + + Validate the `mode` parameter. - ### Raises - - ``ValueError`` if: - - ``mode`` is not present. - - ``mode`` is not one of "maintenance" or "normal". + ## Raises + + ### ValueError + + - `mode` is not present. + - `mode` is not one of "maintenance" or "normal". """ method_name = inspect.stack()[0][3] if item.get("mode", None) is None: @@ -265,12 +289,15 @@ def verify_mode(self, item) -> None: def verify_serial_number(self, item) -> None: """ - ### Summary - Validate the ``serial_number`` parameter. + # Summary + + Validate the `serial_number` parameter. + + ## Raises + + ### ValueError - ### Raises - - ``ValueError`` if: - - ``serial_number`` is not present. + - `serial_number` is not present. """ method_name = inspect.stack()[0][3] if item.get("serial_number", None) is None: @@ -280,14 +307,19 @@ def verify_serial_number(self, item) -> None: def verify_wait_for_mode_change(self, item) -> None: """ - ### Summary - Verify the ``wait_for_mode_change`` parameter. - - ### Raises - - ``ValueError`` if: - - ``wait_for_mode_change`` is not present. - - ``TypeError`` if: - - `wait_for_mode_change`` is not a boolean. + # Summary + + Verify the `wait_for_mode_change` parameter. + + ## Raises + + ### ValueError + + - `wait_for_mode_change` is not present. + + ### TypeError + + - `wait_for_mode_change` is not a boolean. """ method_name = inspect.stack()[0][3] if item.get("wait_for_mode_change", None) is None: @@ -303,14 +335,17 @@ def verify_wait_for_mode_change(self, item) -> None: def verify_commit_parameters(self) -> None: """ - ### Summary + # Summary + Verify that required parameters are present before calling commit. - ### Raises - - ``ValueError`` if: - - ``config`` is not set. - - ``rest_send`` is not set. - - ``results`` is not set. + ## Raises + + ### ValueError + + - `config` is not set. + - `rest_send` is not set. + - `results` is not set. """ method_name = inspect.stack()[0][3] if self.config is None: @@ -331,18 +366,21 @@ def verify_commit_parameters(self) -> None: def commit(self) -> None: """ - ### Summary + # Summary + Initiates the maintenance mode change on the controller. - ### Raises - - ``ValueError`` if - - ``config`` is not set. - - ``rest_send`` is not set. - - ``results`` is not set. - - any exception is raised by: - - ``verify_commit_parameters()`` - - ``change_system_mode()`` - - ``deploy_switches()`` + ## Raises + + ### ValueError + + - `config` is not set. + - `rest_send` is not set. + - `results` is not set. + - any exception is raised by: + - `verify_commit_parameters()` + - `change_system_mode()` + - `deploy_switches()` """ try: self.verify_commit_parameters() @@ -357,18 +395,25 @@ def commit(self) -> None: def change_system_mode(self) -> None: """ - ### Summary + # Summary + Send the maintenance mode change request to the controller. - ### Raises - - ``ControllerResponseError`` if: - - controller response != 200. - - ``ValueError`` if: - - ``fabric_name`` is invalid. - - endpoint cannot be resolved. - - ``Results()`` raises an exception. - - ``TypeError`` if: - - ``serial_number`` is not a string. + ## Raises + + ### ControllerResponseError + + - controller response != 200. + + ### ValueError + + - `fabric_name` is invalid. + - endpoint cannot be resolved. + - `Results()` raises an exception. + + ### TypeError + + - `serial_number` is not a string. """ method_name = inspect.stack()[0][3] @@ -432,41 +477,46 @@ def change_system_mode(self) -> None: def build_deploy_dict(self) -> None: """ - ### Summary - - Build the deploy_dict + # Summary + + Build the deploy_dict + + ## Raises - ### Raises None - ### Structure - - key: fabric_name - - value: list of dict - - each dict contains ``serial_number`` and ``wait_for_mode_change keys`` + ## Structure + + - key: fabric_name + - value: list of dict + - each dict contains `serial_number` and `wait_for_mode_change` keys + + ## Example - ### Example ```json { "MyFabric": [ { "serial_number": "CDM4593459", - "wait_for_mode_change": True + "wait_for_mode_change": true }, { "serial_number": "CDM4593460", - "wait_for_mode_change": False + "wait_for_mode_change": false } ], "YourFabric": [ { "serial_number": "DDM0455882", - "wait_for_mode_change": True + "wait_for_mode_change": true }, { "serial_number": "DDM5598759", - "wait_for_mode_change": True + "wait_for_mode_change": true } ] } + ``` """ self.deploy_dict = {} for item in self.config: @@ -484,25 +534,27 @@ def build_deploy_dict(self) -> None: def build_serial_number_to_ip_address(self) -> None: """ - ### Summary + # Summary + Populate self.serial_number_to_ip_address dict. - ### Raises + ## Raises + None - ### Structure - - key: switch serial_number - - value: associated switch ip_address + ## Structure + + - key: switch serial_number + - value: associated switch ip_address ```json { "CDM4593459": "192.168.1.2" } ``` - ### Raises - None - ### Notes - - ip_address and serial_number are added to the diff in the - ``deploy_switches()`` method. + ## Notes + + ip_address and serial_number are added to the diff in the + `deploy_switches()` method. """ for item in self.config: serial_number = item.get("serial_number") @@ -511,11 +563,15 @@ def build_serial_number_to_ip_address(self) -> None: def build_endpoints(self) -> None: """ - ### Summary - Build ``endpoints`` dict used in ``self.deploy_switches``. + # Summary + + Build `endpoints` dict used in `self.deploy_switches`. + + ## Raises + + ### ValueError - ### Raises - ``ValueError`` if endpoint configuration fails. + - endpoint configuration fails. """ method_name = inspect.stack()[0][3] endpoints = [] @@ -540,14 +596,19 @@ def build_endpoints(self) -> None: def deploy_switches(self) -> None: """ - ### Summary - Initiate config-deploy for the switches in ``self.deploy_dict``. - - ### Raises - - ``ControllerResponseError`` if: - - controller response != 200. - - ``ValueError`` if: - - endpoint cannot be resolved. + # Summary + + Initiate config-deploy for the switches in `self.deploy_dict`. + + ## Raises + + ### ControllerResponseError + + - controller response != 200. + + ### ValueError + + - endpoint cannot be resolved. """ method_name = inspect.stack()[0][3] self.build_deploy_dict() @@ -598,31 +659,30 @@ def deploy_switches(self) -> None: @property def config(self) -> list: """ - ### Summary - The maintenance mode configurations to be sent to the controller. - - ### Raises - - setter: ``ValueError`` if: - - value is not a list. - - value contains invalid content. - - ### getter - Return ``config``. - - ### setter - Set ``config``. - - ### Value structure - value is a ``list`` of ``dict``. Each dict must contain the following: - - ``deploy``: ``bool``. If True, the switch maintenance mode - will be deployed. - - ``fabric_name``: ``str``. The name of the switch's hosting fabric. - - ``ip_address``: ``str``. The ip address of the switch. - - ``mode``: ``str``. The intended maintenance mode. Must be one of - "maintenance" or "normal". - - ``serial_number``: ``str``. The serial number of the switch. - - ### Example + # Summary + + Get/set the maintenance mode configurations to be sent to the controller. + + ## Raises + + ### ValueError + + - setter: value is not a list. + - setter: value contains invalid content. + + ## Value structure + + value is a `list` of `dict`. Each dict must contain the following: + + - `deploy`: `bool`. If True, the switch maintenance mode will be deployed. + - `fabric_name`: `str`. The name of the switch's hosting fabric. + - `ip_address`: `str`. The ip address of the switch. + - `mode`: `str`. The intended maintenance mode. Must be one of + "maintenance" or "normal". + - `serial_number`: `str`. The serial number of the switch. + + ## Example + ```json [ { diff --git a/plugins/module_utils/common/maintenance_mode_info.py b/plugins/module_utils/common/maintenance_mode_info.py index 73915ebb0..b2c1397ec 100644 --- a/plugins/module_utils/common/maintenance_mode_info.py +++ b/plugins/module_utils/common/maintenance_mode_info.py @@ -34,60 +34,68 @@ @Properties.add_results class MaintenanceModeInfo: """ - ### Summary - - Retrieve the maintenance mode state of switches. - - ### Raises - - ``TypeError`` in the following public properties: - - ``config`` if value is not a list. - - ``rest_send`` if value is not an instance of RestSend. - - ``results`` if value is not an instance of Results. - - - ``ValueError`` in the following public methods: - - ``refresh()`` if: - - ``config`` has not been set. - - ``rest_send`` has not been set. - - ``results`` has not been set. - - ### Details - Updates ``MaintenanceModeInfo().results`` to reflect success/failure of + # Summary + + Retrieve the maintenance mode state of switches. + + ## Raises + + ### TypeError + + - `config` property setter: value is not a list. + - `rest_send` property setter: value is not an instance of RestSend. + - `results` property setter: value is not an instance of Results. + + ### ValueError + + - `refresh()`: `config` has not been set. + - `refresh()`: `rest_send` has not been set. + - `refresh()`: `results` has not been set. + + ## Details + + Updates `MaintenanceModeInfo().results` to reflect success/failure of the operation on the controller. - Example value for ``config`` in the ``Usage`` section below: + ## Example value for `config` in the `Usage` section below + ```json ["192.168.1.2", "192.168.1.3"] ``` - Example value for ``info`` in the ``Usage`` section below: - ```json - { - "192.169.1.2": { - deployment_disabled: true - fabric_freeze_mode: true, - fabric_name: "MyFabric", - fabric_read_only: true - mode: "maintenance", - role: "spine", - serial_number: "FCI1234567" - }, - "192.169.1.3": { - deployment_disabled: false, - fabric_freeze_mode: false, - fabric_name: "YourFabric", - fabric_read_only: false - mode: "normal", - role: "leaf", - serial_number: "FCH2345678" - } + ## Example value for `info` in the `Usage` section below + + ```json + { + "192.169.1.2": { + "deployment_disabled": true, + "fabric_freeze_mode": true, + "fabric_name": "MyFabric", + "fabric_read_only": true, + "mode": "maintenance", + "role": "spine", + "serial_number": "FCI1234567" + }, + "192.169.1.3": { + "deployment_disabled": false, + "fabric_freeze_mode": false, + "fabric_name": "YourFabric", + "fabric_read_only": false, + "mode": "normal", + "role": "leaf", + "serial_number": "FCH2345678" } - ``` + } + ``` + + ## Usage + + Where: - ### Usage - - Where: - - ``params`` is ``AnsibleModule.params`` - - ``config`` is per the above example. - - ``sender`` is an instance of a Sender() class. - See ``sender_dcnm.py`` for usage. + - `params` is `AnsibleModule.params` + - `config` is per the above example. + - `sender` is an instance of a Sender() class. + See `sender_dcnm.py` for usage. ```python ansible_module = AnsibleModule() @@ -139,15 +147,17 @@ def __init__(self, params): def verify_refresh_parameters(self) -> None: """ - ### Summary - Verify that required parameters are present before - calling ``refresh()``. - - ### Raises - - ``ValueError`` if: - - ``config`` is not set. - - ``rest_send`` is not set. - - ``results`` is not set. + # Summary + + Verify that required parameters are present before calling `refresh()`. + + ## Raises + + ### ValueError + + - `config` is not set. + - `rest_send` is not set. + - `results` is not set. """ method_name = inspect.stack()[0][3] if self.config is None: @@ -168,47 +178,52 @@ def verify_refresh_parameters(self) -> None: def refresh(self): """ - ### Summary - Build ``self.info``, a dict containing the current maintenance mode + # Summary + + Build `self.info`, a dict containing the current maintenance mode status of all switches in self.config. - ### Raises - - ``ValueError`` if: - - ``SwitchDetails()`` raises ``ControllerResponseError`` - - ``SwitchDetails()`` raises ``ValueError`` - - ``FabricDetails()`` raises ``ControllerResponseError`` - - switch with ``ip_address`` does not exist on the controller. + ## Raises + + ### ValueError + + - `SwitchDetails()` raises `ControllerResponseError` + - `SwitchDetails()` raises `ValueError` + - `FabricDetails()` raises `ControllerResponseError` + - switch with `ip_address` does not exist on the controller. + + ## self.info structure - ### self.info structure info is a dict, keyed on switch_ip, where each element is a dict with the following structure: - - ``fabric_name``: The name of the switch's hosting fabric. - - ``freeze_mode``: The current state of the switch's hosting fabric. - If freeze_mode is True, configuration changes cannot be made to the - fabric or the switches within the fabric. - - ``mode``: The current maintenance mode of the switch. - - ``role``: The role of the switch in the hosting fabric. - - ``serial_number``: The serial number of the switch. + + - `fabric_name`: The name of the switch's hosting fabric. + - `freeze_mode`: The current state of the switch's hosting fabric. + If freeze_mode is True, configuration changes cannot be made to the + fabric or the switches within the fabric. + - `mode`: The current maintenance mode of the switch. + - `role`: The role of the switch in the hosting fabric. + - `serial_number`: The serial number of the switch. ```json { "192.169.1.2": { - fabric_deployment_disabled: true - fabric_freeze_mode: true, - fabric_name: "MyFabric", - fabric_read_only: true - mode: "maintenance", - role: "spine", - serial_number: "FCI1234567" + "fabric_deployment_disabled": true, + "fabric_freeze_mode": true, + "fabric_name": "MyFabric", + "fabric_read_only": true, + "mode": "maintenance", + "role": "spine", + "serial_number": "FCI1234567" }, "192.169.1.3": { - fabric_deployment_disabled: false, - fabric_freeze_mode: false, - fabric_name: "YourFabric", - fabric_read_only: false - mode: "normal", - role: "leaf", - serial_number: "FCH2345678" + "fabric_deployment_disabled": false, + "fabric_freeze_mode": false, + "fabric_name": "YourFabric", + "fabric_read_only": false, + "mode": "normal", + "role": "leaf", + "serial_number": "FCH2345678" } } ``` @@ -303,15 +318,21 @@ def refresh(self): def _get(self, item): """ + # Summary + Return the value of the item from the filtered switch. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - ### NOTES - - We do not need to check that ``item`` exists in the filtered - switch dict, since ``refresh()`` has already done so. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + + ## Notes + + We do not need to check that `item` exists in the filtered + switch dict, since `refresh()` has already done so. """ method_name = inspect.stack()[0][3] @@ -332,20 +353,25 @@ def _get(self, item): @property def filter(self): """ - ### Summary + # Summary + Set the query filter (switch IP address) - ### Raises - None. However, if ``filter`` is not set, or ``filter`` is set to + ## Raises + + None + + However, if `filter` is not set, or `filter` is set to an ip_address for a switch that does not exist on the controller, - ``ValueError`` will be raised when accessing the various getter + `ValueError` will be raised when accessing the various getter properties. - ### Details + ## Details + The filter should be the ip_address of the switch from which to retrieve details. - ``filter`` must be set before accessing this class's properties. + `filter` must be set before accessing this class's properties. """ return self._filter @@ -356,25 +382,34 @@ def filter(self, value): @property def config(self) -> list: """ - ### Summary + # Summary + A list of switch ip addresses for which maintenance mode state will be retrieved. - ### Raises - - setter: ``TypeError`` if: - - ``config`` is not a ``list``. - - Elements of ``config`` are not ``str``. + ## Raises + + ### TypeError - ### getter - Return ``config``. + setter: - ### setter - Set ``config``. + - `config` is not a `list`. + - Elements of `config` are not `str`. - ### Value structure - value is a ``list`` of ip addresses + ## getter + + Return `config`. + + ## setter + + Set `config`. + + ## Value structure + + value is a `list` of ip addresses + + ## Example - ### Example ```json ["172.22.150.2", "172.22.150.3"] ``` @@ -404,136 +439,159 @@ def config(self, value): @property def fabric_deployment_disabled(self): """ - ### Summary - The current ``fabric_deployment_disabled`` state of the + # Summary + + The current `fabric_deployment_disabled` state of the filtered switch's hosting fabric. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``deployment_disabled`` is not in the filtered switch dict. - - ### Valid values - - ``True``: The fabric is in a state where configuration changes - cannot be made. - - ``False``: The fabric is in a state where configuration changes - can be made. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `deployment_disabled` is not in the filtered switch dict. + + ## Valid values + + - `True`: The fabric is in a state where configuration changes + cannot be made. + - `False`: The fabric is in a state where configuration changes + can be made. """ return self._get("fabric_deployment_disabled") @property def fabric_freeze_mode(self): """ - ### Summary + # Summary + The freezeMode state of the fabric in which the filtered switch resides. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``fabric_name`` is not in the filtered switch dict. - - ### Valid values - - ``True``: The fabric is in a state where configuration changes - cannot be made. - - ``False``: The fabric is in a state where configuration changes - can be made. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `fabric_name` is not in the filtered switch dict. + + ## Valid values + + - `True`: The fabric is in a state where configuration changes + cannot be made. + - `False`: The fabric is in a state where configuration changes + can be made. """ return self._get("fabric_freeze_mode") @property def fabric_name(self): """ - ### Summary + # Summary + The name of the fabric in which the filtered switch resides. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``fabric_name`` is not in the filtered switch dict. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `fabric_name` is not in the filtered switch dict. """ return self._get("fabric_name") @property def fabric_read_only(self): """ - ### Summary + # Summary + The read-only state of the fabric in which the filtered switch resides. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``fabric_name`` is not in the filtered switch dict. - - ### Valid values - - ``True``: The fabric is in a state where configuration changes - cannot be made. - - ``False``: The fabric is in a state where configuration changes - can be made. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `fabric_name` is not in the filtered switch dict. + + ## Valid values + + - `True`: The fabric is in a state where configuration changes + cannot be made. + - `False`: The fabric is in a state where configuration changes + can be made. """ return self._get("fabric_read_only") @property def info(self) -> dict: """ - ### Summary + # Summary + Return or set the current maintenance mode state of the switches represented by the ip_addresses in self.config. - ### Raises - - ``ValueError`` if: - - ``refresh()`` has not been called before accessing ``info``. + ## Raises + + ### ValueError - ### getter - Return ``info``. + - `refresh()` has not been called before accessing `info`. - ### setter - Set ``info``. + ## getter - ### ``info`` structure - ``info`` is a dict, keyed on switch_ip, where each element is a dict + Return `info`. + + ## setter + + Set `info`. + + ## `info` structure + + `info` is a dict, keyed on switch_ip, where each element is a dict with the following structure: - - ``fabric_deployment_disabled``: The current state of the switch's - hosting fabric. If fabric_deployment_disabled is True, - configuration changes cannot be made to the fabric or the switches - within the fabric. - - ``fabric_name``: The name of the switch's hosting fabric. - - ``fabric_freeze_mode``: The current state of the switch's - hosting fabric. If freeze_mode is True, configuration changes - cannot be made to the fabric or the switches within the fabric. - - ``fabric_read_only``: The current state of the switch's - hosting fabric. If fabric_read_only is True, configuration changes - cannot be made to the fabric or the switches within the fabric. - - ``mode``: The current maintenance mode of the switch. - - ``role``: The role of the switch in the hosting fabric. - - ``serial_number``: The serial number of the switch. - - ### Example info dict + + - `fabric_deployment_disabled`: The current state of the switch's + hosting fabric. If fabric_deployment_disabled is True, + configuration changes cannot be made to the fabric or the switches + within the fabric. + - `fabric_name`: The name of the switch's hosting fabric. + - `fabric_freeze_mode`: The current state of the switch's + hosting fabric. If freeze_mode is True, configuration changes + cannot be made to the fabric or the switches within the fabric. + - `fabric_read_only`: The current state of the switch's + hosting fabric. If fabric_read_only is True, configuration changes + cannot be made to the fabric or the switches within the fabric. + - `mode`: The current maintenance mode of the switch. + - `role`: The role of the switch in the hosting fabric. + - `serial_number`: The serial number of the switch. + + ## Example info dict + ```json { "192.169.1.2": { - fabric_deployment_disabled: true - fabric_freeze_mode: true, - fabric_name: "MyFabric", - fabric_read_only: true - mode: "maintenance", - role: "spine", - serial_number: "FCI1234567" + "fabric_deployment_disabled": true, + "fabric_freeze_mode": true, + "fabric_name": "MyFabric", + "fabric_read_only": true, + "mode": "maintenance", + "role": "spine", + "serial_number": "FCI1234567" }, "192.169.1.3": { - fabric_deployment_disabled: false - fabric_freeze_mode: false, - fabric_name: "YourFabric", - fabric_read_only: false - mode: "normal", - role: "leaf", - serial_number: "FCH2345678" + "fabric_deployment_disabled": false, + "fabric_freeze_mode": false, + "fabric_name": "YourFabric", + "fabric_read_only": false, + "mode": "normal", + "role": "leaf", + "serial_number": "FCH2345678" } } ``` @@ -558,41 +616,50 @@ def info(self, value: dict): @property def mode(self): """ - ### Summary + # Summary + The current maintenance mode of the filtered switch. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``mode`` is not in the filtered switch dict. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `mode` is not in the filtered switch dict. """ return self._get("mode") @property def role(self): """ - ### Summary + # Summary + The role of the filtered switch in the hosting fabric. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``role`` is not in the filtered switch dict. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `role` is not in the filtered switch dict. """ return self._get("role") @property def serial_number(self): """ - ### Summary + # Summary + The serial number of the filtered switch. - ### Raises - - ``ValueError`` if: - - ``filter`` is not set. - - ``filter`` is not in the controller response. - - ``serial_number`` is not in the filtered switch dict. + ## Raises + + ### ValueError + + - `filter` is not set. + - `filter` is not in the controller response. + - `serial_number` is not in the filtered switch dict. """ return self._get("serial_number") diff --git a/plugins/modules/dcnm_maintenance_mode.py b/plugins/modules/dcnm_maintenance_mode.py index c2265ab54..da04957cd 100644 --- a/plugins/modules/dcnm_maintenance_mode.py +++ b/plugins/modules/dcnm_maintenance_mode.py @@ -172,9 +172,16 @@ def json_pretty(msg): class ParamsSpec: """ + # Summary + Build parameter specifications for the dcnm_maintenance_mode module. - ### Usage + ## Raises + + None + + ## Usage + ```python from ansible.module_utils.basic import AnsibleModule @@ -217,10 +224,15 @@ def __init__(self): def commit(self): """ + # Summary + Build the parameter specification based on the state ## Raises - - ``ValueError`` if params is not set + + ### ValueError + + - params is not set """ if self._params is None: msg = f"{self.class_name}.commit: " @@ -276,19 +288,26 @@ def params_spec(self) -> dict: @property def params(self) -> dict: """ - ### Summary + # Summary + Expects value to be a dictionary containing, at mimimum, the key "state" with value of either "merged" or "query". - ### Raises - - setter: raise ``ValueError`` if value is not a dict - - setter: raise ``ValueError`` if value["state"] is missing - - setter: raise ``ValueError`` if value["state"] is not a valid state + ## Raises - ### Details - - Valid params: {"state": "merged"} or {"state": "query"} - - getter: return the params - - setter: set the params + ### ValueError + + setter: + + - value is not a dict + - value["state"] is missing + - value["state"] is not a valid state + + ## Details + + - Valid params: {"state": "merged"} or {"state": "query"} + - getter: return the params + - setter: set the params """ return self._params @@ -321,23 +340,29 @@ def params(self, value: dict) -> None: class Want: """ - ### Summary + # Summary + Build self.want, a list of validated playbook configurations. - ### Raises - - ``ValueError`` in the following cases: - - ``commit()`` is issued before setting mandatory properties - - When passing invalid values to property setters - - ``TypeError`` in the following cases: - - When passing invalid types to property setters + ## Raises + + ### ValueError + + - `commit()` is issued before setting mandatory properties + - When passing invalid values to property setters + ### TypeError + + - When passing invalid types to property setters + + ## Details - ### Details 1. Merge the playbook global config into each switch config. 2. Validate the merged configs from step 1 against the param spec. 3. Populate self.want with the validated configs. - ### Usage + ## Usage + ```python try: instance = Want() @@ -351,20 +376,21 @@ class Want: except (TypeError, ValueError) as error: handle_error(error) ``` - ### self.want structure + + ## self.want structure ```json [ { "ip_address": "192.168.1.2", "mode": "maintenance", - "deploy": false + "deploy": false, "wait_for_mode_change": false }, { "ip_address": "192.168.1.3", "mode": "normal", - "deploy": true + "deploy": true, "wait_for_mode_change": true } ] @@ -390,12 +416,16 @@ def __init__(self): def generate_params_spec(self) -> None: """ - ### Summary + # Summary + Generate the params_spec used to validate the configs - ### Raises - - ``ValueError`` if self.params is not set - - ``ValueError`` if self.params_spec is not set + ## Raises + + ### ValueError + + - self.params is not set + - self.params_spec is not set """ # Generate the params_spec used to validate the configs if self.params is None: @@ -416,15 +446,18 @@ def generate_params_spec(self) -> None: def validate_configs(self) -> None: """ - ### Summary + # Summary + Validate the merged configs against the param spec and populate self.want with the validated configs. - ### Raises + ## Raises + None - ### Notes - - validator is already verified in commit()s + ## Notes + + validator is already verified in commit()s """ self.validator.params_spec = self.params_spec.params_spec for config in self.merged_configs: @@ -434,12 +467,14 @@ def validate_configs(self) -> None: def build_merged_configs(self) -> None: """ - ### Summary + # Summary + If a parameter is missing from the config, and the parameter has a default value, merge the default value for the parameter into the config. - ### Raises + ## Raises + None """ self.merged_configs = [] @@ -456,25 +491,34 @@ def build_merged_configs(self) -> None: def commit(self) -> None: """ - ### Summary + # Summary + Build self.want, a list of validated playbook configurations. - ### Raises - - ``ValueError`` if: - - self.config is not set - - self.item_key is not set - - self.params is not set - - self.params_spec is not set - - self.validator is not set - - self.params_spec raises ``ValueError`` - - _merge_global_and_switch_configs() raises ``ValueError`` - - merge_dicts() raises `TypeError``` or ``ValueError`` - - playbook is missing list of items - - ### Details + ## Raises + + ### ValueError + + - self.config is not set + - self.item_key is not set + - self.params is not set + - self.params_spec is not set + - self.validator is not set + - self.params_spec raises `ValueError` + - _merge_global_and_switch_configs() raises `ValueError` + - merge_dicts() raises `ValueError` + - playbook is missing list of items + + ### TypeError + + - merge_dicts() raises `TypeError` + + ## Details + See class docstring. - ### self.want structure + ## self.want structure + See class docstring. """ method_name = inspect.stack()[0][3] @@ -512,23 +556,32 @@ def commit(self) -> None: def _merge_global_and_item_configs(self) -> None: """ - ### Summary + # Summary + Builds self.item_configs from self.config Merge the global playbook config with each item config and populate a list of merged configs (``self.item_configs``). - ### Raises - - ``ValueError`` if self.config is not set - - ``ValueError`` if self.items_key is not set - - ``ValueError`` if playbook is missing list of items - - ``ValueError`` if merge_dicts raises ``TypeError`` or ``ValueError`` - - ### Merge rules - - item_config takes precedence over global_config. - - If item_config is missing a parameter, use parameter - from global_config. - - If item_config has a parameter, use it. + ## Raises + + ### ValueError + + - self.config is not set + - self.items_key is not set + - playbook is missing list of items + - merge_dicts raises `ValueError` + + ### TypeError + + - merge_dicts raises `TypeError` + + ## Merge rules + + - item_config takes precedence over global_config. + - If item_config is missing a parameter, use parameter + from global_config. + - If item_config has a parameter, use it. """ method_name = inspect.stack()[0][3] @@ -585,15 +638,25 @@ def _merge_global_and_item_configs(self) -> None: @property def config(self): """ - ### Summary + # Summary + The playbook configuration to be processed. - ``config`` is processed by ``_merge_global_and_switch_configs()`` - to build ``switch_configs``. + `config` is processed by `_merge_global_and_switch_configs()` + to build `switch_configs`. + + ## Raises + + ### TypeError + + setter: - - getter: return config - - setter: set config - - setter: raise ``ValueError`` if value is not a dict + - value is not a dict + + ## Details + + - getter: return config + - setter: set config """ return self._config @@ -609,12 +672,23 @@ def config(self, value) -> None: @property def items_key(self) -> str: """ + # Summary + Expects value to be the key for the list of items in the playbook config. - - getter: return the items_key - - setter: set the items_key - - setter: raise ``ValueError`` if value is not a string + ## Raises + + ### TypeError + + setter: + + - value is not a string + + ## Details + + - getter: return the items_key + - setter: set the items_key """ return self._items_key @@ -633,27 +707,37 @@ def items_key(self, value: str) -> None: @property def want(self) -> list: """ - ### Summary + # Summary + Return the want list. See class docstring for structure details. + + ## Raises + + None """ return self._want @property def params(self) -> dict: """ - ### Summary - The return value of ``AnsibleModule.params`` property - (or equivalent dict). This is passed to ``params_spec`` + # Summary + + The return value of `AnsibleModule.params` property + (or equivalent dict). This is passed to `params_spec` and used in playbook config validation. - ### Raises - - setter: raise ``ValueError`` if value is not a ``dict``. + ## Raises - ### getter - Return params + ### TypeError - ### setter - Set params + setter: + + - value is not a `dict` + + ## Details + + - getter: Return params + - setter: Set params """ return self._params @@ -672,22 +756,26 @@ def params(self, value: dict) -> None: @property def params_spec(self): """ - ### Summary + # Summary + The parameter specification used to validate the playbook config. - Expects value to be an instance of ``ParamsSpec()``. + Expects value to be an instance of `ParamsSpec()`. - ``params_spec`` is passed to ``validator`` to validate the + `params_spec` is passed to `validator` to validate the playbook config. - ### Raises - - setter: raise ``TypeError`` if value is not an instance - of ParamsSpec() + ## Raises - ### getter - Return params_spec + ### TypeError - ### setter - Set params_spec + setter: + + - value is not an instance of ParamsSpec() + + ## Details + + - getter: Return params_spec + - setter: Set params_spec """ return self._params_spec @@ -712,18 +800,23 @@ def params_spec(self, value) -> None: @property def validator(self): """ - ### Summary - ``validator`` is used to validate the playbook config. - Expects value to be an instance of ``ParamsValidate()``. + # Summary + + `validator` is used to validate the playbook config. + Expects value to be an instance of `ParamsValidate()`. + + ## Raises + + ### TypeError + + setter: - ### Raises - - setter: ``TypeError`` if value is not an instance of ``ParamsValidate()`` + - value is not an instance of ``ParamsValidate()`` - ### getter - Return validator + ## Details - ### setter - Set validator + - getter: Return validator + - setter: Set validator """ return self._validator @@ -754,13 +847,21 @@ class Common: def __init__(self, params): """ - ### Raises - - ``ValueError`` if: - - ``params`` does not contain ``check_mode`` - - ``params`` does not contain ``state`` - - ``params`` does not contain ``config`` - - ``TypeError`` if: - - ``config`` is not a dict + # Summary + + Initialize Common instance + + ## Raises + + ### ValueError + + - `params` does not contain `check_mode` + - `params` does not contain `state` + - `params` does not contain `config` + + ### TypeError + + - `config` is not a dict """ self.class_name = self.__class__.__name__ method_name = inspect.stack()[0][3] @@ -810,11 +911,19 @@ def __init__(self, params): def get_want(self) -> None: """ - ### Summary + # Summary + Build self.want, a list of validated playbook configurations. - ### Raises - - ``ValueError`` if Want() instance raises ``ValueError`` + ## Raises + + ### ValueError + + - Want() instance raises `ValueError` + + ### TypeError + + - Want() instance raises `TypeError` """ try: instance = Want() @@ -831,16 +940,36 @@ def get_want(self) -> None: class Merged(Common): """ + # Summary + Handle merged state - ### Raises - - ``ValueError`` if Common().__init__() raises ``ValueError`` + ## Raises + + ### ValueError + + - Common().__init__() raises ``ValueError`` + + ### TypeError + + - Common().__init__() raises `TypeError` """ def __init__(self, params): """ - ### Raises - - ``ValueError`` if Common().__init__() raises ``ValueError`` + # Summary + + Initialize Merged instance + + ## Raises + + ### ValueError + + - Common().__init__() raises `ValueError` + + ### TypeError + + - Common().__init__() raises `TypeError` """ self.class_name = self.__class__.__name__ method_name = inspect.stack()[0][3] @@ -865,49 +994,59 @@ def __init__(self, params): def get_have(self): """ - ### Summary + # Summary + Build self.have, a dict containing the current mode of all switches. - ### Raises - - ``ValueError`` if self.ansible_module is not set - - ``ValueError`` if MaintenanceModeInfo() raises ``ValueError`` + ## Raises + + ### ValueError + + - self.ansible_module is not set + - MaintenanceModeInfo() raises `ValueError` + + ### TypeError + + - MaintenanceModeInfo() raises `TypeError` + + ## self.have structure - ### self.have structure Have is a dict, keyed on switch_ip, where each element is a dict with the following structure: - - ``fabric_name``: The name of the switch's hosting fabric. - - ``fabric_freeze_mode``: The current ``freezeMode`` state of the switch's - hosting fabric. If ``freeze_mode`` is True, configuration changes cannot - be made to the fabric or the switches within the fabric. - - ``fabric_read_only``: The current ``IS_READ_ONLY`` state of the switch's - hosting fabric. If ``fabric_read_only`` is True, configuration changes cannot - be made to the fabric or the switches within the fabric. - - ``mode``: The current maintenance mode of the switch. - Possible values include: , ``inconsistent``, ``maintenance``, - ``migration``, ``normal``. - - ``role``: The role of the switch in the hosting fabric, e.g. - ``spine``, ``leaf``, ``border_gateway``, etc. - - ``serial_number``: The serial number of the switch. + + - `fabric_name`: The name of the switch's hosting fabric. + - `fabric_freeze_mode`: The current `freezeMode` state of the switch's + hosting fabric. If `freeze_mode` is True, configuration changes cannot + be made to the fabric or the switches within the fabric. + - `fabric_read_only`: The current `IS_READ_ONLY` state of the switch's + hosting fabric. If `fabric_read_only` is True, configuration changes cannot + be made to the fabric or the switches within the fabric. + - `mode`: The current maintenance mode of the switch. + Possible values include: , `inconsistent`, `maintenance`, + `migration`, `normal`. + - `role`: The role of the switch in the hosting fabric, e.g. + `spine`, `leaf`, `border_gateway`, etc. + - `serial_number`: The serial number of the switch. ```json { "192.169.1.2": { - fabric_deployment_disabled: true - fabric_freeze_mode: true, - fabric_name: "MyFabric", - fabric_read_only: true - mode: "maintenance", - role: "spine", - serial_number: "FCI1234567" + "fabric_deployment_disabled": true, + "fabric_freeze_mode": true, + "fabric_name": "MyFabric", + "fabric_read_only": true, + "mode": "maintenance", + "role": "spine", + "serial_number": "FCI1234567" }, "192.169.1.3": { - fabric_deployment_disabled: false - fabric_freeze_mode: false, - fabric_name: "YourFabric", - fabric_read_only: false - mode: "normal", - role: "leaf", - serial_number: "FCH2345678" + "fabric_deployment_disabled": false, + "fabric_freeze_mode": false, + "fabric_name": "YourFabric", + "fabric_read_only": false, + "mode": "normal", + "role": "leaf", + "serial_number": "FCH2345678" } } ``` @@ -929,14 +1068,19 @@ def get_have(self): def fabric_deployment_disabled(self) -> None: """ - ### Summary + # Summary + Handle the following cases: - - switch migration mode is ``migration`` - - fabric is in read-only mode (IS_READ_ONLY is True) - - fabric is in freeze mode (Deployment Disable) - ### Raises - - ``ValueError`` if any of the above cases are true + - switch migration mode is `migration` + - fabric is in read-only mode (IS_READ_ONLY is True) + - fabric is in freeze mode (Deployment Disable) + + ## Raises + + ### ValueError + + - any of the above cases are true """ method_name = inspect.stack()[0][3] for ip_address, value in self.have.items(): @@ -1000,13 +1144,18 @@ def fabric_deployment_disabled(self) -> None: def get_need(self): """ - ### Summary + # Summary + Build self.need for merged state. - ### Raises - - ``ValueError`` if the switch is not found on the controller. + ## Raises + + ### ValueError + + - the switch is not found on the controller + + ## self.need structure - ### self.need structure ```json [ { @@ -1014,7 +1163,7 @@ def get_need(self): "fabric_name": "MyFabric", "ip_address": "172.22.150.2", "mode": "maintenance", - "serial_number": "FCI1234567" + "serial_number": "FCI1234567", "wait_for_mode_change": true }, { @@ -1022,10 +1171,11 @@ def get_need(self): "fabric_name": "YourFabric", "ip_address": "172.22.150.3", "mode": "normal", - "serial_number": "HMD2345678" + "serial_number": "HMD2345678", "wait_for_mode_change": true } ] + ``` """ method_name = inspect.stack()[0][3] self.need = [] @@ -1050,15 +1200,18 @@ def get_need(self): def commit(self): """ - ### Summary + # Summary + Commit the merged state request - ### Raises - - ``ValueError`` if: - - ``rest_send`` is not set. - - ``get_want()`` raises ``ValueError`` - - ``get_have()`` raises ``ValueError`` - - ``send_need()`` raises ``ValueError`` + ## Raises + + ### ValueError + + - `rest_send` is not set + - `get_want()` raises `ValueError` + - `get_have()` raises `ValueError` + - `send_need()` raises `ValueError` """ method_name = inspect.stack()[0][3] msg = f"{self.class_name}.{method_name}: entered" @@ -1099,13 +1252,19 @@ def commit(self): def send_need(self) -> None: """ - ### Summary + # Summary + Build and send the payload to modify maintenance mode. - ### Raises - - ``ValueError`` if MaintenanceMode() raises either - ``TypeError`` or ``ValueError`` + ## Raises + + ### ValueError + + - MaintenanceMode() raises `ValueError` + + ### TypeError + - MaintenanceMode() raises `TypeError` """ method_name = inspect.stack()[0][3] # pylint: disable=unused-variable @@ -1126,18 +1285,38 @@ def send_need(self) -> None: class Query(Common): """ + # Summary + Handle query state - ### Raises - - ``ValueError`` if Common().__init__() raises ``ValueError`` - - ``ValueError`` if get_want() raises ``ValueError`` - - ``ValueError`` if get_have() raises ``ValueError`` + ## Raises + + ### ValueError + + - Common().__init__() raises `ValueError` + - get_want() raises `ValueError` + - get_have() raises `ValueError` + + ### TypeError + + - Common().__init__() raises `TypeError` """ def __init__(self, params): """ - ### Raises - - ``ValueError`` if Common().__init__() raises ``ValueError`` + # Summary + + Initialize Query instance + + ## Raises + + ### ValueError + + - Common().__init__() raises `ValueError` + + ### TypeError + + - Common().__init__() raises `TypeError` """ self.class_name = self.__class__.__name__ method_name = inspect.stack()[0][3] @@ -1160,48 +1339,58 @@ def __init__(self, params): def get_have(self): """ - ### Summary + # Summary + Build self.have, a dict containing the current mode of all switches. - ### Raises - - ``ValueError`` if MaintenanceModeInfo() raises ``ValueError`` + ## Raises + + ### ValueError + + - MaintenanceModeInfo() raises `ValueError` + + ### TypeError + + - MaintenanceModeInfo() raises `TypeError` + + ## self.have structure - ### self.have structure Have is a dict, keyed on switch_ip, where each element is a dict with the following structure: - - ``fabric_name``: The name of the switch's hosting fabric. - - ``fabric_freeze_mode``: The current ``freezeMode`` state of the switch's - hosting fabric. If ``freeze_mode`` is True, configuration changes cannot - be made to the fabric or the switches within the fabric. - - ``fabric_read_only``: The current ``IS_READ_ONLY`` state of the switch's - hosting fabric. If ``fabric_read_only`` is True, configuration changes cannot - be made to the fabric or the switches within the fabric. - - ``mode``: The current maintenance mode of the switch. - Possible values include: , ``inconsistent``, ``maintenance``, - ``migration``, ``normal``. - - ``role``: The role of the switch in the hosting fabric, e.g. - ``spine``, ``leaf``, ``border_gateway``, etc. - - ``serial_number``: The serial number of the switch. + + - `fabric_name`: The name of the switch's hosting fabric. + - `fabric_freeze_mode`: The current `freezeMode` state of the switch's + hosting fabric. If `freeze_mode` is True, configuration changes cannot + be made to the fabric or the switches within the fabric. + - `fabric_read_only`: The current `IS_READ_ONLY` state of the switch's + hosting fabric. If `fabric_read_only` is True, configuration changes cannot + be made to the fabric or the switches within the fabric. + - `mode`: The current maintenance mode of the switch. + Possible values include: , `inconsistent`, `maintenance`, + `migration`, `normal`. + - `role`: The role of the switch in the hosting fabric, e.g. + `spine`, `leaf`, `border_gateway`, etc. + - `serial_number`: The serial number of the switch. ```json { "192.169.1.2": { - fabric_deployment_disabled: true - fabric_freeze_mode: true, - fabric_name: "MyFabric", - fabric_read_only: true - mode: "maintenance", - role: "spine", - serial_number: "FCI1234567" + "fabric_deployment_disabled": true, + "fabric_freeze_mode": true, + "fabric_name": "MyFabric", + "fabric_read_only": true, + "mode": "maintenance", + "role": "spine", + "serial_number": "FCI1234567" }, "192.169.1.3": { - fabric_deployment_disabled: false - fabric_freeze_mode: false, - fabric_name: "YourFabric", - fabric_read_only: false - mode: "normal", - role: "leaf", - serial_number: "FCH2345678" + "fabric_deployment_disabled": false, + "fabric_freeze_mode": false, + "fabric_name": "YourFabric", + "fabric_read_only": false, + "mode": "normal", + "role": "leaf", + "serial_number": "FCH2345678" } } ``` @@ -1222,15 +1411,18 @@ def get_have(self): def commit(self) -> None: """ - ### Summary + # Summary + Query the switches in self.want that exist on the controller and update ``self.results`` with the query results. - ### Raises - - ``ValueError`` if: - - ``rest_send`` is not set. - - ``get_want()`` raises ``ValueError`` - - ``get_have()`` raises ``ValueError`` + ## Raises + + ### ValueError + + - `rest_send` is not set + - `get_want()` raises `ValueError` + - `get_have()` raises `ValueError` """ method_name = inspect.stack()[0][3] msg = f"{self.class_name}.{method_name}: entered" diff --git a/tests/unit/module_utils/common/test_maintenance_mode.py b/tests/unit/module_utils/common/test_maintenance_mode.py index c18cd0793..c6ae65ee0 100644 --- a/tests/unit/module_utils/common/test_maintenance_mode.py +++ b/tests/unit/module_utils/common/test_maintenance_mode.py @@ -34,24 +34,24 @@ import pytest from ansible_collections.cisco.dcnm.plugins.module_utils.common.api.v1.lan_fabric.rest.control.fabrics.fabrics import ( - EpMaintenanceModeDisable, EpMaintenanceModeEnable) -from ansible_collections.cisco.dcnm.plugins.module_utils.common.conversion import \ - ConversionUtils -from ansible_collections.cisco.dcnm.plugins.module_utils.common.exceptions import \ - ControllerResponseError -from ansible_collections.cisco.dcnm.plugins.module_utils.common.maintenance_mode import \ - MaintenanceMode -from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import \ - ResponseHandler -from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import \ - RestSend -from ansible_collections.cisco.dcnm.plugins.module_utils.common.results import \ - Results -from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import \ - Sender + EpMaintenanceModeDisable, + EpMaintenanceModeEnable, +) +from ansible_collections.cisco.dcnm.plugins.module_utils.common.conversion import ConversionUtils +from ansible_collections.cisco.dcnm.plugins.module_utils.common.exceptions import ControllerResponseError +from ansible_collections.cisco.dcnm.plugins.module_utils.common.maintenance_mode import MaintenanceMode +from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import ResponseHandler +from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import RestSend +from ansible_collections.cisco.dcnm.plugins.module_utils.common.results import Results +from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import Sender from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import ( - ResponseGenerator, does_not_raise, maintenance_mode_fixture, params, - responses_deploy_maintenance_mode, responses_maintenance_mode) + ResponseGenerator, + does_not_raise, + maintenance_mode_fixture, + params, + responses_deploy_maintenance_mode, + responses_maintenance_mode, +) FABRIC_NAME = "VXLAN_Fabric" CONFIG = [ @@ -68,11 +68,16 @@ def test_maintenance_mode_00000(maintenance_mode) -> None: """ - Classes and Methods - - MaintenanceMode - - __init__() + # Summary + + Verify MaintenanceMode class attributes are initialized to expected values. + + ## Classes and Methods + + - MaintenanceMode.__init__() + + ## Test - Test - Class attributes are initialized to expected values - Exception is not raised """ @@ -101,12 +106,17 @@ def test_maintenance_mode_00000(maintenance_mode) -> None: def test_maintenance_mode_00010() -> None: """ - Classes and Methods - - MaintenanceMode - - __init__() + # Summary + + Verify `ValueError` is raised when params is missing check_mode key. - Test - - ``ValueError`` is raised when params is missing check_mode key. + ## Classes and Methods + + - MaintenanceMode.__init__() + + ## Test + + - `ValueError` is raised when params is missing check_mode key """ params = {"state": "merged"} match = r"MaintenanceMode\.__init__:\s+" @@ -117,12 +127,17 @@ def test_maintenance_mode_00010() -> None: def test_maintenance_mode_00020() -> None: """ - Classes and Methods - - MaintenanceMode - - __init__() + # Summary + + Verify `ValueError` is raised when params is missing state key. + + ## Classes and Methods + + - MaintenanceMode.__init__() - Test - - ``ValueError`` is raised when params is missing state key. + ## Test + + - `ValueError` is raised when params is missing state key """ params = {"check_mode": False} match = r"MaintenanceMode\.__init__:\s+" @@ -133,27 +148,29 @@ def test_maintenance_mode_00020() -> None: def test_maintenance_mode_00030(maintenance_mode) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_commit_parameters() - - commit() - - Summary - - Verify MaintenanceMode().commit() raises ``ValueError`` when - ``config`` is not set. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Other required attributes are set - - Code Flow - Test - - ``MaintenanceMode().commit()`` is called without having first set - ``MaintenanceMode().config`` - - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + # Summary + + Verify MaintenanceMode().commit() raises `ValueError` when `config` is not set. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_commit_parameters() + - MaintenanceMode.commit() + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Other required attributes are set + + ## Code Flow - Test + + - MaintenanceMode().commit() is called without having first set MaintenanceMode().config + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ with does_not_raise(): instance = maintenance_mode @@ -169,27 +186,29 @@ def test_maintenance_mode_00030(maintenance_mode) -> None: def test_maintenance_mode_00040(maintenance_mode) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_commit_parameters() - - commit() - - Summary - - Verify MaintenanceMode().commit() raises ``ValueError`` - when ``rest_send`` is not set. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Other required attributes are set - - Code Flow - Test - - MaintenanceMode().commit() is called without having - first set MaintenanceMode().rest_send - - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + # Summary + + Verify MaintenanceMode().commit() raises `ValueError` when `rest_send` is not set. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_commit_parameters() + - MaintenanceMode.commit() + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Other required attributes are set + + ## Code Flow - Test + + - MaintenanceMode().commit() is called without having first set MaintenanceMode().rest_send + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ with does_not_raise(): instance = maintenance_mode @@ -205,27 +224,29 @@ def test_maintenance_mode_00040(maintenance_mode) -> None: def test_maintenance_mode_00050(maintenance_mode) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_commit_parameters() - - commit() - - Summary - - Verify MaintenanceMode().commit() raises ``ValueError`` - when ``MaintenanceMode().results`` is not set. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Other required attributes are set - - Code Flow - Test - - MaintenanceMode().commit() is called without having - first set MaintenanceMode().results - - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + # Summary + + Verify MaintenanceMode().commit() raises `ValueError` when `results` is not set. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_commit_parameters() + - MaintenanceMode.commit() + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Other required attributes are set + + ## Code Flow - Test + + - MaintenanceMode().commit() is called without having first set MaintenanceMode().results + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ with does_not_raise(): instance = maintenance_mode @@ -247,34 +268,39 @@ def test_maintenance_mode_00050(maintenance_mode) -> None: (ValueError, ValueError, "Bad value"), ], ) -def test_maintenance_mode_00200( - monkeypatch, maintenance_mode, mock_exception, expected_exception, mock_message -) -> None: +def test_maintenance_mode_00200(monkeypatch, maintenance_mode, mock_exception, expected_exception, mock_message) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() - - Summary - - Verify MaintenanceMode().commit() raises ``ValueError`` when - ``MaintenanceMode().change_system_mode`` raises any of: - - ``ControllerResponseError`` - - ``TypeError`` - - ``ValueError`` - - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Required attributes are set - - change_system_mode() is mocked to raise each of the above exceptions - - Code Flow - Test - - MaintenanceMode().commit() is called for each exception - - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + # Summary + + Verify MaintenanceMode().commit() raises `ValueError` when change_system_mode raises exceptions. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.commit() + + ## Test + + Verify MaintenanceMode().commit() raises `ValueError` when MaintenanceMode().change_system_mode raises any of: + + - `ControllerResponseError` + - `TypeError` + - `ValueError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Required attributes are set + - change_system_mode() is mocked to raise each of the above exceptions + + ## Code Flow - Test + + - MaintenanceMode().commit() is called for each exception + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ def mock_change_system_mode(*args, **kwargs): @@ -298,34 +324,39 @@ def mock_change_system_mode(*args, **kwargs): (ValueError, ValueError, "Bad value"), ], ) -def test_maintenance_mode_00210( - monkeypatch, maintenance_mode, mock_exception, expected_exception, mock_message -) -> None: +def test_maintenance_mode_00210(monkeypatch, maintenance_mode, mock_exception, expected_exception, mock_message) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() - - Summary - - Verify MaintenanceMode().commit() raises ``ValueError`` when - ``MaintenanceMode().deploy_switches`` raises any of: - - ``ControllerResponseError`` - - ``ValueError`` - - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Required attributes are set - - change_system_mode() is mocked to do nothing - - deploy_switches() is mocked to raise each of the above exceptions - - Code Flow - Test - - MaintenanceMode().commit() is called for each exception - - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + # Summary + + Verify MaintenanceMode().commit() raises `ValueError` when deploy_switches raises exceptions. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.commit() + + ## Test + + Verify MaintenanceMode().commit() raises `ValueError` when MaintenanceMode().deploy_switches raises any of: + + - `ControllerResponseError` + - `ValueError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Required attributes are set + - change_system_mode() is mocked to do nothing + - deploy_switches() is mocked to raise each of the above exceptions + + ## Code Flow - Test + + - MaintenanceMode().commit() is called for each exception + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ def mock_change_system_mode(*args, **kwargs): @@ -357,34 +388,41 @@ def mock_deploy_switches(*args, **kwargs): ) def test_maintenance_mode_00220(maintenance_mode, mode, deploy) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() - - change_system_mode() - - deploy_switches() - - Summary - - Verify commit() success case: - - RETURN_CODE is 200. - - Controller response contains expected structure and values. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Sender() is mocked to return expected responses - - Required attributes are set - - MaintenanceMode().commit() is called - - responses_MaintenanceMode contains a dict with: - - RETURN_CODE == 200 - - DATA == {"status": "Success"} - - Code Flow - Test - - MaintenanceMode().commit() is called - - Expected Result - - Exception is not raised - - instance.response_data returns expected data - - MaintenanceMode()._properties are updated + # Summary + + Verify commit() success case with RETURN_CODE 200. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.commit() + - MaintenanceMode.change_system_mode() + - MaintenanceMode.deploy_switches() + + ## Test + + - RETURN_CODE is 200 + - Controller response contains expected structure and values + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Sender() is mocked to return expected responses + - Required attributes are set + - MaintenanceMode().commit() is called + - responses_MaintenanceMode contains a dict with: + - RETURN_CODE == 200 + - DATA == {"status": "Success"} + + ## Code Flow - Test + + - MaintenanceMode().commit() is called + + ## Expected Result + + - Exception is not raised + - instance.response_data returns expected data + - MaintenanceMode()._properties are updated """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -438,10 +476,7 @@ def responses(): assert instance.results.diff[1].get("deploy_maintenance_mode", None) is True assert instance.results.diff[1].get("sequence_number", None) == 2 - assert ( - instance.results.metadata[1].get("action", None) - == "deploy_maintenance_mode" - ) + assert instance.results.metadata[1].get("action", None) == "deploy_maintenance_mode" assert instance.results.metadata[1].get("sequence_number", None) == 2 assert instance.results.metadata[1].get("state", None) == "merged" @@ -464,38 +499,44 @@ def responses(): ) def test_maintenance_mode_00230(maintenance_mode, mode) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() - - change_system_mode() - - deploy_switches() - - Summary - - Verify commit() unsuccessful case: - - RETURN_CODE == 500. - - commit raises ``ValueError`` when change_system_mode() raises - ``ControllerResponseError``. - - Controller response contains expected structure and values. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Sender() is mocked to return expected responses - - Required attributes are set - - MaintenanceMode().commit() is called - - responses_MaintenanceMode contains a dict with: - - RETURN_CODE == 500 - - DATA == {"status": "Failure"} - - Code Flow - Test - - ``MaintenanceMode().commit()`` is called - - ``change_system_mode()`` raises ``ControllerResponseError`` - - ``commit()`` raises ``ValueError`` - - Expected Result - - ``commit()`` raises ``ValueError`` - - instance.response_data returns expected data - - MaintenanceMode()._properties are updated + # Summary + + Verify commit() unsuccessful case with RETURN_CODE 500. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.commit() + - MaintenanceMode.change_system_mode() + - MaintenanceMode.deploy_switches() + + ## Test + + - RETURN_CODE == 500 + - commit raises `ValueError` when change_system_mode() raises `ControllerResponseError` + - Controller response contains expected structure and values + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Sender() is mocked to return expected responses + - Required attributes are set + - MaintenanceMode().commit() is called + - responses_MaintenanceMode contains a dict with: + - RETURN_CODE == 500 + - DATA == {"status": "Failure"} + + ## Code Flow - Test + + - MaintenanceMode().commit() is called + - change_system_mode() raises `ControllerResponseError` + - commit() raises `ValueError` + + ## Expected Result + + - commit() raises `ValueError` + - instance.response_data returns expected data + - MaintenanceMode()._properties are updated """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -550,30 +591,35 @@ def responses(): def test_maintenance_mode_00300(maintenance_mode) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_config_parameters() - - config.setter - - Summary - - Verify MaintenanceMode().verify_config_parameters() raises - - ``TypeError`` if: - - value is not a list - - Verify MaintenanceMode().config.setter re-raises: - - ``TypeError`` as ``ValueError`` - - Code Flow - Setup - - MaintenanceMode() is instantiated - - config is set to a non-list value - - Code Flow - Test - - MaintenanceMode().config.setter is accessed with non-list - - Expected Result - - verify_config_parameters() raises ``TypeError``. - - config.setter re-raises as ``ValueError``. - - Exception message matches expected. + # Summary + + Verify MaintenanceMode().verify_config_parameters() raises `TypeError` if value is not a list. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_config_parameters() + - MaintenanceMode.config.setter + + ## Test + + - Verify MaintenanceMode().verify_config_parameters() raises `TypeError` if value is not a list + - Verify MaintenanceMode().config.setter re-raises `TypeError` as `ValueError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - config is set to a non-list value + + ## Code Flow - Test + + - MaintenanceMode().config.setter is accessed with non-list + + ## Expected Result + + - verify_config_parameters() raises `TypeError` + - config.setter re-raises as `ValueError` + - Exception message matches expected """ with does_not_raise(): instance = maintenance_mode @@ -597,33 +643,39 @@ def test_maintenance_mode_00300(maintenance_mode) -> None: ) def test_maintenance_mode_00310(maintenance_mode, remove_param) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_config_parameters() - - config.setter - - Summary - - Verify MaintenanceMode().verify_config_parameters() raises - - ``ValueError`` if: - - deploy is missing from config - - fabric_name is missing from config - - ip_address is missing from config - - mode is missing from config - - serial_number is missing from config - - wait_for_mode_change is missing from config - - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Code Flow - Test - - MaintenanceMode().config is set to a dict with all of the above - keys present, except that each key, in turn, is removed. - - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + # Summary + + Verify MaintenanceMode().verify_config_parameters() raises `ValueError` for missing config keys. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_config_parameters() + - MaintenanceMode.config.setter + + ## Test + + Verify MaintenanceMode().verify_config_parameters() raises `ValueError` if: + + - deploy is missing from config + - fabric_name is missing from config + - ip_address is missing from config + - mode is missing from config + - serial_number is missing from config + - wait_for_mode_change is missing from config + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + + ## Code Flow - Test + + - MaintenanceMode().config is set to a dict with all of the above keys present, except that each key, in turn, is removed + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ with does_not_raise(): @@ -650,29 +702,34 @@ def test_maintenance_mode_00310(maintenance_mode, remove_param) -> None: ) def test_maintenance_mode_00400(maintenance_mode, param, raises) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_config_parameters() - - config.setter - - Summary - - Verify MaintenanceMode().verify_config_parameters() re-raises - - ``ValueError`` if: - - ``deploy`` raises ``TypeError`` - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Code Flow - Test - - MaintenanceMode().config is set to a dict. - - The dict is updated with deploy set to valid and invalid - values of ``deploy`` - - Expected Result - - ``ValueError`` is raised when deploy is not a boolean - - Exception message matches expected - - Exception is not raised when deploy is a boolean + # Summary + + Verify MaintenanceMode().verify_config_parameters() validates deploy parameter type. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_config_parameters() + - MaintenanceMode.config.setter + + ## Test + + - Verify MaintenanceMode().verify_config_parameters() re-raises `ValueError` if `deploy` raises `TypeError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + + ## Code Flow - Test + + - MaintenanceMode().config is set to a dict + - The dict is updated with deploy set to valid and invalid values of `deploy` + + ## Expected Result + + - `ValueError` is raised when deploy is not a boolean + - Exception message matches expected + - Exception is not raised when deploy is a boolean """ with does_not_raise(): @@ -703,30 +760,34 @@ def test_maintenance_mode_00400(maintenance_mode, param, raises) -> None: ) def test_maintenance_mode_00500(maintenance_mode, param, raises) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_config_parameters() - - config.setter - - Summary - - Verify MaintenanceMode().verify_config_parameters() re-raises - - ``ValueError`` if: - - ``fabric_name`` raises ``ValueError`` due to being an - invalid value. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Code Flow - Test - - MaintenanceMode().config is set to a dict. - - The dict is updated with fabric_name set to valid and invalid - values of ``fabric_name`` - - Expected Result - - ``ValueError`` is raised when fabric_name is not a valid value - - Exception message matches expected - - Exception is not raised when fabric_name is a valid value + # Summary + + Verify MaintenanceMode().verify_config_parameters() validates fabric_name parameter. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_config_parameters() + - MaintenanceMode.config.setter + + ## Test + + - Verify MaintenanceMode().verify_config_parameters() re-raises `ValueError` if `fabric_name` raises `ValueError` due to being an invalid value + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + + ## Code Flow - Test + + - MaintenanceMode().config is set to a dict + - The dict is updated with fabric_name set to valid and invalid values of `fabric_name` + + ## Expected Result + + - `ValueError` is raised when fabric_name is not a valid value + - Exception message matches expected + - Exception is not raised when fabric_name is a valid value """ with does_not_raise(): @@ -758,30 +819,34 @@ def test_maintenance_mode_00500(maintenance_mode, param, raises) -> None: ) def test_maintenance_mode_00600(maintenance_mode, param, raises) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_config_parameters() - - config.setter - - Summary - - Verify MaintenanceMode().verify_config_parameters() re-raises - - ``ValueError`` if: - - ``mode`` raises ``ValueError`` due to being an - invalid value. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Code Flow - Test - - MaintenanceMode().config is set to a dict. - - The dict is updated with mode set to valid and invalid - values of ``mode`` - - Expected Result - - ``ValueError`` is raised when mode is not a valid value - - Exception message matches expected - - Exception is not raised when mode is a valid value + # Summary + + Verify MaintenanceMode().verify_config_parameters() validates mode parameter. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_config_parameters() + - MaintenanceMode.config.setter + + ## Test + + - Verify MaintenanceMode().verify_config_parameters() re-raises `ValueError` if `mode` raises `ValueError` due to being an invalid value + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + + ## Code Flow - Test + + - MaintenanceMode().config is set to a dict + - The dict is updated with mode set to valid and invalid values of `mode` + + ## Expected Result + + - `ValueError` is raised when mode is not a valid value + - Exception message matches expected + - Exception is not raised when mode is a valid value """ with does_not_raise(): @@ -812,29 +877,34 @@ def test_maintenance_mode_00600(maintenance_mode, param, raises) -> None: ) def test_maintenance_mode_00700(maintenance_mode, param, raises) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - verify_config_parameters() - - config.setter - - Summary - - Verify MaintenanceMode().verify_config_parameters() re-raises - - ``ValueError`` if: - - ``wait_for_mode_change`` raises ``TypeError`` - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Code Flow - Test - - MaintenanceMode().config is set to a dict. - - The dict is updated with wait_for_mode_change set to valid and invalid - values of ``wait_for_mode_change`` - - Expected Result - - ``ValueError`` is raised when wait_for_mode_change is not a boolean - - Exception message matches expected - - Exception is not raised when wait_for_mode_change is a boolean + # Summary + + Verify MaintenanceMode().verify_config_parameters() validates wait_for_mode_change parameter type. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.verify_config_parameters() + - MaintenanceMode.config.setter + + ## Test + + - Verify MaintenanceMode().verify_config_parameters() re-raises `ValueError` if `wait_for_mode_change` raises `TypeError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + + ## Code Flow - Test + + - MaintenanceMode().config is set to a dict + - The dict is updated with wait_for_mode_change set to valid and invalid values of `wait_for_mode_change` + + ## Expected Result + + - `ValueError` is raised when wait_for_mode_change is not a boolean + - Exception message matches expected + - Exception is not raised when wait_for_mode_change is a boolean """ with does_not_raise(): @@ -871,32 +941,37 @@ def test_maintenance_mode_00800( mock_message, ) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() - - Summary - - Verify MaintenanceMode().change_system_mode() raises ``ValueError`` - when ``EpMaintenanceModeEnable`` or ``EpMaintenanceModeDisable`` raise - any of: - - ``TypeError`` - - ``ValueError`` - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Required attributes are set - - EpMaintenanceModeEnable() is mocked to raise each - of the above exceptions - - EpMaintenanceModeDisable() is mocked to raise each - of the above exceptions - - Code Flow - Test - - MaintenanceMode().commit() is called for each exception - - Expected Result - - ``ValueError`` is raised. - - Exception message matches expected. + # Summary + + Verify MaintenanceMode().change_system_mode() raises `ValueError` when endpoint classes raise exceptions. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.commit() + + ## Test + + Verify MaintenanceMode().change_system_mode() raises `ValueError` when `EpMaintenanceModeEnable` or `EpMaintenanceModeDisable` raise any of: + + - `TypeError` + - `ValueError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Required attributes are set + - EpMaintenanceModeEnable() is mocked to raise each of the above exceptions + - EpMaintenanceModeDisable() is mocked to raise each of the above exceptions + + ## Code Flow - Test + + - MaintenanceMode().commit() is called for each exception + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ class MockEndpoint: @@ -960,29 +1035,36 @@ def test_maintenance_mode_00900( mock_message, ) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() + # Summary + + Verify MaintenanceMode().deploy_switches() raises `ValueError` when EpMaintenanceModeDeploy raises exceptions. - Summary - - Verify MaintenanceMode().deploy_switches() raises ``ValueError`` - when ``EpMaintenanceModeDeploy`` raises any of: - - ``TypeError`` - - ``ValueError`` + ## Classes and Methods + - MaintenanceMode.__init__() + - MaintenanceMode.commit() - Code Flow - Setup - - MaintenanceMode() is instantiated - - Required attributes are set - - EpMaintenanceModeDeploy() is mocked to raise each of the above exceptions + ## Test - Code Flow - Test - - MaintenanceMode().commit() is called for each exception + Verify MaintenanceMode().deploy_switches() raises `ValueError` when `EpMaintenanceModeDeploy` raises any of: - Expected Result - - ``TypeError`` and ``ValueError`` are raised. - - Exception message matches expected. + - `TypeError` + - `ValueError` + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Required attributes are set + - EpMaintenanceModeDeploy() is mocked to raise each of the above exceptions + + ## Code Flow - Test + + - MaintenanceMode().commit() is called for each exception + + ## Expected Result + + - `TypeError` and `ValueError` are raised + - Exception message matches expected """ class MockEndpoint: @@ -1063,35 +1145,38 @@ def responses(): (ValueError, ValueError, r"Converted ValueError to ValueError"), ], ) -def test_maintenance_mode_01000( - maintenance_mode, mock_exception, expected_exception, mock_message -) -> None: +def test_maintenance_mode_01000(maintenance_mode, mock_exception, expected_exception, mock_message) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - change_system_mode() + # Summary + + Verify MaintenanceMode().change_system_mode() raises `ValueError` when Results() raises exceptions. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.change_system_mode() + + ## Test + + Verify MaintenanceMode().change_system_mode() raises `ValueError` when MaintenanceMode().results() raises any of: + - `TypeError` + - `ValueError` - Summary - - Verify MaintenanceMode().change_system_mode() raises ``ValueError`` - when ``MaintenanceMode().results()`` raises any of: - - ``TypeError`` - - ``ValueError`` + ## Code Flow - Setup + - MaintenanceMode() is instantiated + - Required attributes are set + - Results().response_current.setter is mocked to raise each of the above exceptions - Code Flow - Setup - - MaintenanceMode() is instantiated - - Required attributes are set - - Results().response_current.setter is mocked to raise each of the above - exceptions + ## Code Flow - Test - Code Flow - Test - - MaintenanceMode().commit() is called for each exception + - MaintenanceMode().commit() is called for each exception - Expected Result - - ``ValueError`` is raised - - Exception message matches expected + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ class MockResults: @@ -1139,29 +1224,34 @@ def responses(): def test_maintenance_mode_01100(monkeypatch, maintenance_mode) -> None: """ - Classes and Methods - - MaintenanceMode() - - __init__() - - commit() - - Summary - - Verify MaintenanceMode().commit() raises ``ValueError`` when - ``MaintenanceMode().deploy_switches()`` raises - ``ControllerResponseError`` when the RETURN_CODE in the - response is not 200. - - Code Flow - Setup - - MaintenanceMode() is instantiated - - Required attributes are set - - Code Flow - Test - - MaintenanceMode().commit() is called with simulated responses: - - 200 response for ``change_system_mode()`` - - 500 response ``deploy_switches()`` - - Expected Result - - ``ValueError``is raised. - - Exception message matches expected. + # Summary + + Verify MaintenanceMode().commit() raises `ValueError` when deploy_switches() gets non-200 response. + + ## Classes and Methods + + - MaintenanceMode.__init__() + - MaintenanceMode.commit() + + ## Test + + - Verify MaintenanceMode().commit() raises `ValueError` when MaintenanceMode().deploy_switches() raises `ControllerResponseError` when the RETURN_CODE in the response is not 200 + + ## Code Flow - Setup + + - MaintenanceMode() is instantiated + - Required attributes are set + + ## Code Flow - Test + + - MaintenanceMode().commit() is called with simulated responses: + - 200 response for `change_system_mode()` + - 500 response `deploy_switches()` + + ## Expected Result + + - `ValueError` is raised + - Exception message matches expected """ def responses(): diff --git a/tests/unit/module_utils/common/test_maintenance_mode_info.py b/tests/unit/module_utils/common/test_maintenance_mode_info.py index 6d20cc9f3..93ce78cdd 100644 --- a/tests/unit/module_utils/common/test_maintenance_mode_info.py +++ b/tests/unit/module_utils/common/test_maintenance_mode_info.py @@ -32,27 +32,22 @@ import inspect import pytest -from ansible_collections.cisco.dcnm.plugins.module_utils.common.conversion import \ - ConversionUtils -from ansible_collections.cisco.dcnm.plugins.module_utils.common.exceptions import \ - ControllerResponseError -from ansible_collections.cisco.dcnm.plugins.module_utils.common.maintenance_mode_info import \ - MaintenanceModeInfo -from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import \ - ResponseHandler -from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import \ - RestSend -from ansible_collections.cisco.dcnm.plugins.module_utils.common.results import \ - Results -from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import \ - Sender -from ansible_collections.cisco.dcnm.tests.unit.mocks.mock_fabric_details_by_name import \ - MockFabricDetailsByName -from ansible_collections.cisco.dcnm.tests.unit.mocks.mock_switch_details import \ - MockSwitchDetails +from ansible_collections.cisco.dcnm.plugins.module_utils.common.conversion import ConversionUtils +from ansible_collections.cisco.dcnm.plugins.module_utils.common.exceptions import ControllerResponseError +from ansible_collections.cisco.dcnm.plugins.module_utils.common.maintenance_mode_info import MaintenanceModeInfo +from ansible_collections.cisco.dcnm.plugins.module_utils.common.response_handler import ResponseHandler +from ansible_collections.cisco.dcnm.plugins.module_utils.common.rest_send_v2 import RestSend +from ansible_collections.cisco.dcnm.plugins.module_utils.common.results import Results +from ansible_collections.cisco.dcnm.plugins.module_utils.common.sender_file import Sender +from ansible_collections.cisco.dcnm.tests.unit.mocks.mock_fabric_details_by_name import MockFabricDetailsByName +from ansible_collections.cisco.dcnm.tests.unit.mocks.mock_switch_details import MockSwitchDetails from ansible_collections.cisco.dcnm.tests.unit.module_utils.common.common_utils import ( - ResponseGenerator, does_not_raise, maintenance_mode_info_fixture, - responses_fabric_details_by_name, responses_switch_details) + ResponseGenerator, + does_not_raise, + maintenance_mode_info_fixture, + responses_fabric_details_by_name, + responses_switch_details, +) FABRIC_NAME = "VXLAN_Fabric" CONFIG = ["192.168.1.2"] @@ -61,25 +56,35 @@ def test_maintenance_mode_info_00000(maintenance_mode_info) -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``__init__()`` + # Summary + + Verify the `__init__()` method. + + ## Classes and Methods + + - MaintenanceModeInfo.__init__() + + ## Test + + - Class attributes are initialized to expected values. + - Exception is not raised. + + ## Setup - Data + + - None + + ## Setup - Code - ### Summary - - Verify the __init__() method. + - None - ### Setup - Data - - None + ## Trigger - ### Setup - Code - - None + - `MaintenanceModeInfo` is instantiated. - ### Trigger - - ``MaintenanceModeInfo`` is instantiated. + ## Expected Result - ### Expected Result - - Class attributes are initialized to expected values. - - Exception is not raised. + - Class attributes are initialized to expected values. + - Exception is not raised. """ with does_not_raise(): @@ -100,28 +105,39 @@ def test_maintenance_mode_info_00000(maintenance_mode_info) -> None: def test_maintenance_mode_info_00100(maintenance_mode_info) -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``verify_refresh_parameters()`` - - ``refresh()`` + # Summary + + Verify `MaintenanceModeInfo().refresh()` raises `ValueError` when + `config` is not set. + + ## Classes and Methods + + - MaintenanceModeInfo.verify_refresh_parameters() + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - None + + ## Setup - Code - ### Summary - - Verify MaintenanceModeInfo().refresh() raises ``ValueError`` when - ``config`` is not set. + - `MaintenanceModeInfo()` is instantiated. + - Other required attributes are set. - ### Setup - Data - - None + ## Trigger - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated. - - Other required attributes are set. + - `refresh()` is called without having first set `config`. - ### Trigger - - ``refresh()`` is called without having first set ``config``. + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. """ with does_not_raise(): instance = maintenance_mode_info @@ -137,28 +153,38 @@ def test_maintenance_mode_info_00100(maintenance_mode_info) -> None: def test_maintenance_mode_info_00110(maintenance_mode_info) -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``verify_refresh_parameters()`` - - ``refresh()`` + # Summary + + Verify `refresh()` raises `ValueError` when `rest_send` is not set. + + ## Classes and Methods + + - MaintenanceModeInfo.verify_refresh_parameters() + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - None - ### Summary - - Verify ``refresh()`` raises ``ValueError`` when ``rest_send`` - is not set. + ## Setup - Code - ### Setup - Data - - None + - `MaintenanceModeInfo()` is instantiated. + - Other required attributes are set. - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated. - - Other required attributes are set. + ## Trigger - ### Trigger - - ``refresh()`` is called without having first set ``rest_send``. + - `refresh()` is called without having first set `rest_send`. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. """ with does_not_raise(): instance = maintenance_mode_info @@ -174,27 +200,38 @@ def test_maintenance_mode_info_00110(maintenance_mode_info) -> None: def test_maintenance_mode_info_00120(maintenance_mode_info) -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``verify_refresh_parameters()`` - - ``refresh()`` + # Summary + + Verify `refresh()` raises `ValueError` when `results` is not set. + + ## Classes and Methods + + - MaintenanceModeInfo.verify_refresh_parameters() + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data - ### Summary - - Verify ``refresh()`` raises ``ValueError`` when ``results`` is not set. + - None - ### Setup - Data - - None + ## Setup - Code - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated. - - Other required attributes are set. + - `MaintenanceModeInfo()` is instantiated. + - Other required attributes are set. - ### Trigger - - ``refresh()`` is called without having first set ``results``. + ## Trigger + + - `refresh()` is called without having first set `results`. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. """ with does_not_raise(): instance = maintenance_mode_info @@ -264,32 +301,41 @@ def test_maintenance_mode_info_00200( mock_message, ) -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``refresh()`` - - ### Summary - - Verify ``refresh()`` raises ``ValueError`` when: - - ``fabric_details`` properties ``rest_send`` and ``results`` - raise ``TypeError``. - - ``switch_details`` properties ``rest_send`` and ``results`` - raise ``TypeError``. - - ### Setup - Data - - None - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ``FabricDetails()`` is mocked to conditionally raise ``TypeError``. - - ``SwitchDetails()`` is mocked to conditionally raise ``TypeError``. - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. + # Summary + + Verify `refresh()` raises `ValueError` when: + - `fabric_details` properties `rest_send` and `results` raise `TypeError`. + - `switch_details` properties `rest_send` and `results` raise `TypeError`. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - None + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + - `FabricDetails()` is mocked to conditionally raise `TypeError`. + - `SwitchDetails()` is mocked to conditionally raise `TypeError`. + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -351,31 +397,42 @@ def test_maintenance_mode_info_00210( mock_message, ) -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - ### Summary - - Verify ``refresh()`` raises ``ValueError`` when - ``switch_details.serial_number`` raises ``ValueError``. - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ``SwitchDetails()`` is mocked to conditionally raise - ``ValueError`` in the ``serial_number.getter`` property. - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. + # Summary + + Verify `refresh()` raises `ValueError` when + `switch_details.serial_number` raises `ValueError`. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + - `SwitchDetails()` is mocked to conditionally raise + `ValueError` in the `serial_number.getter` property. + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -411,43 +468,54 @@ def responses(): def test_maintenance_mode_info_00300() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - __init__() - - refresh() + # Summary - ### Summary - Verify ``refresh()`` raises ``ValueError`` when - ``switch_details._get()`` raises ``ValueError``. + Verify `refresh()` raises `ValueError` when + `switch_details._get()` raises `ValueError`. This happens when the switch is not found in the response from the controller. - ### Setup - Data - - ``ipAddress`` is set to something other than 192.168.1.2 - - ``responses_SwitchDetails.json``: - - "DATA[0].fabricName: VXLAN_Fabric", - - "DATA[0].freezeMode: null", - - "DATA[0].ipAddress: 192.168.1.1", - - "DATA[0].mode: Normal", - - "DATA[0].serialNumber: FDO211218FV", - - "DATA[0].switchRole: leaf", - - "DATA[0].systemMode: Normal" - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. + ## Classes and Methods + + - MaintenanceModeInfo.__init__() + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - `ipAddress` is set to something other than 192.168.1.2 + - `responses_SwitchDetails.json`: + - "DATA[0].fabricName: VXLAN_Fabric", + - "DATA[0].freezeMode: null", + - "DATA[0].ipAddress: 192.168.1.1", + - "DATA[0].mode: Normal", + - "DATA[0].serialNumber: FDO211218FV", + - "DATA[0].switchRole: leaf", + - "DATA[0].systemMode: Normal" + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -477,45 +545,56 @@ def responses(): def test_maintenance_mode_info_00310() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - __init__() - - refresh() + # Summary - ### Summary - Verify ``refresh()`` raises ``ValueError`` when - ``switch_details.serial_number`` is ``None``. + Verify `refresh()` raises `ValueError` when + `switch_details.serial_number` is `None`. This happens when the switch exists on the controller but its serial_number is null. This is a negative test case since we expect the serial_number to be set. - ### Setup - Data - - ``ipAddress`` is set to something other than 192.168.1.2 - - ``responses_SwitchDetails.json``: - - "DATA[0].fabricName: VXLAN_Fabric", - - "DATA[0].freezeMode: null", - - "DATA[0].ipAddress: 192.168.1.2", - - "DATA[0].mode: Normal", - - "DATA[0].serialNumber: null", - - "DATA[0].switchRole: leaf", - - "DATA[0].systemMode: Normal" - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. + ## Classes and Methods + + - MaintenanceModeInfo.__init__() + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - `ipAddress` is set to something other than 192.168.1.2 + - `responses_SwitchDetails.json`: + - "DATA[0].fabricName: VXLAN_Fabric", + - "DATA[0].freezeMode: null", + - "DATA[0].ipAddress: 192.168.1.2", + - "DATA[0].mode: Normal", + - "DATA[0].serialNumber: null", + - "DATA[0].switchRole: leaf", + - "DATA[0].systemMode: Normal" + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -565,38 +644,49 @@ def test_maintenance_mode_info_00400( mock_message, ) -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - ### Summary - - Verify ``refresh()`` raises ``ValueError`` when - ``fabric_details.filter`` raises ``ValueError``. - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - "DATA[0].fabricName: VXLAN_Fabric", - - "DATA[0].freezeMode: null", - - "DATA[0].ipAddress: 192.168.1.2", - - "DATA[0].mode: Normal", - - "DATA[0].serialNumber: FDO211218FV", - - "DATA[0].switchRole: leaf", - - "DATA[0].systemMode: Normal" - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Code Flow - Setup - - ``MaintenanceModeInfo()`` is instantiated. - - Required attributes are set. - - ``FabricDetailsByName().filter`` is mocked to conditionally raise - ``ValueError``. - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - ``ValueError`` is raised. - - Exception message matches expectations. + # Summary + + Verify `refresh()` raises `ValueError` when + `fabric_details.filter` raises `ValueError`. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + + ## Test + + - `ValueError` is raised. + - Exception message matches expectations. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - "DATA[0].fabricName: VXLAN_Fabric", + - "DATA[0].freezeMode: null", + - "DATA[0].ipAddress: 192.168.1.2", + - "DATA[0].mode: Normal", + - "DATA[0].serialNumber: FDO211218FV", + - "DATA[0].switchRole: leaf", + - "DATA[0].systemMode: Normal" + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated. + - Required attributes are set. + - `FabricDetailsByName().filter` is mocked to conditionally raise + `ValueError`. + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - `ValueError` is raised. + - Exception message matches expectations. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -632,39 +722,49 @@ def responses(): def test_maintenance_mode_info_00500() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - ### Summary - - Verify when ``freezeMode`` == null in the response, - ``freezeMode`` is set to False. - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - "DATA[0].fabricName: VXLAN_Fabric", - - "DATA[0].freezeMode: null", - - "DATA[0].ipAddress: 192.168.1.2", - - "DATA[0].mode: Normal", - - "DATA[0].serialNumber: FDO211218FV", - - "DATA[0].switchRole: leaf", - - "DATA[0].systemMode: Normal" - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - Exception is not raised. - - ``MaintenanceModeInfo().results`` contains expected data. + # Summary + + Verify when `freezeMode` == null in the response, + `freezeMode` is set to False. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + + ## Test + + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - "DATA[0].fabricName: VXLAN_Fabric", + - "DATA[0].freezeMode: null", + - "DATA[0].ipAddress: 192.168.1.2", + - "DATA[0].mode: Normal", + - "DATA[0].serialNumber: FDO211218FV", + - "DATA[0].switchRole: leaf", + - "DATA[0].systemMode: Normal" + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. """ method_name = inspect.stack()[0][3] @@ -697,40 +797,50 @@ def responses(): def test_maintenance_mode_info_00510() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - __init__() - - refresh() - - ### Summary - - Verify happy path with: - - switch_details: freezeMode is True - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - "DATA[0].fabricName: VXLAN_Fabric", - - "DATA[0].freezeMode: true", - - "DATA[0].ipAddress: 192.168.1.2", - - "DATA[0].mode: Normal", - - "DATA[0].serialNumber: FDO211218FV", - - "DATA[0].switchRole: leaf", - - "DATA[0].systemMode: Normal" - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - Exception is not raised. - - ``MaintenanceModeInfo().results`` contains expected data. + # Summary + + Verify happy path with: + - switch_details: freezeMode is True + + ## Classes and Methods + + - MaintenanceModeInfo.__init__() + - MaintenanceModeInfo.refresh() + + ## Test + + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - "DATA[0].fabricName: VXLAN_Fabric", + - "DATA[0].freezeMode: true", + - "DATA[0].ipAddress: 192.168.1.2", + - "DATA[0].mode: Normal", + - "DATA[0].serialNumber: FDO211218FV", + - "DATA[0].switchRole: leaf", + - "DATA[0].systemMode: Normal" + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. """ method_name = inspect.stack()[0][3] @@ -763,41 +873,52 @@ def responses(): def test_maintenance_mode_info_00520() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - __init__() - - refresh() - - ### Summary - - Verify: - - ``mode`` == "inconsistent" when ``mode`` != ``systemMode``. - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - DATA[0].fabricName: VXLAN_Fabric - - DATA[0].freezeMode: true - - DATA[0].ipAddress: 192.168.1.2 - - DATA[0].mode: Normal - - DATA[0].serialNumber: FDO211218FV - - DATA[0].switchRole: leaf - - DATA[0].systemMode: Maintenance - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - Conditions in Summary are confirmed. - - Exception is not raised. - - ``MaintenanceModeInfo().results`` contains expected data. + # Summary + + Verify: + - `mode` == "inconsistent" when `mode` != `systemMode`. + + ## Classes and Methods + + - MaintenanceModeInfo.__init__() + - MaintenanceModeInfo.refresh() + + ## Test + + - Conditions in Summary are confirmed. + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - DATA[0].fabricName: VXLAN_Fabric + - DATA[0].freezeMode: true + - DATA[0].ipAddress: 192.168.1.2 + - DATA[0].mode: Normal + - DATA[0].serialNumber: FDO211218FV + - DATA[0].switchRole: leaf + - DATA[0].systemMode: Maintenance + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - Conditions in Summary are confirmed. + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. """ method_name = inspect.stack()[0][3] @@ -831,45 +952,55 @@ def responses(): def test_maintenance_mode_info_00600() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - FabricDetailsByName() - - refresh() - - ### Summary - - Verify: - - ``fabric_read_only`` is set to True when ``IS_READ_ONLY`` - is true in the controller response (FabricDetailsByName). - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - DATA[0].fabricName: LAN_Classic - - DATA[0].freezeMode: null - - DATA[0].ipAddress: 192.168.1.2 - - DATA[0].mode: Normal - - DATA[0].serialNumber: FDO211218FV - - DATA[0].switchRole: leaf - - DATA[0].systemMode: Normal - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - DATA[0].nvPairs.FABRIC_NAME: LAN_Classic - - DATA[0].nvPairs.IS_READ_ONLY: true - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - Conditions in Summary are confirmed. - - Exception is not raised. - - ``MaintenanceModeInfo().results`` contains expected data. + # Summary + + Verify: + - `fabric_read_only` is set to True when `IS_READ_ONLY` + is true in the controller response (FabricDetailsByName). + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + - FabricDetailsByName.refresh() + + ## Test + + - Conditions in Summary are confirmed. + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - DATA[0].fabricName: LAN_Classic + - DATA[0].freezeMode: null + - DATA[0].ipAddress: 192.168.1.2 + - DATA[0].mode: Normal + - DATA[0].serialNumber: FDO211218FV + - DATA[0].switchRole: leaf + - DATA[0].systemMode: Normal + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - DATA[0].nvPairs.FABRIC_NAME: LAN_Classic + - DATA[0].nvPairs.IS_READ_ONLY: true + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - Conditions in Summary are confirmed. + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. """ method_name = inspect.stack()[0][3] @@ -901,50 +1032,61 @@ def responses(): def test_maintenance_mode_info_00700() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - SwitchDetails() - - refresh() - - FabricDetailsByName() - - refresh() - - ### Summary - - Verify: - - ``role`` is set to "na" when ``switchRole`` is null in the - controller response. - - ### Setup - Data - - ``responses_SwitchDetails.json``: - - DATA[0].fabricName: LAN_Classic - - DATA[0].freezeMode: null - - DATA[0].ipAddress: 192.168.1.2 - - DATA[0].mode: Normal - - DATA[0].serialNumber: FDO211218FV - - DATA[0].switchRole: null - - DATA[0].systemMode: Normal - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - Conditions in Summary are confirmed. - - Exception is not raised. - - ``MaintenanceModeInfo().results`` contains expected data. - - ### NOTES - - ``SwitchDetails().role`` is an alias of ``SwitchDetails().switch_role``. - - ``MaintenanceModeInfo().role`` is set based on the value of - ``SwitchDetails().role``. + # Summary + + Verify: + - `role` is set to "na" when `switchRole` is null in the + controller response. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + - SwitchDetails.refresh() + - FabricDetailsByName.refresh() + + ## Test + + - Conditions in Summary are confirmed. + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. + + ## Setup - Data + + - `responses_SwitchDetails.json`: + - DATA[0].fabricName: LAN_Classic + - DATA[0].freezeMode: null + - DATA[0].ipAddress: 192.168.1.2 + - DATA[0].mode: Normal + - DATA[0].serialNumber: FDO211218FV + - DATA[0].switchRole: null + - DATA[0].systemMode: Normal + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - Conditions in Summary are confirmed. + - Exception is not raised. + - `MaintenanceModeInfo().results` contains expected data. + + ## Notes + + - `SwitchDetails().role` is an alias of `SwitchDetails().switch_role`. + - `MaintenanceModeInfo().role` is set based on the value of + `SwitchDetails().role`. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -975,30 +1117,38 @@ def responses(): def test_maintenance_mode_info_00800() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - SwitchDetails() - - refresh() - - FabricDetailsByName() - - refresh() - - ### Summary - - Verify: - - _get() raises ``ValueError`` if ``filter`` is not set. - - ### Setup - Data + # Summary + + Verify: + - _get() raises `ValueError` if `filter` is not set. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + - SwitchDetails.refresh() + - FabricDetailsByName.refresh() + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data + None - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + + ## Trigger - ### Trigger - - ``MaintenanceModeInfo().role`` is accessed without setting - ``filter``. + - `MaintenanceModeInfo().role` is accessed without setting + `filter`. + + ## Expected Result + + - Conditions in Summary are confirmed. - ### Expected Result - - Conditions in Summary are confirmed. """ with does_not_raise(): instance = MaintenanceModeInfo(PARAMS) @@ -1012,49 +1162,56 @@ def test_maintenance_mode_info_00800() -> None: def test_maintenance_mode_info_00810() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - SwitchDetails() - - refresh() - - FabricDetailsByName() - - refresh() - - ### Summary - - Verify: - - ``_get()`` raises ``ValueError`` if ``filter`` (switch IP) - is not found in the controller response when the user accesses - a property. - - ### Setup - Data - - ``CONFIG``: ["192.168.1.2"] - - ``responses_SwitchDetails.json``: - - DATA[0].fabricName: LAN_Classic - - DATA[0].freezeMode: null - - DATA[0].ipAddress: 192.168.1.2 - - DATA[0].mode: Normal - - DATA[0].serialNumber: FDO211218FV - - DATA[0].switchRole: null - - DATA[0].systemMode: Normal - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - DATA[0].nvPairs.FABRIC_NAME: VXLAN_Fabric - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ``refresh()`` is called. - - ``filter`` is set to 1.2.3.4 - - - ### Trigger - - ``serial_number`` is accessed - - ### Expected Result - - Conditions in Summary are confirmed. + # Summary + + Verify: + - `_get()` raises `ValueError` if `filter` (switch IP) + is not found in the controller response when the user accesses + a property. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + - SwitchDetails.refresh() + - FabricDetailsByName.refresh() + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data + + - `CONFIG`: ["192.168.1.2"] + - `responses_SwitchDetails.json`: + - DATA[0].fabricName: LAN_Classic + - DATA[0].freezeMode: null + - DATA[0].ipAddress: 192.168.1.2 + - DATA[0].mode: Normal + - DATA[0].serialNumber: FDO211218FV + - DATA[0].switchRole: null + - DATA[0].systemMode: Normal + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - DATA[0].nvPairs.FABRIC_NAME: VXLAN_Fabric + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + - `refresh()` is called. + - `filter` is set to 1.2.3.4 + + ## Trigger + + - `serial_number` is accessed + + ## Expected Result + + - Conditions in Summary are confirmed. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -1084,48 +1241,55 @@ def responses(): def test_maintenance_mode_info_00820() -> None: """ - ### Classes and Methods - - MaintenanceModeInfo() - - refresh() - - SwitchDetails() - - refresh() - - FabricDetailsByName() - - refresh() - - ### Summary - - Verify: - - ``refresh`` re-raises ``ValueError`` raised by - ``SwitchDetails()._get()`` when ``item`` is not found in the - controller response. In this, case ``item`` is ``freezeMode``. - - ### Setup - Data - - ``CONFIG``: ["192.168.1.2"] - - ``responses_SwitchDetails.json`` is missing the key ``freezeMode``. - - ``responses_SwitchDetails.json``: - - DATA[0].fabricName: LAN_Classic - - DATA[0].ipAddress: 192.168.1.2 - - DATA[0].mode: Normal - - DATA[0].serialNumber: FDO211218FV - - DATA[0].switchRole: null - - DATA[0].systemMode: Normal - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - DATA[0].nvPairs.FABRIC_NAME: VXLAN_Fabric - - DATA[0].nvPairs.IS_READ_ONLY: false - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - - ### Trigger - - ``refresh()`` is called. - - ### Expected Result - - Conditions in Summary are confirmed. + # Summary + + Verify: + - `refresh` re-raises `ValueError` raised by + `SwitchDetails()._get()` when `item` is not found in the + controller response. In this, case `item` is `freezeMode`. + + ## Classes and Methods + + - MaintenanceModeInfo.refresh() + - SwitchDetails.refresh() + - FabricDetailsByName.refresh() + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data + + - `CONFIG`: ["192.168.1.2"] + - `responses_SwitchDetails.json` is missing the key `freezeMode`. + - `responses_SwitchDetails.json`: + - DATA[0].fabricName: LAN_Classic + - DATA[0].ipAddress: 192.168.1.2 + - DATA[0].mode: Normal + - DATA[0].serialNumber: FDO211218FV + - DATA[0].switchRole: null + - DATA[0].systemMode: Normal + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - DATA[0].nvPairs.FABRIC_NAME: VXLAN_Fabric + - DATA[0].nvPairs.IS_READ_ONLY: false + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `refresh()` is called. + + ## Expected Result + + - Conditions in Summary are confirmed. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -1157,26 +1321,36 @@ def responses(): def test_maintenance_mode_info_00900() -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``config.setter`` + # Summary + + Verify: + - `config` raises `TypeError` when set to an invalid type. + + ## Classes and Methods - ### Summary - - Verify: - - ``config`` raises ``TypeError`` when set to an invalid type. + - MaintenanceModeInfo.config setter + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data - ### Setup - Data None - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set - ### Trigger - - ``config`` is set to a value that is not a ``list``. + ## Trigger + + - `config` is set to a value that is not a `list`. + + ## Expected Result + + - Conditions in Summary are confirmed. - ### Expected Result - - Conditions in Summary are confirmed. """ with does_not_raise(): instance = MaintenanceModeInfo(PARAMS) @@ -1190,27 +1364,37 @@ def test_maintenance_mode_info_00900() -> None: def test_maintenance_mode_info_00910() -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``config.setter`` + # Summary + + Verify: + - `config` raises `TypeError` when an element in the list is + not a `str`. - ### Summary - - Verify: - - ``config`` raises ``TypeError`` when an element in the list is - not a ``str``. + ## Classes and Methods + + - MaintenanceModeInfo.config setter + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data - ### Setup - Data None - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `config` is set to a value that is not a `list`. + + ## Expected Result - ### Trigger - - ``config`` is set to a value that is not a ``list``. + - Conditions in Summary are confirmed. - ### Expected Result - - Conditions in Summary are confirmed. """ with does_not_raise(): instance = MaintenanceModeInfo(PARAMS) @@ -1226,27 +1410,37 @@ def test_maintenance_mode_info_00910() -> None: def test_maintenance_mode_info_01000() -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``info.getter`` + # Summary - ### Summary - - Verify: - - ``info`` raises ``ValueError`` when accessed before - ``refresh()`` is called. + Verify: + - `info` raises `ValueError` when accessed before + `refresh()` is called. + + ## Classes and Methods + + - MaintenanceModeInfo.info getter + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data - ### Setup - Data None - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `info` is accessed without having first called `refresh()`. - ### Trigger - - ``info`` is accessed without having first called ``refresh()``. + ## Expected Result + + - Conditions in Summary are confirmed. - ### Expected Result - - Conditions in Summary are confirmed. """ with does_not_raise(): instance = MaintenanceModeInfo(PARAMS) @@ -1260,41 +1454,51 @@ def test_maintenance_mode_info_01000() -> None: def test_maintenance_mode_info_01010() -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``info.getter`` - - ### Summary - - Verify: - - ``info`` returns expected information in the happy path. - - ### Setup - Data - - ``CONFIG``: ["192.168.1.2"] - - ``responses_SwitchDetails.json``: - - DATA[0].fabricName: VXLAN_Fabric - - DATA[0].freezeMode: null - - DATA[0].ipAddress: 192.168.1.2 - - DATA[0].mode: Normal - - DATA[0].serialNumber: FDO211218FV - - DATA[0].switchRole: leaf - - DATA[0].systemMode: Maintenance - - RETURN_CODE: 200 - - MESSAGE: OK - - ``responses_FabricDetailsByName.json``: - - DATA[0].nvPairs.FABRIC_NAME: VXLAN_Fabric - - DATA[0].nvPairs.IS_READ_ONLY: false - - RETURN_CODE: 200 - - MESSAGE: OK - - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set - - ### Trigger - - ``info`` is accessed without having first called ``refresh()``. - - ### Expected Result - - Conditions in Summary are confirmed. + # Summary + + Verify: + - `info` returns expected information in the happy path. + + ## Classes and Methods + + - MaintenanceModeInfo.info getter + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data + + - `CONFIG`: ["192.168.1.2"] + - `responses_SwitchDetails.json`: + - DATA[0].fabricName: VXLAN_Fabric + - DATA[0].freezeMode: null + - DATA[0].ipAddress: 192.168.1.2 + - DATA[0].mode: Normal + - DATA[0].serialNumber: FDO211218FV + - DATA[0].switchRole: leaf + - DATA[0].systemMode: Maintenance + - RETURN_CODE: 200 + - MESSAGE: OK + - `responses_FabricDetailsByName.json`: + - DATA[0].nvPairs.FABRIC_NAME: VXLAN_Fabric + - DATA[0].nvPairs.IS_READ_ONLY: false + - RETURN_CODE: 200 + - MESSAGE: OK + + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `info` is accessed without having first called `refresh()`. + + ## Expected Result + + - Conditions in Summary are confirmed. + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -1327,26 +1531,36 @@ def responses(): def test_maintenance_mode_info_01020() -> None: """ - ### Classes and Methods - - ``MaintenanceModeInfo()`` - - ``info.setter`` + # Summary + + Verify: + - `info` raises `TypeError` when set to an invalid type. - ### Summary - - Verify: - - ``info`` raises ``TypeError`` when set to an invalid type. + ## Classes and Methods + + - MaintenanceModeInfo.info setter + + ## Test + + - Conditions in Summary are confirmed. + + ## Setup - Data - ### Setup - Data None - ### Setup - Code - - ``MaintenanceModeInfo()`` is instantiated - - Required attributes are set + ## Setup - Code + + - `MaintenanceModeInfo()` is instantiated + - Required attributes are set + + ## Trigger + + - `info` is set to a value that is not a `dict`. + + ## Expected Result - ### Trigger - - ``info`` is set to a value that is not a ``dict``. + - Conditions in Summary are confirmed. - ### Expected Result - - Conditions in Summary are confirmed. """ with does_not_raise(): instance = MaintenanceModeInfo(PARAMS) From 0e26ebbdb92423059fbcce8caa5369aac4d02396 Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 13:53:25 -1000 Subject: [PATCH 06/14] Appease pep8 linter Fix below error: ERROR: tests/unit/module_utils/common/test_maintenance_mode.py:1238:161: E501: line too long (181 > 160 characters) --- tests/unit/module_utils/common/test_maintenance_mode.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/module_utils/common/test_maintenance_mode.py b/tests/unit/module_utils/common/test_maintenance_mode.py index c6ae65ee0..55ebcfdb8 100644 --- a/tests/unit/module_utils/common/test_maintenance_mode.py +++ b/tests/unit/module_utils/common/test_maintenance_mode.py @@ -1235,7 +1235,8 @@ def test_maintenance_mode_01100(monkeypatch, maintenance_mode) -> None: ## Test - - Verify MaintenanceMode().commit() raises `ValueError` when MaintenanceMode().deploy_switches() raises `ControllerResponseError` when the RETURN_CODE in the response is not 200 + - Verify MaintenanceMode().commit() raises `ValueError` when MaintenanceMode().deploy_switches() raises `ControllerResponseError` + when the RETURN_CODE in the response is not 200 ## Code Flow - Setup From 3041e2de6d243ee9a88138609514cab8a750f01f Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 15:48:25 -1000 Subject: [PATCH 07/14] dcnm_maintenance_mode.py: Add type hints/annotations Add type hints for all vars and type annotations for all methods. --- plugins/modules/dcnm_maintenance_mode.py | 201 ++++++++++++----------- 1 file changed, 109 insertions(+), 92 deletions(-) diff --git a/plugins/modules/dcnm_maintenance_mode.py b/plugins/modules/dcnm_maintenance_mode.py index da04957cd..1b7aa227e 100644 --- a/plugins/modules/dcnm_maintenance_mode.py +++ b/plugins/modules/dcnm_maintenance_mode.py @@ -1,6 +1,9 @@ #!/usr/bin/python +""" +Ansible module to manage Maintenance Mode Configuration of NX-OS Switches. +""" # -# Copyright (c) 2020-2024 Cisco and/or its affiliates. +# Copyright (c) 2020-2025 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. @@ -13,10 +16,12 @@ # 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. +# pylint: disable=too-many-lines from __future__ import absolute_import, division, print_function +from typing import Any -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __author__ = "Allen Robel" DOCUMENTATION = """ @@ -169,7 +174,6 @@ def json_pretty(msg): """ return json.dumps(msg, indent=4, sort_keys=True) - class ParamsSpec: """ # Summary @@ -211,18 +215,18 @@ class ParamsSpec: ``` """ - def __init__(self): - self.class_name = self.__class__.__name__ + def __init__(self) -> None: + self.class_name: str = self.__class__.__name__ - self.log = logging.getLogger(f"dcnm.{self.class_name}") + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") self.log.debug("ENTERED ParamsSpec()") - self._params = None - self._params_spec: dict = {} + self._params: dict[str, Any] = {} + self._params_spec: dict[str, Any] = {} - self.valid_states = ["merged", "query"] + self._valid_states: list[str] = ["merged", "query"] - def commit(self): + def commit(self) -> None: """ # Summary @@ -233,22 +237,34 @@ def commit(self): ### ValueError - params is not set + - params["state"] is not a valid state (merged or query) """ - if self._params is None: + if not self._params: msg = f"{self.class_name}.commit: " msg += "params must be set before calling commit()." raise ValueError(msg) - if self.params["state"] == "merged": + if self.params.get("state") == "merged": self._build_params_spec_for_merged_state() - if self.params["state"] == "query": + elif self.params.get("state") == "query": self._build_params_spec_for_query_state() + else: + msg = f"{self.class_name}.commit: " + msg += f"Invalid state {self.params.get('state')}." + raise ValueError(msg) + def _build_params_spec_for_merged_state(self) -> None: """ + # Summary + Build the parameter specifications for ``merged`` state. + + ## Raises + + None """ - self._params_spec: dict = {} + self._params_spec = {} self._params_spec["ip_address"] = {} self._params_spec["ip_address"]["required"] = True self._params_spec["ip_address"]["type"] = "ipv4" @@ -271,22 +287,28 @@ def _build_params_spec_for_merged_state(self) -> None: def _build_params_spec_for_query_state(self) -> None: """ + # Summary + Build the parameter specifications for ``query`` state. + + ## Raises + + None """ - self._params_spec: dict = {} + self._params_spec = {} self._params_spec["ip_address"] = {} self._params_spec["ip_address"]["required"] = True self._params_spec["ip_address"]["type"] = "ipv4" @property - def params_spec(self) -> dict: + def params_spec(self) -> dict[str, Any]: """ return the parameter specification """ return self._params_spec @property - def params(self) -> dict: + def params(self) -> dict[str, Any]: """ # Summary @@ -312,11 +334,11 @@ def params(self) -> dict: return self._params @params.setter - def params(self, value: dict) -> None: + def params(self, value: dict[str, Any]) -> None: """ - setter: set the params """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if not isinstance(value, dict): msg = f"{self.class_name}.{method_name}.setter: " msg += "Invalid type. Expected dict but " @@ -329,10 +351,10 @@ def params(self, value: dict) -> None: msg += "params.state is required but missing." raise ValueError(msg) - if value["state"] not in self.valid_states: + if value["state"] not in self._valid_states: msg = f"{self.class_name}.{method_name}.setter: " msg += f"params.state is invalid: {value['state']}. " - msg += f"Expected one of {', '.join(self.valid_states)}." + msg += f"Expected one of {', '.join(self._valid_states)}." raise ValueError(msg) self._params = value @@ -397,22 +419,22 @@ class Want: ``` """ - def __init__(self): - self.class_name = self.__class__.__name__ + def __init__(self) -> None: + self.class_name: str = self.__class__.__name__ - self.log = logging.getLogger(f"dcnm.{self.class_name}") + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") self.log.debug("ENTERED Want()") - self._config = None - self._items_key = None - self._params = None - self._params_spec = None - self._validator = None - self._want = [] + self._config: dict[str, Any] = {} + self._items_key: str = "" + self._params: dict[str, Any] = {} + self._params_spec: ParamsSpec = ParamsSpec() + self._validator: ParamsValidate = ParamsValidate() + self._want: list[dict[str, Any]] = [] - self.merge_dicts = MergeDicts() - self.merged_configs = [] - self.item_configs = [] + self.merge_dicts: MergeDicts = MergeDicts() + self.merged_configs: list[dict[str, Any]] = [] + self.item_configs: list[dict[str, Any]] = [] def generate_params_spec(self) -> None: """ @@ -428,11 +450,11 @@ def generate_params_spec(self) -> None: - self.params_spec is not set """ # Generate the params_spec used to validate the configs - if self.params is None: + if not self.params: msg = f"{self.class_name}.generate_params_spec(): " msg += "params is not set, and is required." raise ValueError(msg) - if self.params_spec is None: + if not self.params_spec: msg = f"{self.class_name}.generate_params_spec(): " msg += "params_spec is not set, and is required." raise ValueError(msg) @@ -457,13 +479,13 @@ def validate_configs(self) -> None: ## Notes - validator is already verified in commit()s + validator is already verified in commit() """ - self.validator.params_spec = self.params_spec.params_spec + self._validator.params_spec = self._params_spec.params_spec for config in self.merged_configs: - self.validator.parameters = config - self.validator.commit() - self.want.append(copy.deepcopy(config)) + self._validator.parameters = config + self._validator.commit() + self._want.append(copy.deepcopy(config)) def build_merged_configs(self) -> None: """ @@ -478,7 +500,7 @@ def build_merged_configs(self) -> None: None """ self.merged_configs = [] - merge_defaults = ParamsMergeDefaults() + merge_defaults: ParamsMergeDefaults = ParamsMergeDefaults() merge_defaults.params_spec = self.params_spec.params_spec for config in self.item_configs: merge_defaults.parameters = config @@ -521,9 +543,9 @@ def commit(self) -> None: See class docstring. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] - if self.validator is None: + if self._validator is None: msg = f"{self.class_name}.{method_name}: " msg += f"self.validator must be set before calling {method_name}." raise ValueError(msg) @@ -583,9 +605,9 @@ def _merge_global_and_item_configs(self) -> None: from global_config. - If item_config has a parameter, use it. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] - if self.config is None: + if not self.config: msg = f"{self.class_name}.{method_name}: " msg += "config is not set, and is required." raise ValueError(msg) @@ -754,7 +776,7 @@ def params(self, value: dict) -> None: self._params = value @property - def params_spec(self): + def params_spec(self) -> ParamsSpec: """ # Summary @@ -780,8 +802,8 @@ def params_spec(self): return self._params_spec @params_spec.setter - def params_spec(self, value) -> None: - method_name = inspect.stack()[0][3] + def params_spec(self, value: ParamsSpec) -> None: + method_name: str = inspect.stack()[0][3] _class_have = None _class_need = "ParamsSpec" msg = f"{self.class_name}.{method_name}: " @@ -798,7 +820,7 @@ def params_spec(self, value) -> None: self._params_spec = value @property - def validator(self): + def validator(self) -> ParamsValidate: """ # Summary @@ -811,7 +833,7 @@ def validator(self): setter: - - value is not an instance of ``ParamsValidate()`` + - value is not an instance of `ParamsValidate()` ## Details @@ -821,8 +843,8 @@ def validator(self): return self._validator @validator.setter - def validator(self, value) -> None: - method_name = inspect.stack()[0][3] + def validator(self, value: ParamsValidate) -> None: + method_name: str = inspect.stack()[0][3] _class_have = None _class_need = "ParamsValidate" msg = f"{self.class_name}.{method_name}: " @@ -845,7 +867,7 @@ class Common: Common methods, properties, and resources for all states. """ - def __init__(self, params): + def __init__(self, params: dict[str, Any]): """ # Summary @@ -855,7 +877,6 @@ def __init__(self, params): ### ValueError - - `params` does not contain `check_mode` - `params` does not contain `state` - `params` does not contain `config` @@ -863,26 +884,22 @@ def __init__(self, params): - `config` is not a dict """ - self.class_name = self.__class__.__name__ - method_name = inspect.stack()[0][3] + self.class_name: str = self.__class__.__name__ + method_name: str = inspect.stack()[0][3] self.params = params - self.log = logging.getLogger(f"dcnm.{self.class_name}") - self.check_mode = self.params.get("check_mode", None) - if self.check_mode is None: - msg = f"{self.class_name}.{method_name}: " - msg += "check_mode is required." - raise ValueError(msg) + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") - self.state = self.params.get("state", None) - if self.state is None: + self._check_mode: bool = self.params.get("check_mode", False) + self.state: str = self.params.get("state", "") + if not self.state: msg = f"{self.class_name}.{method_name}: " msg += "state is required." raise ValueError(msg) - self.config = self.params.get("config", None) - if self.config is None: + self.config: dict[str, Any] = self.params.get("config", {}) + if not self.config: msg = f"{self.class_name}.{method_name}: " msg += "config is required." raise ValueError(msg) @@ -892,11 +909,11 @@ def __init__(self, params): msg += f"Got {type(self.config).__name__}" raise TypeError(msg) - self._rest_send = None + self._rest_send: RestSend = RestSend({}) - self.results = Results() + self.results: Results = Results() self.results.state = self.state - self.results.check_mode = self.check_mode + self.results.check_mode = self._check_mode self.have = {} # populated in self.validate_input() @@ -906,7 +923,7 @@ def __init__(self, params): msg = f"ENTERED Common().{method_name}: " msg += f"state: {self.state}, " - msg += f"check_mode: {self.check_mode}" + msg += f"check_mode: {self._check_mode}" self.log.debug(msg) def get_want(self) -> None: @@ -971,8 +988,8 @@ def __init__(self, params): - Common().__init__() raises `TypeError` """ - self.class_name = self.__class__.__name__ - method_name = inspect.stack()[0][3] + self.class_name: str = self.__class__.__name__ + method_name: str = inspect.stack()[0][3] try: super().__init__(params) except (TypeError, ValueError) as error: @@ -987,7 +1004,7 @@ def __init__(self, params): msg = f"ENTERED Merged.{method_name}: " msg += f"state: {self.state}, " - msg += f"check_mode: {self.check_mode}" + msg += f"check_mode: {self._check_mode}" self.log.debug(msg) self.need = [] @@ -1051,7 +1068,7 @@ def get_have(self): } ``` """ - method_name = inspect.stack()[0][3] # pylint: disable=unused-variable + method_name: str = inspect.stack()[0][3] # pylint: disable=unused-variable try: instance = MaintenanceModeInfo(self.params) @@ -1082,7 +1099,7 @@ def fabric_deployment_disabled(self) -> None: - any of the above cases are true """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] for ip_address, value in self.have.items(): fabric_name = value.get("fabric_name") mode = value.get("mode") @@ -1177,7 +1194,7 @@ def get_need(self): ] ``` """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] self.need = [] for want in self.want: ip_address = want.get("ip_address", None) @@ -1213,7 +1230,7 @@ def commit(self): - `get_have()` raises `ValueError` - `send_need()` raises `ValueError` """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] msg = f"{self.class_name}.{method_name}: entered" self.log.debug(msg) @@ -1266,7 +1283,7 @@ def send_need(self) -> None: - MaintenanceMode() raises `TypeError` """ - method_name = inspect.stack()[0][3] # pylint: disable=unused-variable + method_name: str = inspect.stack()[0][3] # pylint: disable=unused-variable if len(self.need) == 0: msg = f"{self.class_name}.{method_name}: " @@ -1302,7 +1319,7 @@ class Query(Common): - Common().__init__() raises `TypeError` """ - def __init__(self, params): + def __init__(self, params: dict[str, Any]) -> None: """ # Summary @@ -1318,8 +1335,8 @@ def __init__(self, params): - Common().__init__() raises `TypeError` """ - self.class_name = self.__class__.__name__ - method_name = inspect.stack()[0][3] + self.class_name: str = self.__class__.__name__ + method_name: str = inspect.stack()[0][3] try: super().__init__(params) except (TypeError, ValueError) as error: @@ -1328,16 +1345,16 @@ def __init__(self, params): msg += f"Error detail: {error}" raise ValueError(msg) from error - self.log = logging.getLogger(f"dcnm.{self.class_name}") + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") - self.maintenance_mode_info = MaintenanceModeInfo(self.params) + self.maintenance_mode_info: MaintenanceModeInfo = MaintenanceModeInfo(self.params) msg = "ENTERED Query(): " msg += f"state: {self.state}, " - msg += f"check_mode: {self.check_mode}" + msg += f"check_mode: {self._check_mode}" self.log.debug(msg) - def get_have(self): + def get_have(self) -> None: """ # Summary @@ -1395,7 +1412,7 @@ def get_have(self): } ``` """ - method_name = inspect.stack()[0][3] # pylint: disable=unused-variable + method_name: str = inspect.stack()[0][3] # pylint: disable=unused-variable try: self.maintenance_mode_info.rest_send = self.rest_send @@ -1424,7 +1441,7 @@ def commit(self) -> None: - `get_want()` raises `ValueError` - `get_have()` raises `ValueError` """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] msg = f"{self.class_name}.{method_name}: entered" self.log.debug(msg) @@ -1469,7 +1486,7 @@ def commit(self) -> None: def main(): """main entry point for module execution""" - argument_spec = {} + argument_spec: dict[str, Any] = {} argument_spec["config"] = { "required": True, "type": "dict", @@ -1481,8 +1498,8 @@ def main(): "type": "str", } - ansible_module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - params = copy.deepcopy(ansible_module.params) + ansible_module: AnsibleModule = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + params: dict[str, Any] = copy.deepcopy(ansible_module.params) params["check_mode"] = ansible_module.check_mode # Logging setup @@ -1492,9 +1509,9 @@ def main(): except ValueError as error: ansible_module.fail_json(str(error)) - sender = Sender() + sender: Sender = Sender() sender.ansible_module = ansible_module - rest_send = RestSend(params) + rest_send: RestSend = RestSend(params) rest_send.response_handler = ResponseHandler() rest_send.sender = sender From 2e9b67c357a599332565f36b7179496b87e745b9 Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 15:49:34 -1000 Subject: [PATCH 08/14] UT: Update to align with last commit. Certain dcnm_maintenance_mode unit test asserts will fail due to the changes in the last commit. Fixing that in this commit. --- .../test_dcnm_maintenance_mode_common.py | 153 +++++++++++------- 1 file changed, 95 insertions(+), 58 deletions(-) diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py index b3e38491f..8510f0533 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py @@ -1,3 +1,6 @@ +""" +Unit tests for dcnm_maintenance_mode Common class +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,11 +19,11 @@ # 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=unused-import,protected-access from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." __author__ = "Allen Robel" @@ -51,7 +54,7 @@ def test_dcnm_maintenance_mode_common_00000(common) -> None: instance = common assert instance.class_name == "Common" assert instance.state == "merged" - assert instance.check_mode is False + assert instance._check_mode is False assert instance.have == {} assert instance.payloads == {} assert instance.query == [] @@ -63,30 +66,42 @@ def test_dcnm_maintenance_mode_common_00000(common) -> None: def test_dcnm_maintenance_mode_common_00010() -> None: """ - ### Classes and Methods + # Summary + + Verify check_mode is False if not set in params. + + ## Setup - Code + + - `check_mode` is removed from params to simulate missing `check_mode` key/value. + + ## Expected Results + + - check_mode is False if not set in params. + + ## Classes and Methods + - Common - __init__() - ### Summary - - Verify ``ValueError`` is raised. - - params is missing ``check_mode`` key/value. """ params_test = copy.deepcopy(params) params_test.pop("check_mode", None) - match = r"Common\.__init__: check_mode is required" - with pytest.raises(ValueError, match=match): - Common(params_test) + instance = Common(params_test) + assert instance._check_mode is False def test_dcnm_maintenance_mode_common_00020() -> None: """ - ### Classes and Methods - - Common - - __init__() + # Summary - ### Summary - Verify ``ValueError`` is raised. - params is missing ``state`` key/value. + + ## Classes and Methods + + - Common + - __init__() + """ params_test = copy.deepcopy(params) params_test.pop("state", None) @@ -97,13 +112,14 @@ def test_dcnm_maintenance_mode_common_00020() -> None: def test_dcnm_maintenance_mode_common_00030() -> None: """ - ### Classes and Methods - - Common - - __init__() + # Summary - ### Summary - Verify ``ValueError`` is raised. - params is missing ``config`` key/value. + + ## Classes and Methods + - Common + - __init__() """ params_test = copy.deepcopy(params) params_test.pop("config", None) @@ -114,13 +130,15 @@ def test_dcnm_maintenance_mode_common_00030() -> None: def test_dcnm_maintenance_mode_common_00040() -> None: """ - ### Classes and Methods - - Common - - __init__() + # Summary - ### Summary - Verify ``TypeError`` is raised. - config is not a dict. + + ## Classes and Methods + + - Common + - __init__() """ params_test = copy.deepcopy(params) params_test.update({"config": 10}) @@ -131,13 +149,14 @@ def test_dcnm_maintenance_mode_common_00040() -> None: def test_dcnm_maintenance_mode_common_00100() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify Common().get_want() builds expected want contents. - All switches inherit top-level config. + + ## Classes and Methods + - Common + - get_want() """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -165,14 +184,16 @@ def configs(): def test_dcnm_maintenance_mode_common_00110() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify Common().get_want() builds expected want contents. - 192.168.1.2 inherits top-level config. - 192.168.1.3 overrides top-level config. + + ## Classes and Methods + + - Common + - get_want() """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -200,15 +221,18 @@ def configs(): def test_dcnm_maintenance_mode_common_00120() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify Common().get_want() builds expected want contents. - top-level config is missing. - 192.168.1.2 uses switch-level config. - 192.168.1.3 uses switch-level config. + + ## Classes and Methods + + - Common + - get_want() + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -236,11 +260,8 @@ def configs(): def test_dcnm_maintenance_mode_common_00130() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify Common().get_want() builds expected want contents. - 192.168.1.2 missing all optional parameters, so default values are provided. @@ -248,6 +269,12 @@ def test_dcnm_maintenance_mode_common_00130() -> None: - mode default value is "normal". - wait_for_mode_change default value is False. - 192.168.1.3 uses switch-level config. + + ## Classes and Methods + + - Common + - get_want() + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -275,13 +302,15 @@ def configs(): def test_dcnm_maintenance_mode_common_00140() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify ``ValueError`` is raised. - switch is missing mandatory parameter ip_address + + ## Classes and Methods + + - Common + - get_want() """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -304,13 +333,16 @@ def configs(): def test_dcnm_maintenance_mode_common_00150() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify ``ValueError`` is raised. - 192.168.1.2 contains invalid choice for mode + + ## Classes and Methods + + - Common + - get_want() + """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -334,13 +366,15 @@ def configs(): def test_dcnm_maintenance_mode_common_00160() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify ``ValueError`` is raised. - 192.168.1.2 contains non-boolean value for deploy + + ## Classes and Methods + + - Common + - get_want() """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -364,13 +398,14 @@ def configs(): def test_dcnm_maintenance_mode_common_00170() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify ``ValueError`` is raised. - 192.168.1.2 contains non-boolean value for wait_for_mode_change + + ## Classes and Methods + - Common + - get_want() """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -394,13 +429,15 @@ def configs(): def test_dcnm_maintenance_mode_common_00180() -> None: """ - ### Classes and Methods - - Common - - get_want() + # Summary - ### Summary - Verify ``ValueError`` is raised. - params contains invalid value for ``state`` + + ## Classes and Methods + + - Common + - get_want() """ method_name = inspect.stack()[0][3] key = f"{method_name}a" From 50202f2f7f31b6e21a5a70798c1e44b9c6b885bd Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 16:54:49 -1000 Subject: [PATCH 09/14] UT: Update docstrings in dcnm_maintenance_mode unit test files No functional changes in this commit. 1. Update all docstrings to conform to Markdown format. 2. Add module dostrings where missing. 3. Add pylint supression directive for __metaclass__ invalid-name --- .../test_dcnm_maintenance_mode_merged.py | 237 +++++++------ .../test_dcnm_maintenance_mode_params_spec.py | 114 ++++--- .../test_dcnm_maintenance_mode_query.py | 113 ++++--- .../test_dcnm_maintenance_mode_want.py | 313 ++++++++++-------- 4 files changed, 454 insertions(+), 323 deletions(-) diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py index 0fd42581c..0bb275cf5 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py @@ -1,3 +1,6 @@ +""" +Unit tests for dcnm_maintenance_mode Merged class. +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +24,7 @@ from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." __author__ = "Allen Robel" @@ -50,16 +53,19 @@ def test_dcnm_maintenance_mode_merged_00000() -> None: """ - ### Classes and Methods - - Common - - __init__() + # Summary + + Verify the class attributes are initialized to expected values. - ### Summary - - Verify the class attributes are initialized to expected values. + ## Test - ### Test - Class attributes are initialized to expected values. - Exception is not raised. + + ## Classes and Methods + + - Common + - `__init__()` """ with does_not_raise(): instance = Merged(params) @@ -92,15 +98,18 @@ def test_dcnm_maintenance_mode_merged_00000() -> None: def test_dcnm_maintenance_mode_merged_00100() -> None: """ - ### Classes and Methods - - Merged() - - commit() + # Summary + + Verify `commit()` happy path. + + - Change switch mode from maintenance to normal. + - No exceptions are raised. + - want contains expected structure and values. - ### Summary - - Verify ``commit()`` happy path. - - Change switch mode from maintenance to normal. - - No exceptions are raised. - - want contains expected structure and values. + ## Classes and Methods + + - Merged() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -188,15 +197,18 @@ def responses(): def test_dcnm_maintenance_mode_merged_00110() -> None: """ - ### Classes and Methods - - Merged() - - commit() + # Summary + + Verify `commit()` happy path. - ### Summary - - Verify ``commit()`` happy path. - - Change switch mode from normal to maintenance. - - No exceptions are raised. - - want contains expected structure and values. + - Change switch mode from normal to maintenance. + - No exceptions are raised. + - want contains expected structure and values. + + ## Classes and Methods + + - Merged() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -284,17 +296,20 @@ def responses(): def test_dcnm_maintenance_mode_merged_00115() -> None: """ - ### Classes and Methods + # Summary + + Verify `commit()` happy path. + + - User wants to change switches to maintenance mode, but all + switches are already in maintenance mode. + - `send_need()` returns without sending any requests since + `instance.need` is empty. + - No exceptions are raised. + + ## Classes and Methods + - Merged() - - commit() - - ### Summary - - Verify ``commit()`` happy path. - - User wants to change switches to maintenance mode, but all - switches are already in maintenance mode. - - send_need() returns without sending any requests since - instance.need is empty. - - No exceptions are raised. + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -346,14 +361,16 @@ def responses(): def test_dcnm_maintenance_mode_merged_00120() -> None: """ - ### Classes and Methods - - Merged() - - get_need() - - commit() + # Summary + + Verify `get_have()` raises `ValueError` when `ip_address` + does not exist on the controller. - ### Summary - - Verify ``get_have()`` raises ``ValueError`` when ip_address - does not exist on the controller. + ## Classes and Methods + + - Merged() + - `get_need()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -414,14 +431,16 @@ def responses(): def test_dcnm_maintenance_mode_merged_00130() -> None: """ - ### Classes and Methods - - Merged() - - fabric_deployment_disabled() - - commit() + # Summary + + Verify `fabric_deployment_disabled()` raises `ValueError` when + have `ip_address` is in migration mode. - ### Summary - - Verify ``fabric_deployment_disabled()`` raises ``ValueError`` when - have ip_address is in migration mode. + ## Classes and Methods + + - Merged() + - `fabric_deployment_disabled()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -495,14 +514,16 @@ def responses(): def test_dcnm_maintenance_mode_merged_00140() -> None: """ - ### Classes and Methods - - Merged() - - fabric_deployment_disabled() - - commit() + # Summary + + Verify `fabric_deployment_disabled()` raises `ValueError` when + the fabric is in read-only mode. + + ## Classes and Methods - ### Summary - - Verify ``fabric_deployment_disabled()`` raises ``ValueError`` when - the fabric is in read-only mode. + - Merged() + - `fabric_deployment_disabled()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -568,14 +589,16 @@ def responses(): def test_dcnm_maintenance_mode_merged_00150() -> None: """ - ### Classes and Methods - - Merged() - - fabric_deployment_disabled() - - commit() + # Summary + + Verify `fabric_deployment_disabled()` raises `ValueError` when + fabric freeze-mode is True. + + ## Classes and Methods - ### Summary - - Verify ``fabric_deployment_disabled()`` raises ``ValueError`` when - fabric freeze-mode is True. + - Merged() + - `fabric_deployment_disabled()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -641,13 +664,15 @@ def responses(): def test_dcnm_maintenance_mode_merged_00200() -> None: """ - ### Classes and Methods - - Merged() - - commit() + # Summary + + Verify `commit()` raises `ValueError` when `rest_send` has not + been set. + + ## Classes and Methods - ### Summary - - Verify ``commit()`` raises ``ValueError`` when rest_send has not - been set. + - Merged() + - `commit()` """ with does_not_raise(): instance = Merged(params) @@ -664,14 +689,16 @@ def test_dcnm_maintenance_mode_merged_00200() -> None: def test_dcnm_maintenance_mode_merged_00300(monkeypatch) -> None: """ - ### Classes and Methods - - Merged() - - get_need() - - commit() + # Summary + + Verify `get_need()` raises `ValueError` when `ip_address` + does not exist in `self.have`. + + ## Classes and Methods - ### Summary - - Verify ``get_need()`` raises ``ValueError`` when ip_address - does not exist in self.have. + - Merged() + - `get_need()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -718,14 +745,16 @@ def mock_get_have(): def test_dcnm_maintenance_mode_merged_00400(monkeypatch) -> None: """ - ### Classes and Methods - - Merged() - - get_want() - - commit() + # Summary + + Verify `commit()` re-raises `ValueError` when `get_want()` + raises `ValueError`. - ### Summary - - Verify ``commit`` re-raises ``ValueError`` when ``get_want()`` - raises ``ValueError``. + ## Classes and Methods + + - Merged() + - `get_want()` + - `commit()` """ params_test = copy.deepcopy(params) params_test.update({"config": {}}) @@ -753,13 +782,15 @@ def mock_get_want(): def test_dcnm_maintenance_mode_merged_00500() -> None: """ - ### Classes and Methods - - Merged() - - __init__() + # Summary + + Verify `__init__()` re-raises `ValueError` when `Common().__init__()` + raises `ValueError`. - ### Summary - - Verify ``__init__`` re-raises ``ValueError`` when ``Common().__init__`` - raises ``ValueError``. + ## Classes and Methods + + - Merged() + - `__init__()` """ params_test = copy.deepcopy(params) params_test.update({"config": {}}) @@ -775,14 +806,16 @@ def test_dcnm_maintenance_mode_merged_00500() -> None: def test_dcnm_maintenance_mode_merged_00600(monkeypatch) -> None: """ - ### Classes and Methods - - Merged() - - send_need() - - commit() + # Summary - ### Summary - - Verify ``commit()`` re-raises ``ValueError`` when - send_need() raises ``ValueError``. + Verify `commit()` re-raises `ValueError` when + `send_need()` raises `ValueError`. + + ## Classes and Methods + + - Merged() + - `send_need()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -843,14 +876,16 @@ def mock_send_need(): def test_dcnm_maintenance_mode_merged_00700(monkeypatch) -> None: """ - ### Classes and Methods - - Merged() - - send_need() - - commit() + # Summary - ### Summary - - Verify ``send_need()`` re-raises ``ValueError`` when - MaintenanceMode.commit() raises ``ValueError``. + Verify `send_need()` re-raises `ValueError` when + `MaintenanceMode.commit()` raises `ValueError`. + + ## Classes and Methods + + - Merged() + - `send_need()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py index e244eb49a..9c5c409e7 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py @@ -1,3 +1,6 @@ +""" +Unit tests for dcnm_maintenance_mode ParamsSpec class. +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +27,7 @@ from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." __author__ = "Allen Robel" @@ -38,16 +41,19 @@ def test_dcnm_maintenance_mode_params_spec_00000() -> None: """ - ### Classes and Methods - - ParamsSpec - - __init__() + # Summary + + Verify the class attributes are initialized to expected values. - ### Summary - - Verify the class attributes are initialized to expected values. + ## Test - ### Test - Class attributes are initialized to expected values - - ``ValueError`` is not called + - `ValueError` is not called + + ## Classes and Methods + + - ParamsSpec + - `__init__()` """ with does_not_raise(): instance = ParamsSpec() @@ -59,13 +65,16 @@ def test_dcnm_maintenance_mode_params_spec_00000() -> None: def test_dcnm_maintenance_mode_params_spec_00100() -> None: """ - ### Classes and Methods - - ParamsSpec - - params.setter + # Summary + + Verify `TypeError` is raised. + + - `params` is not a dict. + + ## Classes and Methods - ### Summary - - Verify ``TypeError`` is raised. - - params is not a dict. + - ParamsSpec + - `params.setter` """ params_test = "foo" @@ -80,13 +89,16 @@ def test_dcnm_maintenance_mode_params_spec_00100() -> None: def test_dcnm_maintenance_mode_params_spec_00110() -> None: """ - ### Classes and Methods - - ParamsSpec - - params.setter + # Summary + + Verify `ValueError` is raised. + + - `params` is missing `state` key/value. - ### Summary - - Verify ``ValueError`` is raised. - - params is missing ``state`` key/value. + ## Classes and Methods + + - ParamsSpec + - `params.setter` """ params_test = copy.deepcopy(params) params_test.pop("state", None) @@ -102,13 +114,16 @@ def test_dcnm_maintenance_mode_params_spec_00110() -> None: def test_dcnm_maintenance_mode_params_spec_00120() -> None: """ - ### Classes and Methods - - ParamsSpec - - params.setter + # Summary + + Verify `ValueError` is raised. - ### Summary - - Verify ``ValueError`` is raised. - - params ``state`` has invalid value. + - `params` `state` has invalid value. + + ## Classes and Methods + + - ParamsSpec + - `params.setter` """ params_test = copy.deepcopy(params) params_test.update({"state": "foo"}) @@ -124,13 +139,15 @@ def test_dcnm_maintenance_mode_params_spec_00120() -> None: def test_dcnm_maintenance_mode_params_spec_00200() -> None: """ - ### Classes and Methods - - ParamsSpec - - params.setter - - commit() + # Summary - ### Summary - - Verify commit() happy path for merged state. + Verify `commit()` happy path for merged state. + + ## Classes and Methods + + - ParamsSpec + - `params.setter` + - `commit()` """ params_test = copy.deepcopy(params) @@ -160,13 +177,15 @@ def test_dcnm_maintenance_mode_params_spec_00200() -> None: def test_dcnm_maintenance_mode_params_spec_00210() -> None: """ - ### Classes and Methods - - ParamsSpec - - params.setter - - commit() + # Summary - ### Summary - - Verify commit() happy path for query state. + Verify `commit()` happy path for query state. + + ## Classes and Methods + + - ParamsSpec + - `params.setter` + - `commit()` """ params_test = copy.deepcopy(params) params_test.update({"state": "query"}) @@ -184,15 +203,18 @@ def test_dcnm_maintenance_mode_params_spec_00210() -> None: def test_dcnm_maintenance_mode_params_spec_00220() -> None: """ - ### Classes and Methods - - ParamsSpec - - params.setter - - commit() + # Summary - ### Summary - - Verify commit() sad path. - - params is not set before calling commit. - - commit() raises ``ValueError`` when params is not set. + Verify `commit()` sad path. + + - `params` is not set before calling `commit()`. + - `commit()` raises `ValueError` when `params` is not set. + + ## Classes and Methods + + - ParamsSpec + - `params.setter` + - `commit()` """ params_test = copy.deepcopy(params) params_test.update({"state": "query"}) diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py index 065c3101a..7c46f81c8 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py @@ -1,3 +1,6 @@ +""" +Unit tests for dcnm_maintenance_mode Query class. +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +24,7 @@ from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." __author__ = "Allen Robel" @@ -47,16 +50,19 @@ def test_dcnm_maintenance_mode_query_00000() -> None: """ - ### Classes and Methods - - Common - - __init__() + # Summary + + Verify the class attributes are initialized to expected values. - ### Summary - - Verify the class attributes are initialized to expected values. + ## Test - ### Test - Class attributes are initialized to expected values. - Exception is not raised. + + ## Classes and Methods + + - Common + - `__init__()` """ with does_not_raise(): instance = Query(params_query) @@ -83,14 +89,17 @@ def test_dcnm_maintenance_mode_query_00000() -> None: def test_dcnm_maintenance_mode_query_00100() -> None: """ - ### Classes and Methods - - Query() - - commit() + # Summary + + Verify `commit()` happy path. + + - No exceptions are raised. + - want contains expected structure and values. - ### Summary - - Verify ``commit()`` happy path. - - No exceptions are raised. - - want contains expected structure and values. + ## Classes and Methods + + - Query() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -175,13 +184,15 @@ def responses(): def test_dcnm_maintenance_mode_query_00200() -> None: """ - ### Classes and Methods - - Query() - - commit() + # Summary + + Verify `commit()` raises `ValueError` when `rest_send` has not + been set. - ### Summary - - Verify ``commit()`` raises ``ValueError`` when rest_send has not - been set. + ## Classes and Methods + + - Query() + - `commit()` """ with does_not_raise(): instance = Query(params_query) @@ -198,14 +209,16 @@ def test_dcnm_maintenance_mode_query_00200() -> None: def test_dcnm_maintenance_mode_query_00300(monkeypatch) -> None: """ - ### Classes and Methods - - Query() - - get_need() - - commit() + # Summary - ### Summary - - Verify ``get_need()`` raises ``ValueError`` when ip_address - does not exist in self.have. + Verify `get_need()` raises `ValueError` when `ip_address` + does not exist in `self.have`. + + ## Classes and Methods + + - Query() + - `get_need()` + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" @@ -253,14 +266,16 @@ def mock_get_have(): def test_dcnm_maintenance_mode_query_00400(monkeypatch) -> None: """ - ### Classes and Methods - - Merged() - - get_want() - - commit() - - ### Summary - - Verify ``commit`` re-raises ``ValueError`` when ``get_want()`` - raises ``ValueError``. + # Summary + + Verify `commit()` re-raises `ValueError` when `get_want()` + raises `ValueError`. + + ## Classes and Methods + + - Query() + - `get_want()` + - `commit()` """ params_test = copy.deepcopy(params_query) params_test.update({"config": {}}) @@ -288,13 +303,15 @@ def mock_get_want(): def test_dcnm_maintenance_mode_query_00500() -> None: """ - ### Classes and Methods - - Query() - - __init__() + # Summary - ### Summary - - Verify ``__init__`` re-raises ``ValueError`` when ``Common().__init__`` - raises ``ValueError``. + Verify `__init__()` re-raises `ValueError` when `Common().__init__()` + raises `ValueError`. + + ## Classes and Methods + + - Query() + - `__init__()` """ params_test = copy.deepcopy(params_query) params_test.update({"config": {}}) @@ -310,13 +327,15 @@ def test_dcnm_maintenance_mode_query_00500() -> None: def test_dcnm_maintenance_mode_query_00600(monkeypatch) -> None: """ - ### Classes and Methods - - Query() - - commit() + # Summary - ### Summary - - Verify ``commit`` re-raises ``ValueError`` when ``get_have()`` - raises ``ValueError``. + Verify `commit()` re-raises `ValueError` when `get_have()` + raises `ValueError`. + + ## Classes and Methods + + - Query() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}" diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py index d9a79b926..5ea770d77 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py @@ -1,3 +1,6 @@ +""" +Unit tests for dcnm_maintenance_mode Want class. +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +24,7 @@ from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." __author__ = "Allen Robel" @@ -38,16 +41,19 @@ def test_dcnm_maintenance_mode_want_00000() -> None: """ - ### Classes and Methods - - Common - - __init__() + # Summary + + Verify the class attributes are initialized to expected values. - ### Summary - - Verify the class attributes are initialized to expected values. + ## Test - ### Test - Class attributes are initialized to expected values - - ``ValueError`` is not called + - `ValueError` is not called + + ## Classes and Methods + + - Common + - `__init__()` """ with does_not_raise(): instance = Want() @@ -64,14 +70,17 @@ def test_dcnm_maintenance_mode_want_00000() -> None: def test_dcnm_maintenance_mode_want_00100() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary - ### Summary - - Verify ``commit()`` happy path. - - No exceptions are raised. - - want contains expected structure and values. + Verify `commit()` happy path. + + - No exceptions are raised. + - want contains expected structure and values. + + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -104,13 +113,16 @@ def configs(): def test_dcnm_maintenance_mode_want_00110() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `ValueError` is raised. - ### Summary - - Verify ``ValueError`` is raised. - - Want().validator is not set prior to calling commit(). + - `Want().validator` is not set prior to calling `commit()`. + + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -137,14 +149,17 @@ def configs(): def test_dcnm_maintenance_mode_want_00120() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `Want().commit()` catches and re-raises `ValueError`. + + - `Want().generate_params_spec()` raises `ValueError` because + `params` is not set. - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError``. - - Want().generate_params_spec() raises ``ValueError`` because - ``params`` is not set. + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -174,14 +189,17 @@ def configs(): def test_dcnm_maintenance_mode_want_00121() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `Want().commit()` catches and re-raises `ValueError`. + + - `Want().generate_params_spec()` raises `ValueError` because + `params_spec` is not set. - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError``. - - Want().generate_params_spec() raises ``ValueError`` because - ``params_spec`` is not set. + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -211,14 +229,17 @@ def configs(): def test_dcnm_maintenance_mode_want_00130() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `Want().commit()` catches and re-raises `ValueError`. + + - `Want()._merge_global_and_item_configs()` raises `ValueError` + because `config` is not set. + + ## Classes and Methods - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError``. - - Want()._merge_global_and_item_configs() raises ``ValueError`` - because ``config`` is not set. + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -248,14 +269,17 @@ def configs(): def test_dcnm_maintenance_mode_want_00131() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `Want().commit()` catches and re-raises `ValueError`. - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError``. - - Want()._merge_global_and_item_configs() raises ``ValueError`` - because ``items_key`` is not set. + - `Want()._merge_global_and_item_configs()` raises `ValueError` + because `items_key` is not set. + + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -285,14 +309,17 @@ def configs(): def test_dcnm_maintenance_mode_want_00132() -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `Want().commit()` catches and re-raises `ValueError`. + + - `Want()._merge_global_and_item_configs()` raises `ValueError` + because `config` is missing the key specified by `items_key`. - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError``. - - Want()._merge_global_and_item_configs() raises ``ValueError`` - because ``config`` is missing the key specified by items_key. + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -323,14 +350,17 @@ def configs(): def test_dcnm_maintenance_mode_want_00133(monkeypatch) -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError``. - - Want()._merge_global_and_item_configs() raises ``ValueError`` - because MergeDict().commit() raises ``ValueError``. + Verify `Want().commit()` catches and re-raises `ValueError`. + + - `Want()._merge_global_and_item_configs()` raises `ValueError` + because `MergeDict().commit()` raises `ValueError`. + + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -351,11 +381,13 @@ class MockMergeDicts: # pylint: disable=too-few-public-methods @staticmethod def commit(): """ - ### Summary - Mock method for MergeDicts().commit(). + # Summary + + Mock method for `MergeDicts().commit()`. - ### Raises - ValueError: Always + ## Raises + + - `ValueError`: Always """ raise ValueError("MergeDicts().commit(). ValueError.") @@ -378,14 +410,17 @@ def commit(): def test_dcnm_maintenance_mode_want_00140(monkeypatch) -> None: """ - ### Classes and Methods - - Want() - - commit() + # Summary + + Verify `Want().commit()` catches and re-raises `ValueError` + when `Want().validate_configs()` raises `ValueError`. - ### Summary - - Verify Want().commit() catches and re-raises ``ValueError`` - when Want().validate_configs() raises ``ValueError``. - - Want().validate_configs() is mocked to raise ``ValueError``. + - `Want().validate_configs()` is mocked to raise `ValueError`. + + ## Classes and Methods + + - Want() + - `commit()` """ method_name = inspect.stack()[0][3] key = f"{method_name}a" @@ -418,12 +453,14 @@ def mock_def(): def test_dcnm_maintenance_mode_want_00200() -> None: """ - ### Classes and Methods - - Want() - - config.setter + # Summary + + Verify `Want().config` raises `TypeError` when `config` is not a dict. + + ## Classes and Methods - ### Summary - - Verify Want().config raises ``TypeError`` when config is not a dict. + - Want() + - `config.setter` """ with does_not_raise(): instance = Want() @@ -436,13 +473,15 @@ def test_dcnm_maintenance_mode_want_00200() -> None: def test_dcnm_maintenance_mode_want_00300() -> None: """ - ### Classes and Methods - - Want() - - items_key.setter + # Summary + + Verify `Want().items_key` raises `TypeError` when `items_key` is not + a string. - ### Summary - - Verify Want().items_key raises ``TypeError`` when items_key is not - a string. + ## Classes and Methods + + - Want() + - `items_key.setter` """ with does_not_raise(): instance = Want() @@ -455,12 +494,14 @@ def test_dcnm_maintenance_mode_want_00300() -> None: def test_dcnm_maintenance_mode_want_00400() -> None: """ - ### Classes and Methods - - Want() - - params.setter + # Summary - ### Summary - Verify Want().params happy path. + Verify `Want().params` happy path. + + ## Classes and Methods + + - Want() + - `params.setter` """ with does_not_raise(): instance = Want() @@ -469,12 +510,14 @@ def test_dcnm_maintenance_mode_want_00400() -> None: def test_dcnm_maintenance_mode_want_00410() -> None: """ - ### Classes and Methods - - Want() - - params.setter + # Summary + + Verify `Want().params` raises `TypeError` when `params` is not a dict. + + ## Classes and Methods - ### Summary - - Verify Want().params raises ``TypeError`` when params is not a dict. + - Want() + - `params.setter` """ with does_not_raise(): instance = Want() @@ -487,12 +530,14 @@ def test_dcnm_maintenance_mode_want_00410() -> None: def test_dcnm_maintenance_mode_want_00500() -> None: """ - ### Classes and Methods - - Want() - - params_spec.setter + # Summary - ### Summary - Verify Want().params_spec happy path. + Verify `Want().params_spec` happy path. + + ## Classes and Methods + + - Want() + - `params_spec.setter` """ with does_not_raise(): instance = Want() @@ -501,13 +546,15 @@ def test_dcnm_maintenance_mode_want_00500() -> None: def test_dcnm_maintenance_mode_want_00510() -> None: """ - ### Classes and Methods - - Want() - - params_spec.setter + # Summary + + Verify `Want().params_spec` raises `TypeError` when `params_spec` + is not an instance of `ParamsSpec()`. + + ## Classes and Methods - ### Summary - - Verify Want().params_spec raises ``TypeError`` when params_spec - is not an instance of ParamsSpec(). + - Want() + - `params_spec.setter` """ with does_not_raise(): instance = Want() @@ -522,14 +569,16 @@ def test_dcnm_maintenance_mode_want_00510() -> None: def test_dcnm_maintenance_mode_want_00520() -> None: """ - ### Classes and Methods - - Want() - - params_spec.setter + # Summary - ### Summary - Verify Want().params_spec raises ``TypeError`` when params_spec - is not an instance of ParamsSpec(), but IS an instance of another + Verify `Want().params_spec` raises `TypeError` when `params_spec` + is not an instance of `ParamsSpec()`, but IS an instance of another class. + + ## Classes and Methods + + - Want() + - `params_spec.setter` """ with does_not_raise(): instance = Want() @@ -543,12 +592,14 @@ def test_dcnm_maintenance_mode_want_00520() -> None: def test_dcnm_maintenance_mode_want_00600() -> None: """ - ### Classes and Methods - - Want() - - validator.setter + # Summary - ### Summary - Verify Want().validator happy path. + Verify `Want().validator` happy path. + + ## Classes and Methods + + - Want() + - `validator.setter` """ with does_not_raise(): instance = Want() @@ -557,13 +608,15 @@ def test_dcnm_maintenance_mode_want_00600() -> None: def test_dcnm_maintenance_mode_want_00610() -> None: """ - ### Classes and Methods - - Want() - - validator.setter + # Summary + + Verify `Want().validator` raises `TypeError` when `validator` + is not an instance of `ParamsValidate()`. + + ## Classes and Methods - ### Summary - - Verify Want().validator raises ``TypeError`` when validator - is not an instance of ParamsValidate(). + - Want() + - `validator.setter` """ with does_not_raise(): instance = Want() @@ -578,14 +631,16 @@ def test_dcnm_maintenance_mode_want_00610() -> None: def test_dcnm_maintenance_mode_want_00620() -> None: """ - ### Classes and Methods - - Want() - - validator.setter + # Summary - ### Summary - Verify Want().validator raises ``TypeError`` when validator - is not an instance of ParamsValidate(), but IS an instance of + Verify `Want().validator` raises `TypeError` when `validator` + is not an instance of `ParamsValidate()`, but IS an instance of another class. + + ## Classes and Methods + + - Want() + - `validator.setter` """ with does_not_raise(): instance = Want() From 89f23a3fac6ded8762c034927eb55126deb3416f Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Wed, 3 Dec 2025 16:56:39 -1000 Subject: [PATCH 10/14] UT: Update copyright dates No functional changes in this commit. Update copyright dates for all unit test files associuated with dcnm_maintenance_mode. --- .../test_dcnm_maintenance_mode_merged.py | 4 ++-- .../test_dcnm_maintenance_mode_params_spec.py | 4 ++-- .../dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py | 4 ++-- .../dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py index 0bb275cf5..088441875 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py @@ -1,7 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Merged class. """ -# Copyright (c) 2024 Cisco and/or its affiliates. +# Copyright (c) 2024-2025 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. @@ -26,7 +26,7 @@ __metaclass__ = type # pylint: disable=invalid-name -__copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." +__copyright__ = "Copyright (c) 2024-2025 Cisco and/or its affiliates." __author__ = "Allen Robel" import copy diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py index 9c5c409e7..a7ea359ed 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py @@ -1,7 +1,7 @@ """ Unit tests for dcnm_maintenance_mode ParamsSpec class. """ -# Copyright (c) 2024 Cisco and/or its affiliates. +# Copyright (c) 2024-2025 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. @@ -29,7 +29,7 @@ __metaclass__ = type # pylint: disable=invalid-name -__copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." +__copyright__ = "Copyright (c) 2024-2025 Cisco and/or its affiliates." __author__ = "Allen Robel" import copy diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py index 7c46f81c8..be814015d 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py @@ -1,7 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Query class. """ -# Copyright (c) 2024 Cisco and/or its affiliates. +# Copyright (c) 2024-2025 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. @@ -26,7 +26,7 @@ __metaclass__ = type # pylint: disable=invalid-name -__copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." +__copyright__ = "Copyright (c) 2024-2025 Cisco and/or its affiliates." __author__ = "Allen Robel" import copy diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py index 5ea770d77..500352185 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py @@ -1,7 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Want class. """ -# Copyright (c) 2024 Cisco and/or its affiliates. +# Copyright (c) 2024-2025 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. @@ -26,7 +26,7 @@ __metaclass__ = type # pylint: disable=invalid-name -__copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." +__copyright__ = "Copyright (c) 2024-2025 Cisco and/or its affiliates." __author__ = "Allen Robel" import copy From baa9adb25c403e3ff1c87a0e8e0d09e7de5abefb Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Thu, 4 Dec 2025 07:33:51 -1000 Subject: [PATCH 11/14] Fix typo in docstring --- plugins/module_utils/common/maintenance_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/module_utils/common/maintenance_mode.py b/plugins/module_utils/common/maintenance_mode.py index 49fc549c0..e999b8c5c 100644 --- a/plugins/module_utils/common/maintenance_mode.py +++ b/plugins/module_utils/common/maintenance_mode.py @@ -45,7 +45,7 @@ class MaintenanceMode: - `config` property setter: config contains invalid content. - `commit()`: config, rest_send, or results are not set. - `commit()`: `EpMaintenanceModeEnable` or `EpMaintenanceModeDisable` raise `ValueError`. - - `commit()`: either `chance_system_mode()` or `deploy_switches()` raise `ControllerResponseError`. + - `commit()`: either `change_system_mode()` or `deploy_switches()` raise `ControllerResponseError`. ### TypeError From f5ee6ca8e36ef2bb32d747bc09d920527afc976d Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Thu, 4 Dec 2025 11:40:24 -1000 Subject: [PATCH 12/14] Add pylint suppression directive and module docstring 1. Suppress invalid-name for __metaclass__ 2. Add module docstring --- tests/unit/module_utils/common/common_utils.py | 7 +++++-- tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/unit/module_utils/common/common_utils.py b/tests/unit/module_utils/common/common_utils.py index ede1e1817..1c94e8800 100644 --- a/tests/unit/module_utils/common/common_utils.py +++ b/tests/unit/module_utils/common/common_utils.py @@ -1,4 +1,7 @@ -# Copyright (c) 2024 Cisco and/or its affiliates. +""" +Utility functions and fixtures for unit tests in tests/unit/module_utils/common +""" +# Copyright (c) 2024-2025 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. @@ -14,7 +17,7 @@ from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name from contextlib import contextmanager diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py index 829316ab3..2fd5a55c1 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/utils.py @@ -1,4 +1,7 @@ -# Copyright (c) 2024 Cisco and/or its affiliates. +""" +Utility functions and fixtures for dcnm_maintenance_mode unit tests +""" +# Copyright (c) 2024-2025 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. @@ -14,7 +17,7 @@ from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name from contextlib import contextmanager From 60da07fdd0ecf9d44189d64c5bd560a3c1163cfd Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Fri, 5 Dec 2025 15:06:47 -1000 Subject: [PATCH 13/14] Type hints and remove class decorators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add type hints for dcnm_maintenance_mode module and support classes. 2. Replace class decorators for RestSend and Results with local properties. - plugins/module_utils/common/maintenance_mode.py - plugins/module_utils/common/maintenance_mode_info.py - plugins/modules/dcnm_maintenance_mode.py 3. Update unit tests for the above 4. Some unit tests related to verifying Results is set are removed since they are no longer needed given that Results is instantiated in class initializers. 5. Add enums for maintenance mode values (e.g, “normal” “maintenance”). --- plugins/module_utils/common/enums.py | 111 ++++++++ .../module_utils/common/maintenance_mode.py | 249 +++++++++++------- .../common/maintenance_mode_info.py | 226 +++++++++++----- plugins/modules/dcnm_maintenance_mode.py | 147 +++++++---- .../common/test_maintenance_mode.py | 98 +++---- .../common/test_maintenance_mode_info.py | 90 ++----- .../fixtures/configs_Want.json | 26 -- .../test_dcnm_maintenance_mode_common.py | 5 +- .../test_dcnm_maintenance_mode_merged.py | 4 +- .../test_dcnm_maintenance_mode_params_spec.py | 6 +- .../test_dcnm_maintenance_mode_query.py | 5 +- .../test_dcnm_maintenance_mode_want.py | 108 +------- 12 files changed, 604 insertions(+), 471 deletions(-) create mode 100644 plugins/module_utils/common/enums.py diff --git a/plugins/module_utils/common/enums.py b/plugins/module_utils/common/enums.py new file mode 100644 index 000000000..9918f3aad --- /dev/null +++ b/plugins/module_utils/common/enums.py @@ -0,0 +1,111 @@ +""" +Common enum definitions for module utilities in module_utils/common +""" +# Copyright (c) 2025 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. + +from __future__ import absolute_import, annotations, division, print_function + +__metaclass__ = type # pylint: disable=invalid-name +__author__ = "Allen Robel" + +from enum import Enum + + +class MaintenanceModeSetEnum(str, Enum): + """ + # Summary + + Valid maintenance mode values for switches. + + These are modes that the user can set. + + ## Raises + + None + + ## Values + + - `MAINTENANCE`: Switch is in maintenance mode + - `NORMAL`: Switch is in normal operational mode + + ## See also + + MaintenanceModeGetEnum + """ + + MAINTENANCE = "maintenance" + NORMAL = "normal" + + @classmethod + def values(cls) -> list[str]: + """ + # Summary + + Return a set of valid maintenance mode values. + + ## Raises + + None + + ## Returns + + List of string values for all maintenance modes. + """ + return [mode.value for mode in cls] + + +class MaintenanceModeGetEnum(str, Enum): + """ + # Summary + + Valid maintenance mode values for switches. + + These are modes that the user can retrieve. + + ## Raises + + None + + ## Values + + - `INCONSISTENT`: A synthesized mode indicating that mode != systemMode + - `MAINTENANCE`: Switch is in maintenance mode + - `NORMAL`: Switch is in normal operational mode + + ## See also + + MaintenanceModeGetEnum + """ + + INCONSISTENT = "inconsistent" + MAINTENANCE = "maintenance" + NORMAL = "normal" + + @classmethod + def values(cls) -> list[str]: + """ + # Summary + + Return a set of valid maintenance mode values. + + ## Raises + + None + + ## Returns + + List of string values for all maintenance modes. + """ + return [mode.value for mode in cls] diff --git a/plugins/module_utils/common/maintenance_mode.py b/plugins/module_utils/common/maintenance_mode.py index e999b8c5c..8cc2dc141 100644 --- a/plugins/module_utils/common/maintenance_mode.py +++ b/plugins/module_utils/common/maintenance_mode.py @@ -1,3 +1,6 @@ +""" +Modify the maintenance mode state of switches and optionally deploy the changes +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -11,26 +14,24 @@ # 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 __future__ import absolute_import, division, print_function +from __future__ import absolute_import, annotations, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __author__ = "Allen Robel" -# Required for class decorators -# pylint: disable=no-member - import copy import inspect import logging +from typing import Any, Literal -from .api.v1.lan_fabric.rest.control.fabrics.fabrics import EpFabricConfigDeploy, EpMaintenanceModeDeploy, EpMaintenanceModeDisable, EpMaintenanceModeEnable +from .api.v1.lan_fabric.rest.control.fabrics.fabrics import EpMaintenanceModeDeploy, EpMaintenanceModeDisable, EpMaintenanceModeEnable from .conversion import ConversionUtils +from .enums import MaintenanceModeSetEnum from .exceptions import ControllerResponseError -from .properties import Properties +from .rest_send_v2 import RestSend +from .results import Results -@Properties.add_rest_send -@Properties.add_results class MaintenanceMode: """ # Summary @@ -41,11 +42,12 @@ class MaintenanceMode: ### ValueError - - `__init__()`: params is missing mandatory parameters `check_mode` or `state`. + - `__init__()`: params is missing mandatory parameter `state`. - `config` property setter: config contains invalid content. - - `commit()`: config, rest_send, or results are not set. + - `commit()`: config or rest_send.params are not set. - `commit()`: `EpMaintenanceModeEnable` or `EpMaintenanceModeDisable` raise `ValueError`. - `commit()`: either `change_system_mode()` or `deploy_switches()` raise `ControllerResponseError`. + - `rest_send` property setter: rest_send.params is not set. ### TypeError @@ -107,50 +109,45 @@ class MaintenanceMode: ``` """ - def __init__(self, params): - self.class_name = self.__class__.__name__ - method_name = inspect.stack()[0][3] + def __init__(self, params: dict[str, Any]) -> None: + self.class_name: str = self.__class__.__name__ + method_name: str = inspect.stack()[0][3] - self.log = logging.getLogger(f"dcnm.{self.class_name}") + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") - self.params = params - self.action = "maintenance_mode" - self.endpoints = [] + self.params: dict[str, Any] = params + self.action: str = "maintenance_mode" + self._endpoints: list[dict[str, str]] = [] - self.check_mode = self.params.get("check_mode", None) - if self.check_mode is None: - msg = f"{self.class_name}.{method_name}: " - msg += "params is missing mandatory parameter: check_mode." - raise ValueError(msg) + self._check_mode: bool = self.params.get("check_mode", False) - self.state = self.params.get("state", None) - if self.state is None: + self.state = self.params.get("state", "") + if not self.state: msg = f"{self.class_name}.{method_name}: " msg += "params is missing mandatory parameter: state." raise ValueError(msg) # Populated in build_deploy_dict() - self.deploy_dict = {} - self.serial_number_to_ip_address = {} + self._deploy_dict: dict[str, Any] = {} + self.serial_number_to_ip_address: dict[str, str] = {} - self.valid_modes = ["maintenance", "normal"] + self._valid_modes: list[str] = MaintenanceModeSetEnum.values() - self.conversion = ConversionUtils() - self.ep_maintenance_mode_deploy = EpMaintenanceModeDeploy() - self.ep_maintenance_mode_disable = EpMaintenanceModeDisable() - self.ep_maintenance_mode_enable = EpMaintenanceModeEnable() - self.ep_fabric_config_deploy = EpFabricConfigDeploy() + self._conversion = ConversionUtils() + self._ep_maintenance_mode_deploy = EpMaintenanceModeDeploy() + self._ep_maintenance_mode_disable = EpMaintenanceModeDisable() + self._ep_maintenance_mode_enable = EpMaintenanceModeEnable() - self._config = None - self._rest_send = None - self._results = None + self._config: list[dict[str, Any]] = [] + self._rest_send: RestSend = RestSend({}) + self._results: Results = Results() msg = "ENTERED MaintenanceMode(): " - msg += f"check_mode: {self.check_mode}, " + msg += f"check_mode: {self._check_mode}, " msg += f"state: {self.state}" self.log.debug(msg) - def verify_config_parameters(self, value) -> None: + def verify_config_parameters(self, value: list[dict[str, Any]]) -> None: """ # Summary @@ -176,7 +173,7 @@ def verify_config_parameters(self, value) -> None: - verify_mode() - verify_serial_number() """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if not isinstance(value, list): msg = f"{self.class_name}.{method_name}: " msg += f"{self.class_name}.config must be a list. " @@ -194,7 +191,7 @@ def verify_config_parameters(self, value) -> None: except (TypeError, ValueError) as error: raise ValueError(error) from error - def verify_deploy(self, item) -> None: + def verify_deploy(self, item: dict[str, Any]) -> None: """ # Summary @@ -210,7 +207,7 @@ def verify_deploy(self, item) -> None: - `deploy` is not a boolean. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if item.get("deploy", None) is None: msg = f"{self.class_name}.{method_name}: " msg += "config is missing mandatory key: deploy." @@ -222,7 +219,7 @@ def verify_deploy(self, item) -> None: msg += f"value {item.get('deploy', None)}." raise TypeError(msg) - def verify_fabric_name(self, item) -> None: + def verify_fabric_name(self, item: dict[str, Any]) -> None: """ # Summary @@ -235,17 +232,17 @@ def verify_fabric_name(self, item) -> None: - `fabric_name` is not present. - `fabric_name` is not a valid fabric name. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if item.get("fabric_name", None) is None: msg = f"{self.class_name}.{method_name}: " msg += "config is missing mandatory key: fabric_name." raise ValueError(msg) try: - self.conversion.validate_fabric_name(item.get("fabric_name", None)) + self._conversion.validate_fabric_name(item.get("fabric_name", None)) except (TypeError, ValueError) as error: raise ValueError(error) from error - def verify_ip_address(self, item) -> None: + def verify_ip_address(self, item: dict[str, Any]) -> None: """ # Summary @@ -257,13 +254,13 @@ def verify_ip_address(self, item) -> None: - `ip_address` is not present. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if item.get("ip_address", None) is None: msg = f"{self.class_name}.{method_name}: " msg += "config is missing mandatory key: ip_address." raise ValueError(msg) - def verify_mode(self, item) -> None: + def verify_mode(self, item: dict[str, Any]) -> None: """ # Summary @@ -276,18 +273,18 @@ def verify_mode(self, item) -> None: - `mode` is not present. - `mode` is not one of "maintenance" or "normal". """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if item.get("mode", None) is None: msg = f"{self.class_name}.{method_name}: " msg += "config is missing mandatory key: mode." raise ValueError(msg) - if item.get("mode", None) not in self.valid_modes: + if item.get("mode", None) not in self._valid_modes: msg = f"{self.class_name}.{method_name}: " - msg += f"mode must be one of {' or '.join(self.valid_modes)}. " + msg += f"mode must be one of {' or '.join(list(self._valid_modes))}. " msg += f"Got {item.get('mode', None)}." raise ValueError(msg) - def verify_serial_number(self, item) -> None: + def verify_serial_number(self, item: dict[str, Any]) -> None: """ # Summary @@ -299,13 +296,13 @@ def verify_serial_number(self, item) -> None: - `serial_number` is not present. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if item.get("serial_number", None) is None: msg = f"{self.class_name}.{method_name}: " msg += "config is missing mandatory key: serial_number." raise ValueError(msg) - def verify_wait_for_mode_change(self, item) -> None: + def verify_wait_for_mode_change(self, item: dict[str, Any]) -> None: """ # Summary @@ -321,7 +318,7 @@ def verify_wait_for_mode_change(self, item) -> None: - `wait_for_mode_change` is not a boolean. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] if item.get("wait_for_mode_change", None) is None: msg = f"{self.class_name}.{method_name}: " msg += "config is missing mandatory key: wait_for_mode_change." @@ -344,25 +341,19 @@ def verify_commit_parameters(self) -> None: ### ValueError - `config` is not set. - - `rest_send` is not set. - - `results` is not set. + - `rest_send.params` is not set. """ - method_name = inspect.stack()[0][3] - if self.config is None: + method_name: str = inspect.stack()[0][3] + if not self.config: msg = f"{self.class_name}.{method_name}: " msg += f"{self.class_name}.config must be set " msg += "before calling commit." raise ValueError(msg) - if self.rest_send is None: + if not self.rest_send.params: msg = f"{self.class_name}.{method_name}: " msg += f"{self.class_name}.rest_send must be set " msg += "before calling commit." raise ValueError(msg) - if self.results is None: - msg = f"{self.class_name}.{method_name}: " - msg += f"{self.class_name}.results must be set " - msg += "before calling commit." - raise ValueError(msg) def commit(self) -> None: """ @@ -415,7 +406,7 @@ def change_system_mode(self) -> None: - `serial_number` is not a string. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] for item in self.config: # Build endpoint @@ -423,10 +414,10 @@ def change_system_mode(self) -> None: fabric_name = item.get("fabric_name") ip_address = item.get("ip_address") serial_number = item.get("serial_number") - if mode == "normal": - endpoint = self.ep_maintenance_mode_disable + if mode == MaintenanceModeSetEnum.NORMAL.value: + endpoint = self._ep_maintenance_mode_disable else: - endpoint = self.ep_maintenance_mode_enable + endpoint = self._ep_maintenance_mode_enable try: endpoint.fabric_name = fabric_name @@ -458,7 +449,7 @@ def change_system_mode(self) -> None: # register result try: self.results.action = "change_sytem_mode" - self.results.check_mode = self.check_mode + self.results.check_mode = self._check_mode self.results.state = self.state self.results.response_current = copy.deepcopy(self.rest_send.response_current) self.results.result_current = copy.deepcopy(self.rest_send.result_current) @@ -518,19 +509,19 @@ def build_deploy_dict(self) -> None: } ``` """ - self.deploy_dict = {} + self._deploy_dict = {} for item in self.config: fabric_name = item.get("fabric_name") serial_number = item.get("serial_number") deploy = item.get("deploy") wait_for_mode_change = item.get("wait_for_mode_change") - if fabric_name not in self.deploy_dict: - self.deploy_dict[fabric_name] = [] + if fabric_name not in self._deploy_dict: + self._deploy_dict[fabric_name] = [] item_dict = {} if deploy is True: item_dict["serial_number"] = serial_number item_dict["wait_for_mode_change"] = wait_for_mode_change - self.deploy_dict[fabric_name].append(item_dict) + self._deploy_dict[fabric_name].append(item_dict) def build_serial_number_to_ip_address(self) -> None: """ @@ -573,32 +564,32 @@ def build_endpoints(self) -> None: - endpoint configuration fails. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] endpoints = [] - for fabric_name, switches in self.deploy_dict.items(): + for fabric_name, switches in self._deploy_dict.items(): for item in switches: endpoint = {} try: - self.ep_maintenance_mode_deploy.fabric_name = fabric_name - self.ep_maintenance_mode_deploy.serial_number = item["serial_number"] - self.ep_maintenance_mode_deploy.wait_for_mode_change = item["wait_for_mode_change"] + self._ep_maintenance_mode_deploy.fabric_name = fabric_name + self._ep_maintenance_mode_deploy.serial_number = item["serial_number"] + self._ep_maintenance_mode_deploy.wait_for_mode_change = item["wait_for_mode_change"] except (KeyError, TypeError, ValueError) as error: msg = f"{self.class_name}.{method_name}: " msg += "Error resolving endpoint: " msg += f"Error details: {error}." raise ValueError(msg) from error - endpoint["path"] = self.ep_maintenance_mode_deploy.path - endpoint["verb"] = self.ep_maintenance_mode_deploy.verb - endpoint["serial_number"] = self.ep_maintenance_mode_deploy.serial_number + endpoint["path"] = self._ep_maintenance_mode_deploy.path + endpoint["verb"] = self._ep_maintenance_mode_deploy.verb + endpoint["serial_number"] = self._ep_maintenance_mode_deploy.serial_number endpoint["fabric_name"] = fabric_name endpoints.append(copy.copy(endpoint)) - self.endpoints = copy.copy(endpoints) + self._endpoints = copy.copy(endpoints) def deploy_switches(self) -> None: """ # Summary - Initiate config-deploy for the switches in `self.deploy_dict`. + Initiate config-deploy for the switches in `self._deploy_dict`. ## Raises @@ -610,7 +601,7 @@ def deploy_switches(self) -> None: - endpoint cannot be resolved. """ - method_name = inspect.stack()[0][3] + method_name: str = inspect.stack()[0][3] self.build_deploy_dict() self.build_serial_number_to_ip_address() try: @@ -621,7 +612,7 @@ def deploy_switches(self) -> None: msg += f"Error detail: {error}" raise ValueError(msg) from error - for endpoint in self.endpoints: + for endpoint in self._endpoints: # Send request self.rest_send.path = endpoint["path"] self.rest_send.verb = endpoint["verb"] @@ -641,7 +632,7 @@ def deploy_switches(self) -> None: self.results.diff_current = diff self.results.action = action - self.results.check_mode = self.check_mode + self.results.check_mode = self._check_mode self.results.state = self.state self.results.response_current = copy.deepcopy(self.rest_send.response_current) self.results.result_current = copy.deepcopy(self.rest_send.result_current) @@ -657,7 +648,7 @@ def deploy_switches(self) -> None: raise ControllerResponseError(msg) @property - def config(self) -> list: + def config(self) -> list[dict[str, Any]]: """ # Summary @@ -705,9 +696,91 @@ def config(self) -> list: return self._config @config.setter - def config(self, value): + def config(self, value: list[dict[str, Any]]) -> None: try: self.verify_config_parameters(value) except (TypeError, ValueError) as error: raise ValueError(error) from error self._config = value + + @property + def rest_send(self) -> RestSend: + """ + # Summary + + An instance of the RestSend class. + + ## Raises + + - setter: `TypeError` if the value is not an instance of RestSend. + - setter: `ValueError` if RestSend.params is not set. + + ## getter + + Return an instance of the RestSend class. + + ## setter + + Set an instance of the RestSend class. + """ + return self._rest_send + + @rest_send.setter + def rest_send(self, value: RestSend) -> None: + method_name: str = inspect.stack()[0][3] + _class_have: str = "" + _class_need: Literal["RestSend"] = "RestSend" + msg = f"{self.class_name}.{method_name}: " + msg += f"value must be an instance of {_class_need}. " + msg += f"Got value {value} of type {type(value).__name__}." + try: + _class_have = value.class_name + except AttributeError as error: + msg += f" Error detail: {error}." + raise TypeError(msg) from error + if _class_have != _class_need: + raise TypeError(msg) + if not value.params: + msg = f"{self.class_name}.{method_name}: " + msg += "RestSend.params must be set." + raise ValueError(msg) + self._rest_send = value + + @property + def results(self) -> Results: + """ + # Summary + + An instance of the Results class. + + ## Raises + + - setter: `TypeError` if the value is not an instance of Results. + + ## getter + + Return an instance of the Results class. + + ## setter + + Set an instance of the Results class. + """ + return self._results + + @results.setter + def results(self, value: Results) -> None: + method_name: str = inspect.stack()[0][3] + _class_have: str = "" + _class_need: Literal["Results"] = "Results" + msg = f"{self.class_name}.{method_name}: " + msg += f"value must be an instance of {_class_need}. " + msg += f"Got value {value} of type {type(value).__name__}." + try: + _class_have = value.class_name + except AttributeError as error: + msg += f" Error detail: {error}." + raise TypeError(msg) from error + if _class_have != _class_need: + raise TypeError(msg) + self._results = value + self._results.action = self.action diff --git a/plugins/module_utils/common/maintenance_mode_info.py b/plugins/module_utils/common/maintenance_mode_info.py index b2c1397ec..f0ae1aac0 100644 --- a/plugins/module_utils/common/maintenance_mode_info.py +++ b/plugins/module_utils/common/maintenance_mode_info.py @@ -1,3 +1,6 @@ +""" +Retrieve the maintenance mode state of switches. +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +16,7 @@ # limitations under the License. from __future__ import absolute_import, division, print_function -__metaclass__ = type +__metaclass__ = type # pylint: disable=invalid-name __author__ = "Allen Robel" # Required for class decorators @@ -22,16 +25,19 @@ import copy import inspect import logging +from typing import Any, Literal +# TODO: import fabric_details_v3 when SwitchDetails (v2) has been merged. from ..fabric.fabric_details_v2 import FabricDetailsByName from .conversion import ConversionUtils +from .enums import MaintenanceModeGetEnum from .exceptions import ControllerResponseError -from .properties import Properties +from .rest_send_v2 import RestSend +# TODO: import results_v2 when SwitchDetails (v2) has been merged. +from .results import Results +# TODO: import switch_details_v2 when SwitchDetails (v2) has been merged. from .switch_details import SwitchDetails - -@Properties.add_rest_send -@Properties.add_results class MaintenanceModeInfo: """ # Summary @@ -50,7 +56,6 @@ class MaintenanceModeInfo: - `refresh()`: `config` has not been set. - `refresh()`: `rest_send` has not been set. - - `refresh()`: `results` has not been set. ## Details @@ -125,22 +130,23 @@ class MaintenanceModeInfo: ``` """ - def __init__(self, params): + def __init__(self, params: dict[str, Any]) -> None: self.class_name = self.__class__.__name__ - self.log = logging.getLogger(f"dcnm.{self.class_name}") - self.action = "maintenance_mode_info" + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") + self.action: str = "maintenance_mode_info" - self.params = params - self.conversion = ConversionUtils() - self.fabric_details = FabricDetailsByName() - self.switch_details = SwitchDetails() + self.params: dict[str, Any] = params + self._conversion: ConversionUtils = ConversionUtils() + self._fabric_details: FabricDetailsByName = FabricDetailsByName() + self._switch_details: SwitchDetails = SwitchDetails() - self._config = None - self._filter = None - self._info = None - self._rest_send = None - self._results = None + self._config: list[str] = [] + self._filter: str = "" + self._info: dict[str, Any] = {} + self._rest_send: RestSend = RestSend(params={}) + self._results: Results = Results() + self._valid_modes: list[str] = MaintenanceModeGetEnum.values() msg = "ENTERED MaintenanceModeInfo(): " self.log.debug(msg) @@ -160,21 +166,17 @@ def verify_refresh_parameters(self) -> None: - `results` is not set. """ method_name = inspect.stack()[0][3] - if self.config is None: + if not self.config: msg = f"{self.class_name}.{method_name}: " msg += f"{self.class_name}.config must be set " msg += "before calling refresh." raise ValueError(msg) - if self.rest_send is None: + + if not self.rest_send.params: msg = f"{self.class_name}.{method_name}: " msg += f"{self.class_name}.rest_send must be set " msg += "before calling refresh." raise ValueError(msg) - if self.results is None: - msg = f"{self.class_name}.{method_name}: " - msg += f"{self.class_name}.results must be set " - msg += "before calling refresh." - raise ValueError(msg) def refresh(self): """ @@ -233,31 +235,31 @@ def refresh(self): self.verify_refresh_parameters() try: - self.switch_details.rest_send = self.rest_send - self.fabric_details.rest_send = self.rest_send + self._switch_details.rest_send = self.rest_send + self._fabric_details.rest_send = self.rest_send - self.switch_details.results = self.results - self.fabric_details.results = self.results + self._switch_details.results = self.results + self._fabric_details.results = self.results except TypeError as error: raise ValueError(error) from error try: - self.switch_details.refresh() + self._switch_details.refresh() except (ControllerResponseError, ValueError) as error: raise ValueError(error) from error try: - self.fabric_details.refresh() + self._fabric_details.refresh() except (ControllerResponseError, ValueError) as error: raise ValueError(error) from error info = {} # Populate info dict for ip_address in self.config: - self.switch_details.filter = ip_address + self._switch_details.filter = ip_address try: - serial_number = self.switch_details.serial_number + serial_number = self._switch_details.serial_number except ValueError as error: raise ValueError(error) from error @@ -269,10 +271,10 @@ def refresh(self): raise ValueError(msg) try: - fabric_name = self.switch_details.fabric_name - freeze_mode = self.switch_details.freeze_mode - mode = self.switch_details.maintenance_mode - role = self.switch_details.switch_role + fabric_name = self._switch_details.fabric_name + freeze_mode = self._switch_details.freeze_mode + mode = self._switch_details.maintenance_mode + role = self._switch_details.switch_role except ValueError as error: msg = f"{self.class_name}.{method_name}: " msg += "Error setting properties for switch with ip_address " @@ -281,11 +283,11 @@ def refresh(self): raise ValueError(msg) from error try: - self.fabric_details.filter = fabric_name + self._fabric_details.filter = fabric_name except ValueError as error: raise ValueError(error) from error - fabric_read_only = self.fabric_details.is_read_only + fabric_read_only = self._fabric_details.is_read_only info[ip_address] = {} info[ip_address].update({"fabric_name": fabric_name}) @@ -316,7 +318,7 @@ def refresh(self): self.info = copy.deepcopy(info) - def _get(self, item): + def _get(self, item: str) -> Any: """ # Summary @@ -336,22 +338,22 @@ def _get(self, item): """ method_name = inspect.stack()[0][3] - if self.filter is None: + if not self._filter: msg = f"{self.class_name}.{method_name}: " msg += "set instance.filter before accessing " msg += f"property {item}." raise ValueError(msg) - if self.filter not in self._info: + if self._filter not in self._info: msg = f"{self.class_name}.{method_name}: " - msg += f"Switch with ip_address {self.filter} does not exist on " + msg += f"Switch with ip_address {self._filter} does not exist on " msg += "the controller." raise ValueError(msg) - return self.conversion.make_boolean(self.conversion.make_none(self._info[self.filter].get(item))) + return self._conversion.make_boolean(self._conversion.make_none(self._info[self._filter].get(item))) @property - def filter(self): + def filter(self) -> str: """ # Summary @@ -376,11 +378,11 @@ def filter(self): return self._filter @filter.setter - def filter(self, value): + def filter(self, value: str) -> None: self._filter = value @property - def config(self) -> list: + def config(self) -> list[str]: """ # Summary @@ -417,7 +419,7 @@ def config(self) -> list: return self._config @config.setter - def config(self, value): + def config(self, value: list[str]) -> None: method_name = inspect.stack()[0][3] if not isinstance(value, list): msg = f"{self.class_name}.{method_name}: " @@ -437,7 +439,7 @@ def config(self, value): self._config = value @property - def fabric_deployment_disabled(self): + def fabric_deployment_disabled(self) -> bool: """ # Summary @@ -459,10 +461,13 @@ def fabric_deployment_disabled(self): - `False`: The fabric is in a state where configuration changes can be made. """ - return self._get("fabric_deployment_disabled") + value = self._get("fabric_deployment_disabled") + if value is None: + return False + return value @property - def fabric_freeze_mode(self): + def fabric_freeze_mode(self) -> bool: """ # Summary @@ -484,10 +489,13 @@ def fabric_freeze_mode(self): - `False`: The fabric is in a state where configuration changes can be made. """ - return self._get("fabric_freeze_mode") + value = self._get("fabric_freeze_mode") + if value is None: + return False + return value @property - def fabric_name(self): + def fabric_name(self) -> str: """ # Summary @@ -502,10 +510,13 @@ def fabric_name(self): - `filter` is not in the controller response. - `fabric_name` is not in the filtered switch dict. """ - return self._get("fabric_name") + value = self._get("fabric_name") + if value is None: + return "" + return value @property - def fabric_read_only(self): + def fabric_read_only(self) -> bool: """ # Summary @@ -527,10 +538,13 @@ def fabric_read_only(self): - `False`: The fabric is in a state where configuration changes can be made. """ - return self._get("fabric_read_only") + value = self._get("fabric_read_only") + if value is None: + return False + return value @property - def info(self) -> dict: + def info(self) -> dict[str, Any]: """ # Summary @@ -597,7 +611,7 @@ def info(self) -> dict: ``` """ method_name = inspect.stack()[0][3] - if self._info is None: + if not self._info: msg = f"{self.class_name}.{method_name}: " msg += f"{self.class_name}.refresh() must be called before " msg += f"accessing {self.class_name}.{method_name}." @@ -605,7 +619,7 @@ def info(self) -> dict: return copy.deepcopy(self._info) @info.setter - def info(self, value: dict): + def info(self, value: dict[str, Any]) -> None: if not isinstance(value, dict): msg = f"{self.class_name}.info.setter: " msg += "value must be a dict. " @@ -627,8 +641,100 @@ def mode(self): - `filter` is not set. - `filter` is not in the controller response. - `mode` is not in the filtered switch dict. + + ## Example values + + - `maintenance` + - `normal` + """ + value = self._get("mode") + if value not in self._valid_modes: + msg = f"{self.class_name}.mode: " + msg += f"Invalid mode value: {value}." + raise ValueError(msg) + return value + + @property + def rest_send(self) -> RestSend: + """ + # Summary + + An instance of the RestSend class. + + ## Raises + + - setter: `TypeError` if the value is not an instance of RestSend. + - setter: `ValueError` if RestSend.params is not set. + + ## getter + + Return an instance of the RestSend class. + + ## setter + + Set an instance of the RestSend class. + """ + return self._rest_send + + @rest_send.setter + def rest_send(self, value: RestSend) -> None: + method_name: str = inspect.stack()[0][3] + _class_have: str = "" + _class_need: Literal["RestSend"] = "RestSend" + msg = f"{self.class_name}.{method_name}: " + msg += f"value must be an instance of {_class_need}. " + msg += f"Got value {value} of type {type(value).__name__}." + try: + _class_have = value.class_name + except AttributeError as error: + msg += f" Error detail: {error}." + raise TypeError(msg) from error + if _class_have != _class_need: + raise TypeError(msg) + if not value.params: + msg = f"{self.class_name}.{method_name}: " + msg += "RestSend.params must be set." + raise ValueError(msg) + self._rest_send = value + + @property + def results(self) -> Results: + """ + # Summary + + An instance of the Results class. + + ## Raises + + - setter: `TypeError` if the value is not an instance of Results. + + ## getter + + Return an instance of the Results class. + + ## setter + + Set an instance of the Results class. """ - return self._get("mode") + return self._results + + @results.setter + def results(self, value: Results) -> None: + method_name: str = inspect.stack()[0][3] + _class_have: str = "" + _class_need: Literal["Results"] = "Results" + msg = f"{self.class_name}.{method_name}: " + msg += f"value must be an instance of {_class_need}. " + msg += f"Got value {value} of type {type(value).__name__}." + try: + _class_have = value.class_name + except AttributeError as error: + msg += f" Error detail: {error}." + raise TypeError(msg) from error + if _class_have != _class_need: + raise TypeError(msg) + self._results = value + self._results.action = self.action @property def role(self): diff --git a/plugins/modules/dcnm_maintenance_mode.py b/plugins/modules/dcnm_maintenance_mode.py index 1b7aa227e..add560ab7 100644 --- a/plugins/modules/dcnm_maintenance_mode.py +++ b/plugins/modules/dcnm_maintenance_mode.py @@ -18,8 +18,8 @@ # limitations under the License. # pylint: disable=too-many-lines -from __future__ import absolute_import, division, print_function -from typing import Any +from __future__ import absolute_import, annotations, division, print_function +from typing import Any, Literal __metaclass__ = type # pylint: disable=invalid-name __author__ = "Allen Robel" @@ -161,7 +161,6 @@ from ..module_utils.common.merge_dicts_v2 import MergeDicts from ..module_utils.common.params_merge_defaults_v2 import ParamsMergeDefaults from ..module_utils.common.params_validate_v2 import ParamsValidate -from ..module_utils.common.properties import Properties from ..module_utils.common.response_handler import ResponseHandler from ..module_utils.common.rest_send_v2 import RestSend from ..module_utils.common.results import Results @@ -390,9 +389,7 @@ class Want: instance = Want() instance.config = playbook_config instance.params = ansible_module.params - instance.params_spec = ParamsSpec() instance.items_key = "switches" - instance.validator = ParamsValidate() instance.commit() want = instance.want except (TypeError, ValueError) as error: @@ -447,17 +444,12 @@ def generate_params_spec(self) -> None: ### ValueError - self.params is not set - - self.params_spec is not set """ # Generate the params_spec used to validate the configs if not self.params: msg = f"{self.class_name}.generate_params_spec(): " msg += "params is not set, and is required." raise ValueError(msg) - if not self.params_spec: - msg = f"{self.class_name}.generate_params_spec(): " - msg += "params_spec is not set, and is required." - raise ValueError(msg) try: self.params_spec.params = self.params @@ -524,8 +516,6 @@ def commit(self) -> None: - self.config is not set - self.item_key is not set - self.params is not set - - self.params_spec is not set - - self.validator is not set - self.params_spec raises `ValueError` - _merge_global_and_switch_configs() raises `ValueError` - merge_dicts() raises `ValueError` @@ -545,11 +535,6 @@ def commit(self) -> None: """ method_name: str = inspect.stack()[0][3] - if self._validator is None: - msg = f"{self.class_name}.{method_name}: " - msg += f"self.validator must be set before calling {method_name}." - raise ValueError(msg) - try: self.generate_params_spec() except ValueError as error: @@ -590,7 +575,7 @@ def _merge_global_and_item_configs(self) -> None: ### ValueError - self.config is not set - - self.items_key is not set + - self._items_key is not set - playbook is missing list of items - merge_dicts raises `ValueError` @@ -611,23 +596,22 @@ def _merge_global_and_item_configs(self) -> None: msg = f"{self.class_name}.{method_name}: " msg += "config is not set, and is required." raise ValueError(msg) - if self.items_key is None: + if not self._items_key: msg = f"{self.class_name}.{method_name}: " msg += "items_key is not set, and is required." raise ValueError(msg) - if not self.config.get(self.items_key): + if not self.config.get(self._items_key): msg = f"{self.class_name}.{method_name}: " - msg += f"playbook is missing list of {self.items_key}." + msg += f"playbook is missing list of {self._items_key}." raise ValueError(msg) self.item_configs = [] - merged_configs = [] - for item in self.config[self.items_key]: + merged_configs: list[dict[str, Any]] = [] + for item in self.config[self._items_key]: # we need to rebuild global_config in this loop # because merge_dicts modifies it in place global_config = copy.deepcopy(self.config) - global_config.pop(self.items_key, None) - + global_config.pop(self._items_key, None) msg = f"{self.class_name}.{method_name}: " msg += "global_config: " msg += f"{json.dumps(global_config, indent=4, sort_keys=True)}" @@ -658,7 +642,7 @@ def _merge_global_and_item_configs(self) -> None: self.item_configs = copy.copy(merged_configs) @property - def config(self): + def config(self) -> dict[str, Any]: """ # Summary @@ -683,7 +667,7 @@ def config(self): return self._config @config.setter - def config(self, value) -> None: + def config(self, value: dict[str, Any]) -> None: if not isinstance(value, dict): msg = f"{self.class_name}.config.setter: " msg += "expected dict but got " @@ -727,7 +711,7 @@ def items_key(self, value: str) -> None: self._items_key = value @property - def want(self) -> list: + def want(self) -> list[dict[str, Any]]: """ # Summary @@ -740,7 +724,7 @@ def want(self) -> list: return self._want @property - def params(self) -> dict: + def params(self) -> dict[str, Any]: """ # Summary @@ -764,7 +748,7 @@ def params(self) -> dict: return self._params @params.setter - def params(self, value: dict) -> None: + def params(self, value: dict[str, Any]) -> None: """ - setter: set the params """ @@ -783,16 +767,15 @@ def params_spec(self) -> ParamsSpec: The parameter specification used to validate the playbook config. Expects value to be an instance of `ParamsSpec()`. - `params_spec` is passed to `validator` to validate the - playbook config. + `params_spec` is passed to `validator` to validate the playbook config. + + `params_spec` is optional. If not set, a default instance of `ParamsSpec()` is used. ## Raises ### TypeError - setter: - - - value is not an instance of ParamsSpec() + - setter: value is not an instance of ParamsSpec() ## Details @@ -827,13 +810,13 @@ def validator(self) -> ParamsValidate: `validator` is used to validate the playbook config. Expects value to be an instance of `ParamsValidate()`. + `validator` is optional. If not set, a default instance of `ParamsValidate()` is used. + ## Raises ### TypeError - setter: - - - value is not an instance of `ParamsValidate()` + - setter: value is not an instance of `ParamsValidate()` ## Details @@ -861,7 +844,6 @@ def validator(self, value: ParamsValidate) -> None: self._validator = value -@Properties.add_rest_send class Common: """ Common methods, properties, and resources for all states. @@ -877,8 +859,9 @@ def __init__(self, params: dict[str, Any]): ### ValueError - - `params` does not contain `state` + - `params` does not contain `check_mode` - `params` does not contain `config` + - `params` does not contain `state` ### TypeError @@ -887,11 +870,16 @@ def __init__(self, params: dict[str, Any]): self.class_name: str = self.__class__.__name__ method_name: str = inspect.stack()[0][3] - self.params = params + self.params: dict[str, Any] = params self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") - self._check_mode: bool = self.params.get("check_mode", False) + self._check_mode: bool | None = self.params.get("check_mode", None) + if self._check_mode is None: + msg = f"{self.class_name}.{method_name}: " + msg += "check_mode is required." + raise ValueError(msg) + self.state: str = self.params.get("state", "") if not self.state: msg = f"{self.class_name}.{method_name}: " @@ -899,10 +887,11 @@ def __init__(self, params: dict[str, Any]): raise ValueError(msg) self.config: dict[str, Any] = self.params.get("config", {}) - if not self.config: + if not self.config and self.state != "query": msg = f"{self.class_name}.{method_name}: " msg += "config is required." raise ValueError(msg) + if not isinstance(self.config, dict): msg = f"{self.class_name}.{method_name}: " msg += "Expected dict type for self.config. " @@ -915,6 +904,9 @@ def __init__(self, params: dict[str, Any]): self.results.state = self.state self.results.check_mode = self._check_mode + self.results.state = self.state + self.results.check_mode = self._check_mode + self.have = {} # populated in self.validate_input() self.payloads = {} @@ -954,6 +946,41 @@ def get_want(self) -> None: except (TypeError, ValueError) as error: raise ValueError(error) from error + @property + def rest_send(self) -> RestSend: + """ + # Summary + + Get/set an instance of the RestSend class. + + ## Raises + + - setter: `TypeError` if the value is not an instance of RestSend. + - setter: `ValueError` if RestSend.params is not set. + """ + return self._rest_send + + @rest_send.setter + def rest_send(self, value: RestSend) -> None: + method_name: str = inspect.stack()[0][3] + _class_have: str = "" + _class_need: Literal["RestSend"] = "RestSend" + msg = f"{self.class_name}.{method_name}: " + msg += f"value must be an instance of {_class_need}. " + msg += f"Got value {value} of type {type(value).__name__}." + try: + _class_have = value.class_name + except AttributeError as error: + msg += f" Error detail: {error}." + raise TypeError(msg) from error + if _class_have != _class_need: + raise TypeError(msg) + if not value.params: + msg = f"{self.class_name}.{method_name}: " + msg += "RestSend.params must be set." + raise ValueError(msg) + self._rest_send = value + class Merged(Common): """ @@ -972,7 +999,7 @@ class Merged(Common): - Common().__init__() raises `TypeError` """ - def __init__(self, params): + def __init__(self, params: dict[str, Any]) -> None: """ # Summary @@ -998,18 +1025,19 @@ def __init__(self, params): msg += f"Error detail: {error}" raise ValueError(msg) from error - self.log = logging.getLogger(f"dcnm.{self.class_name}") + self.log: logging.Logger = logging.getLogger(f"dcnm.{self.class_name}") - self.maintenance_mode = MaintenanceMode(params) + self.maintenance_mode: MaintenanceMode = MaintenanceMode(params) msg = f"ENTERED Merged.{method_name}: " msg += f"state: {self.state}, " msg += f"check_mode: {self._check_mode}" self.log.debug(msg) - self.need = [] + self.have: dict[str, Any] = {} + self.need: list[dict[str, Any]] = [] - def get_have(self): + def get_have(self) -> None: """ # Summary @@ -1159,7 +1187,7 @@ def fabric_deployment_disabled(self) -> None: msg += additional_info raise ValueError(msg) - def get_need(self): + def get_need(self) -> None: """ # Summary @@ -1215,7 +1243,7 @@ def get_need(self): need.update({"wait_for_mode_change": want.get("wait_for_mode_change")}) self.need.append(copy.copy(need)) - def commit(self): + def commit(self) -> None: """ # Summary @@ -1234,7 +1262,7 @@ def commit(self): msg = f"{self.class_name}.{method_name}: entered" self.log.debug(msg) - if self.rest_send is None: + if not self.rest_send.params: msg = f"{self.class_name}.{method_name}: " msg += "rest_send must be set before calling commit." raise ValueError(msg) @@ -1445,7 +1473,7 @@ def commit(self) -> None: msg = f"{self.class_name}.{method_name}: entered" self.log.debug(msg) - if self.rest_send is None: + if not self.rest_send.params: msg = f"{self.class_name}.{method_name}: " msg += "rest_send must be set before calling commit." raise ValueError(msg) @@ -1537,15 +1565,22 @@ def main(): msg = f"Unknown state {params['state']}" ansible_module.fail_json(msg) - task.results.build_final_result() + if params["state"] == "merged": + task.results.build_final_result() + final_result = task.results.final_result + failed = task.results.failed + else: + task.results.build_final_result() + final_result = task.results.final_result + failed = task.results.failed # Results().failed is a property that returns a set() # of boolean values. pylint doesn't seem to understand this so we've # disabled the unsupported-membership-test warning. - if True in task.results.failed: # pylint: disable=unsupported-membership-test + if True in failed: # pylint: disable=unsupported-membership-test msg = "Module failed." - ansible_module.fail_json(msg, **task.results.final_result) - ansible_module.exit_json(**task.results.final_result) + ansible_module.fail_json(msg, **final_result) + ansible_module.exit_json(**final_result) if __name__ == "__main__": diff --git a/tests/unit/module_utils/common/test_maintenance_mode.py b/tests/unit/module_utils/common/test_maintenance_mode.py index 55ebcfdb8..24a89ce04 100644 --- a/tests/unit/module_utils/common/test_maintenance_mode.py +++ b/tests/unit/module_utils/common/test_maintenance_mode.py @@ -1,3 +1,6 @@ +""" +Unit tests for MaintenanceMode class in module_utils/common/maintenance_mode.py +""" # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +24,7 @@ # pylint: disable=protected-access # pylint: disable=unused-argument # pylint: disable=invalid-name +# pylint: disable=too-many-lines from __future__ import absolute_import, division, print_function @@ -84,31 +88,30 @@ def test_maintenance_mode_00000(maintenance_mode) -> None: with does_not_raise(): instance = maintenance_mode - assert instance._config is None - assert instance._rest_send is None - assert instance._results is None + assert instance._config == [] + assert instance._endpoints == [] + assert instance._rest_send.class_name == "RestSend" + assert instance._rest_send.params == {} + assert instance._results.class_name == "Results" assert instance.action == "maintenance_mode" - assert instance.check_mode is False + assert instance._check_mode is False assert instance.class_name == "MaintenanceMode" - assert instance.config is None - assert instance.deploy_dict == {} - assert instance.rest_send is None - assert instance.results is None + assert instance._deploy_dict == {} assert instance.serial_number_to_ip_address == {} assert instance.state == "merged" - assert instance.valid_modes == ["maintenance", "normal"] + assert instance._valid_modes == ["maintenance", "normal"] - assert isinstance(instance.conversion, ConversionUtils) - assert isinstance(instance.ep_maintenance_mode_disable, EpMaintenanceModeDisable) - assert isinstance(instance.ep_maintenance_mode_enable, EpMaintenanceModeEnable) + assert isinstance(instance._conversion, ConversionUtils) + assert isinstance(instance._ep_maintenance_mode_disable, EpMaintenanceModeDisable) + assert isinstance(instance._ep_maintenance_mode_enable, EpMaintenanceModeEnable) def test_maintenance_mode_00010() -> None: """ # Summary - Verify `ValueError` is raised when params is missing check_mode key. + Verify check_mode is set to False when params is missing check_mode key. ## Classes and Methods @@ -116,13 +119,12 @@ def test_maintenance_mode_00010() -> None: ## Test - - `ValueError` is raised when params is missing check_mode key + - check_mode is set to False when params is missing check_mode key """ params = {"state": "merged"} - match = r"MaintenanceMode\.__init__:\s+" - match += r"params is missing mandatory parameter: check_mode\." - with pytest.raises(ValueError, match=match): - instance = MaintenanceMode(params) # pylint: disable=unused-variable + with does_not_raise(): + instance = MaintenanceMode(params) + assert instance._check_mode is False def test_maintenance_mode_00020() -> None: @@ -174,7 +176,7 @@ def test_maintenance_mode_00030(maintenance_mode) -> None: """ with does_not_raise(): instance = maintenance_mode - instance.rest_send = RestSend({}) + instance.rest_send = RestSend(params=params) instance.results = Results() match = r"MaintenanceMode\.verify_commit_parameters: " @@ -222,44 +224,6 @@ def test_maintenance_mode_00040(maintenance_mode) -> None: instance.commit() -def test_maintenance_mode_00050(maintenance_mode) -> None: - """ - # Summary - - Verify MaintenanceMode().commit() raises `ValueError` when `results` is not set. - - ## Classes and Methods - - - MaintenanceMode.__init__() - - MaintenanceMode.verify_commit_parameters() - - MaintenanceMode.commit() - - ## Code Flow - Setup - - - MaintenanceMode() is instantiated - - Other required attributes are set - - ## Code Flow - Test - - - MaintenanceMode().commit() is called without having first set MaintenanceMode().results - - ## Expected Result - - - `ValueError` is raised - - Exception message matches expected - """ - with does_not_raise(): - instance = maintenance_mode - instance.rest_send = RestSend({}) - instance.config = CONFIG - - match = r"MaintenanceMode\.verify_commit_parameters: " - match += r"MaintenanceMode\.results must be set before calling\s+" - match += r"commit\." - with pytest.raises(ValueError, match=match): - instance.commit() - - @pytest.mark.parametrize( "mock_exception, expected_exception, mock_message", [ @@ -309,7 +273,7 @@ def mock_change_system_mode(*args, **kwargs): with does_not_raise(): instance = maintenance_mode instance.config = CONFIG - instance.rest_send = RestSend({}) + instance.rest_send = RestSend(params=params) instance.results = Results() monkeypatch.setattr(instance, "change_system_mode", mock_change_system_mode) @@ -368,7 +332,7 @@ def mock_deploy_switches(*args, **kwargs): with does_not_raise(): instance = maintenance_mode instance.config = CONFIG - instance.rest_send = RestSend({}) + instance.rest_send = RestSend(params=params) instance.results = Results() monkeypatch.setattr(instance, "change_system_mode", mock_change_system_mode) @@ -926,10 +890,10 @@ def test_maintenance_mode_00700(maintenance_mode, param, raises) -> None: @pytest.mark.parametrize( "endpoint_instance, mock_exception, expected_exception, mock_message", [ - ("ep_maintenance_mode_disable", TypeError, ValueError, "Bad type"), - ("ep_maintenance_mode_disable", ValueError, ValueError, "Bad value"), - ("ep_maintenance_mode_enable", TypeError, ValueError, "Bad type"), - ("ep_maintenance_mode_enable", ValueError, ValueError, "Bad value"), + ("_ep_maintenance_mode_disable", TypeError, ValueError, "Bad type"), + ("_ep_maintenance_mode_disable", ValueError, ValueError, "Bad value"), + ("_ep_maintenance_mode_enable", TypeError, ValueError, "Bad type"), + ("_ep_maintenance_mode_enable", ValueError, ValueError, "Bad value"), ], ) def test_maintenance_mode_00800( @@ -1008,10 +972,10 @@ def serial_number(self, value): with does_not_raise(): instance = maintenance_mode config = copy.deepcopy(CONFIG[0]) - if endpoint_instance == "ep_maintenance_mode_disable": + if endpoint_instance == "_ep_maintenance_mode_disable": config["mode"] = "normal" instance.config = [config] - instance.rest_send = RestSend({}) + instance.rest_send = RestSend(params=params) instance.results = Results() monkeypatch.setattr(instance, endpoint_instance, MockEndpoint()) @@ -1022,8 +986,8 @@ def serial_number(self, value): @pytest.mark.parametrize( "endpoint_instance, mock_exception, expected_exception, mock_message", [ - ("ep_maintenance_mode_deploy", TypeError, ValueError, "Bad type"), - ("ep_maintenance_mode_deploy", ValueError, ValueError, "Bad value"), + ("_ep_maintenance_mode_deploy", TypeError, ValueError, "Bad type"), + ("_ep_maintenance_mode_deploy", ValueError, ValueError, "Bad value"), ], ) def test_maintenance_mode_00900( diff --git a/tests/unit/module_utils/common/test_maintenance_mode_info.py b/tests/unit/module_utils/common/test_maintenance_mode_info.py index 93ce78cdd..cbe7ae76a 100644 --- a/tests/unit/module_utils/common/test_maintenance_mode_info.py +++ b/tests/unit/module_utils/common/test_maintenance_mode_info.py @@ -1,4 +1,7 @@ -# Copyright (c) 2024 Cisco and/or its affiliates. +""" +Unit tests for MaintenanceModeInfo class in tests/unit/module_utils/common/maintenance_mode_info.py +""" +# Copyright (c) 2024-2025 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. @@ -21,12 +24,13 @@ # pylint: disable=protected-access # pylint: disable=unused-argument # pylint: disable=invalid-name +# pylint: disable=too-many-lines from __future__ import absolute_import, division, print_function __metaclass__ = type -__copyright__ = "Copyright (c) 2024 Cisco and/or its affiliates." +__copyright__ = "Copyright (c) 2024-2025 Cisco and/or its affiliates." __author__ = "Allen Robel" import inspect @@ -89,18 +93,15 @@ def test_maintenance_mode_info_00000(maintenance_mode_info) -> None: """ with does_not_raise(): instance = maintenance_mode_info - assert instance._config is None - assert instance._info is None - assert instance._rest_send is None - assert instance._results is None - + assert instance._config == [] + assert instance._info == {} + assert instance._rest_send.class_name == "RestSend" + assert instance._results.class_name == "Results" + assert instance._valid_modes == ["inconsistent", "maintenance", "normal"] assert instance.action == "maintenance_mode_info" assert instance.class_name == "MaintenanceModeInfo" - assert instance.config is None - assert instance.rest_send is None - assert instance.results is None - assert isinstance(instance.conversion, ConversionUtils) + assert isinstance(instance._conversion, ConversionUtils) def test_maintenance_mode_info_00100(maintenance_mode_info) -> None: @@ -141,7 +142,7 @@ def test_maintenance_mode_info_00100(maintenance_mode_info) -> None: """ with does_not_raise(): instance = maintenance_mode_info - instance.rest_send = RestSend({}) + instance.rest_send = RestSend(params=PARAMS) instance.results = Results() match = r"MaintenanceModeInfo\.verify_refresh_parameters: " @@ -198,53 +199,6 @@ def test_maintenance_mode_info_00110(maintenance_mode_info) -> None: instance.refresh() -def test_maintenance_mode_info_00120(maintenance_mode_info) -> None: - """ - # Summary - - Verify `refresh()` raises `ValueError` when `results` is not set. - - ## Classes and Methods - - - MaintenanceModeInfo.verify_refresh_parameters() - - MaintenanceModeInfo.refresh() - - ## Test - - - `ValueError` is raised. - - Exception message matches expectations. - - ## Setup - Data - - - None - - ## Setup - Code - - - `MaintenanceModeInfo()` is instantiated. - - Other required attributes are set. - - ## Trigger - - - `refresh()` is called without having first set `results`. - - ## Expected Result - - - `ValueError` is raised. - - Exception message matches expectations. - - """ - with does_not_raise(): - instance = maintenance_mode_info - instance.rest_send = RestSend({}) - instance.config = CONFIG - - match = r"MaintenanceModeInfo\.verify_refresh_parameters: " - match += r"MaintenanceModeInfo\.results must be set before calling\s+" - match += r"refresh\." - with pytest.raises(ValueError, match=match): - instance.refresh() - - @pytest.mark.parametrize( "mock_class, mock_property, mock_exception, expected_exception, mock_message", [ @@ -364,8 +318,8 @@ def responses(): mock_switch_details.mock_message = mock_message mock_switch_details.mock_property = mock_property - monkeypatch.setattr(instance, "fabric_details", mock_fabric_details) - monkeypatch.setattr(instance, "switch_details", mock_switch_details) + monkeypatch.setattr(instance, "_fabric_details", mock_fabric_details) + monkeypatch.setattr(instance, "_switch_details", mock_switch_details) with does_not_raise(): instance.config = CONFIG @@ -455,7 +409,7 @@ def responses(): mock_switch_details.mock_message = mock_message mock_switch_details.mock_property = mock_property - monkeypatch.setattr(instance, "switch_details", mock_switch_details) + monkeypatch.setattr(instance, "_switch_details", mock_switch_details) with does_not_raise(): instance.config = CONFIG @@ -709,7 +663,7 @@ def responses(): mock_fabric_details.mock_message = mock_message mock_fabric_details.mock_property = mock_property - monkeypatch.setattr(instance, "fabric_details", mock_fabric_details) + monkeypatch.setattr(instance, "_fabric_details", mock_fabric_details) with does_not_raise(): instance.config = CONFIG @@ -942,6 +896,8 @@ def responses(): instance.refresh() instance.filter = CONFIG[0] assert instance.mode == "inconsistent" + assert instance.results.response is not None + assert instance.results.result is not None assert instance.results.response[0]["DATA"][0]["mode"] == "Normal" assert instance.results.response[0]["DATA"][0]["systemMode"] == "Maintenance" assert instance.results.result[0]["success"] is True @@ -1023,6 +979,7 @@ def responses(): instance.results = Results() instance.refresh() instance.filter = CONFIG[0] + assert instance.results.result is not None assert instance.fabric_read_only is True assert instance.results.result[0]["success"] is True assert instance.results.result[1]["success"] is True @@ -1109,6 +1066,7 @@ def responses(): instance.refresh() instance.filter = CONFIG[0] assert instance.role == "na" + assert instance.results.result is not None assert instance.results.result[0]["success"] is True assert instance.results.result[1]["success"] is True assert instance.results.result[0]["found"] is True @@ -1359,7 +1317,7 @@ def test_maintenance_mode_info_00900() -> None: match += r"MaintenanceModeInfo\.config must be a list\.\s+" match += r"Got type: str\." with pytest.raises(TypeError, match=match): - instance.config = "NOT_A_LIST" + instance.config = "NOT_A_LIST" # type: ignore[arg-type] def test_maintenance_mode_info_00910() -> None: @@ -1405,7 +1363,7 @@ def test_maintenance_mode_info_00910() -> None: match += r"value contains element of type int.\s+" match += r"value:.*\." with pytest.raises(TypeError, match=match): - instance.config = ["192.168.1.1", 10, "192.168.1.2"] + instance.config = ["192.168.1.1", 10, "192.168.1.2"] # type: ignore[list-item] def test_maintenance_mode_info_01000() -> None: @@ -1569,4 +1527,4 @@ def test_maintenance_mode_info_01020() -> None: match += r"value must be a dict\.\s+" match += r"Got value NOT_A_DICT of type str\." with pytest.raises(TypeError, match=match): - instance.info = "NOT_A_DICT" + instance.info = "NOT_A_DICT" # type: ignore[assignment] diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/fixtures/configs_Want.json b/tests/unit/modules/dcnm/dcnm_maintenance_mode/fixtures/configs_Want.json index b4e233696..2b8d7a6a4 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/fixtures/configs_Want.json +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/fixtures/configs_Want.json @@ -17,19 +17,6 @@ } ] }, - "test_dcnm_maintenance_mode_want_00110a": { - "deploy": true, - "mode": "normal", - "wait_for_mode_change": true, - "switches": [ - { - "ip_address": "192.168.1.2" - }, - { - "ip_address": "192.168.1.3" - } - ] - }, "test_dcnm_maintenance_mode_want_00120a": { "deploy": true, "mode": "normal", @@ -43,19 +30,6 @@ } ] }, - "test_dcnm_maintenance_mode_want_00121a": { - "deploy": true, - "mode": "normal", - "wait_for_mode_change": true, - "switches": [ - { - "ip_address": "192.168.1.2" - }, - { - "ip_address": "192.168.1.3" - } - ] - }, "test_dcnm_maintenance_mode_want_00130a": { "deploy": true, "mode": "normal", diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py index 8510f0533..ae8bdc752 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py @@ -86,9 +86,8 @@ def test_dcnm_maintenance_mode_common_00010() -> None: """ params_test = copy.deepcopy(params) params_test.pop("check_mode", None) - instance = Common(params_test) - - assert instance._check_mode is False + with pytest.raises(ValueError, match=r"Common\.__init__: check_mode is required."): + Common(params_test) def test_dcnm_maintenance_mode_common_00020() -> None: """ diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py index 088441875..b9d03b26e 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py @@ -74,7 +74,7 @@ def test_dcnm_maintenance_mode_merged_00000() -> None: assert instance.class_name == "Merged" assert instance.log.name == "dcnm.Merged" - assert instance.check_mode is False + assert instance._check_mode is False assert instance.state == "merged" assert isinstance(instance.config, dict) @@ -89,7 +89,7 @@ def test_dcnm_maintenance_mode_merged_00000() -> None: assert instance.maintenance_mode.class_name == "MaintenanceMode" assert instance.maintenance_mode.state == "merged" - assert instance.maintenance_mode.check_mode is False + assert instance.maintenance_mode._check_mode is False assert instance.results.class_name == "Results" assert instance.results.state == "merged" diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py index a7ea359ed..dd7800875 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py @@ -58,9 +58,9 @@ def test_dcnm_maintenance_mode_params_spec_00000() -> None: with does_not_raise(): instance = ParamsSpec() assert instance.class_name == "ParamsSpec" - assert instance._params is None + assert instance._params == {} assert instance._params_spec == {} - assert instance.valid_states == ["merged", "query"] + assert instance._valid_states == ["merged", "query"] def test_dcnm_maintenance_mode_params_spec_00100() -> None: @@ -84,7 +84,7 @@ def test_dcnm_maintenance_mode_params_spec_00100() -> None: match = r"ParamsSpec\.params.setter:\s+" match += r"Invalid type\. Expected dict but got type str, value foo\." with pytest.raises(TypeError, match=match): - instance.params = params_test + instance.params = params_test # type: ignore def test_dcnm_maintenance_mode_params_spec_00110() -> None: diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py index be814015d..0e4d0fec9 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py @@ -71,7 +71,7 @@ def test_dcnm_maintenance_mode_query_00000() -> None: assert instance.class_name == "Query" assert instance.log.name == "dcnm.Query" - assert instance.check_mode is False + assert instance._check_mode is False assert instance.state == "query" assert isinstance(instance.config, dict) @@ -268,8 +268,7 @@ def test_dcnm_maintenance_mode_query_00400(monkeypatch) -> None: """ # Summary - Verify `commit()` re-raises `ValueError` when `get_want()` - raises `ValueError`. + Verify `commit()` re-raises `ValueError` when `get_want()` raises `ValueError`. ## Classes and Methods diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py index 500352185..b8146e244 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py @@ -58,11 +58,11 @@ def test_dcnm_maintenance_mode_want_00000() -> None: with does_not_raise(): instance = Want() assert instance.class_name == "Want" - assert instance._config is None - assert instance._items_key is None - assert instance._params is None - assert instance._params_spec is None - assert instance._validator is None + assert instance._config == {} + assert instance._items_key == "" + assert instance._params == {} + assert instance._params_spec.class_name == "ParamsSpec" + assert instance._validator.class_name == "ParamsValidate" assert instance._want == [] assert instance.merged_configs == [] assert instance.item_configs == [] @@ -98,8 +98,6 @@ def configs(): instance.items_key = "switches" instance.config = params_test.get("config") instance.params = params_test - instance.params_spec = ParamsSpec() - instance.validator = ParamsValidate() instance.commit() assert instance.want[0].get("deploy", None) is True assert instance.want[0].get("ip_address", None) == "192.168.1.2" @@ -111,42 +109,6 @@ def configs(): assert instance.want[1].get("wait_for_mode_change", None) is True -def test_dcnm_maintenance_mode_want_00110() -> None: - """ - # Summary - - Verify `ValueError` is raised. - - - `Want().validator` is not set prior to calling `commit()`. - - ## Classes and Methods - - - Want() - - `commit()` - """ - method_name = inspect.stack()[0][3] - key = f"{method_name}a" - - def configs(): - yield configs_want(key) - - gen = ResponseGenerator(configs()) - - params_test = copy.deepcopy(params) - params_test.update({"config": gen.next}) - - with does_not_raise(): - instance = Want() - instance.items_key = "switches" - instance.config = params_test.get("config") - instance.params = params_test - instance.params_spec = ParamsSpec() - match = r"Want\.commit:\s+" - match += r"self\.validator must be set before calling commit\." - with pytest.raises(ValueError, match=match): - instance.commit() - - def test_dcnm_maintenance_mode_want_00120() -> None: """ # Summary @@ -187,46 +149,6 @@ def configs(): instance.commit() -def test_dcnm_maintenance_mode_want_00121() -> None: - """ - # Summary - - Verify `Want().commit()` catches and re-raises `ValueError`. - - - `Want().generate_params_spec()` raises `ValueError` because - `params_spec` is not set. - - ## Classes and Methods - - - Want() - - `commit()` - """ - method_name = inspect.stack()[0][3] - key = f"{method_name}a" - - def configs(): - yield configs_want(key) - - gen = ResponseGenerator(configs()) - - params_test = copy.deepcopy(params) - params_test.update({"config": gen.next}) - - with does_not_raise(): - instance = Want() - instance.items_key = "switches" - instance.config = params_test.get("config") - instance.params = params_test - instance.validator = ParamsValidate() - match = r"Want\.commit:\s+" - match += r"Error generating params_spec\.\s+" - match += r"Error detail:\s+" - match += r"Want\.generate_params_spec\(\):\s+" - match += r"params_spec is not set, and is required\." - with pytest.raises(ValueError, match=match): - instance.commit() - - def test_dcnm_maintenance_mode_want_00130() -> None: """ # Summary @@ -296,8 +218,6 @@ def configs(): instance = Want() instance.config = params_test.get("config") instance.params = params_test - instance.params_spec = ParamsSpec() - instance.validator = ParamsValidate() match = r"Want\.commit:\s+" match += r"Error merging global and item configs\.\s+" match += r"Error detail:\s+" @@ -337,8 +257,6 @@ def configs(): instance.config = params_test.get("config") instance.items_key = "NOT_PRESENT_IN_CONFIG" instance.params = params_test - instance.params_spec = ParamsSpec() - instance.validator = ParamsValidate() match = r"Want\.commit:\s+" match += r"Error merging global and item configs\.\s+" match += r"Error detail:\s+" @@ -397,8 +315,6 @@ def commit(): instance.config = params_test.get("config") instance.items_key = "switches" instance.params = params_test - instance.params_spec = ParamsSpec() - instance.validator = ParamsValidate() match = r"Want\.commit: Error merging global and item configs\.\s+" match += r"Error detail:\s+" match += r"Want\._merge_global_and_item_configs:\s+" @@ -441,9 +357,7 @@ def mock_def(): monkeypatch.setattr(instance, "validate_configs", mock_def) instance.config = params_test.get("config") instance.params = params_test - instance.params_spec = ParamsSpec() instance.items_key = "switches" - instance.validator = ParamsValidate() match = r"Want\.commit:\s+" match += r"Error validating playbook configs against params spec\.\s+" match += r"Error detail: validate_configs ValueError\." @@ -489,7 +403,7 @@ def test_dcnm_maintenance_mode_want_00300() -> None: match = r"Want\.items_key\.setter:\s+" match += r"expected string but got set, value {'NOT_A_STRING'}\." with pytest.raises(TypeError, match=match): - instance.items_key = {"NOT_A_STRING"} + instance.items_key = {"NOT_A_STRING"} # type: ignore def test_dcnm_maintenance_mode_want_00400() -> None: @@ -525,7 +439,7 @@ def test_dcnm_maintenance_mode_want_00410() -> None: match = r"Want\.params\.setter:\s+" match += r"expected dict but got str, value NOT_A_DICT\." with pytest.raises(TypeError, match=match): - instance.params = "NOT_A_DICT" + instance.params = "NOT_A_DICT" # type: ignore def test_dcnm_maintenance_mode_want_00500() -> None: @@ -564,7 +478,7 @@ def test_dcnm_maintenance_mode_want_00510() -> None: match += r"Got type str, value NOT_AN_INSTANCE_OF_PARAMS_SPEC\.\s+" match += r"Error detail: 'str' object has no attribute 'class_name'\." with pytest.raises(TypeError, match=match): - instance.params_spec = "NOT_AN_INSTANCE_OF_PARAMS_SPEC" + instance.params_spec = "NOT_AN_INSTANCE_OF_PARAMS_SPEC" # type: ignore def test_dcnm_maintenance_mode_want_00520() -> None: @@ -587,7 +501,7 @@ def test_dcnm_maintenance_mode_want_00520() -> None: match += r"value must be an instance of ParamsSpec\.\s+" match += r"Got type ParamsValidate, value .* object at 0x.*\." with pytest.raises(TypeError, match=match): - instance.params_spec = ParamsValidate() + instance.params_spec = ParamsValidate() # type: ignore def test_dcnm_maintenance_mode_want_00600() -> None: @@ -626,7 +540,7 @@ def test_dcnm_maintenance_mode_want_00610() -> None: match += r"Got type str, value NOT_AN_INSTANCE_OF_PARAMS_VALIDATE\.\s+" match += r"Error detail: 'str' object has no attribute 'class_name'\." with pytest.raises(TypeError, match=match): - instance.validator = "NOT_AN_INSTANCE_OF_PARAMS_VALIDATE" + instance.validator = "NOT_AN_INSTANCE_OF_PARAMS_VALIDATE" # type: ignore def test_dcnm_maintenance_mode_want_00620() -> None: @@ -649,4 +563,4 @@ def test_dcnm_maintenance_mode_want_00620() -> None: match += r"value must be an instance of ParamsValidate\.\s+" match += r"Got type ParamsSpec, value .* object at 0x.*\." with pytest.raises(TypeError, match=match): - instance.validator = ParamsSpec() + instance.validator = ParamsSpec() # type: ignore From 71db70594ef7c35909a44ba846a42bf46f65721c Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Fri, 5 Dec 2025 15:22:48 -1000 Subject: [PATCH 14/14] Appease linters 1. Add blank lines where linters prefer them. 2. Move import after DOCUMENTATION. --- plugins/module_utils/common/maintenance_mode.py | 1 + plugins/module_utils/common/maintenance_mode_info.py | 3 +++ plugins/modules/dcnm_maintenance_mode.py | 4 ++-- .../test_dcnm_maintenance_mode_common.py | 2 ++ .../test_dcnm_maintenance_mode_merged.py | 1 + .../test_dcnm_maintenance_mode_params_spec.py | 1 + .../dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py | 1 + .../dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py | 1 + 8 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/common/maintenance_mode.py b/plugins/module_utils/common/maintenance_mode.py index 8cc2dc141..d0bf0a4c5 100644 --- a/plugins/module_utils/common/maintenance_mode.py +++ b/plugins/module_utils/common/maintenance_mode.py @@ -1,6 +1,7 @@ """ Modify the maintenance mode state of switches and optionally deploy the changes """ + # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/plugins/module_utils/common/maintenance_mode_info.py b/plugins/module_utils/common/maintenance_mode_info.py index f0ae1aac0..2bdf83b8e 100644 --- a/plugins/module_utils/common/maintenance_mode_info.py +++ b/plugins/module_utils/common/maintenance_mode_info.py @@ -33,11 +33,14 @@ from .enums import MaintenanceModeGetEnum from .exceptions import ControllerResponseError from .rest_send_v2 import RestSend + # TODO: import results_v2 when SwitchDetails (v2) has been merged. from .results import Results + # TODO: import switch_details_v2 when SwitchDetails (v2) has been merged. from .switch_details import SwitchDetails + class MaintenanceModeInfo: """ # Summary diff --git a/plugins/modules/dcnm_maintenance_mode.py b/plugins/modules/dcnm_maintenance_mode.py index add560ab7..4c44deaeb 100644 --- a/plugins/modules/dcnm_maintenance_mode.py +++ b/plugins/modules/dcnm_maintenance_mode.py @@ -19,7 +19,6 @@ # pylint: disable=too-many-lines from __future__ import absolute_import, annotations, division, print_function -from typing import Any, Literal __metaclass__ = type # pylint: disable=invalid-name __author__ = "Allen Robel" @@ -152,6 +151,7 @@ import inspect import json import logging +from typing import Any, Literal from ansible.module_utils.basic import AnsibleModule @@ -173,6 +173,7 @@ def json_pretty(msg): """ return json.dumps(msg, indent=4, sort_keys=True) + class ParamsSpec: """ # Summary @@ -252,7 +253,6 @@ def commit(self) -> None: msg += f"Invalid state {self.params.get('state')}." raise ValueError(msg) - def _build_params_spec_for_merged_state(self) -> None: """ # Summary diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py index ae8bdc752..c277c4894 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_common.py @@ -1,6 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Common class """ + # Copyright (c) 2024 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -89,6 +90,7 @@ def test_dcnm_maintenance_mode_common_00010() -> None: with pytest.raises(ValueError, match=r"Common\.__init__: check_mode is required."): Common(params_test) + def test_dcnm_maintenance_mode_common_00020() -> None: """ # Summary diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py index b9d03b26e..bcf4eb788 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_merged.py @@ -1,6 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Merged class. """ + # Copyright (c) 2024-2025 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py index dd7800875..04b94444a 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_params_spec.py @@ -1,6 +1,7 @@ """ Unit tests for dcnm_maintenance_mode ParamsSpec class. """ + # Copyright (c) 2024-2025 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py index 0e4d0fec9..cf28c1012 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_query.py @@ -1,6 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Query class. """ + # Copyright (c) 2024-2025 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py index b8146e244..f1300bbc0 100644 --- a/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py +++ b/tests/unit/modules/dcnm/dcnm_maintenance_mode/test_dcnm_maintenance_mode_want.py @@ -1,6 +1,7 @@ """ Unit tests for dcnm_maintenance_mode Want class. """ + # Copyright (c) 2024-2025 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License");