summaryrefslogtreecommitdiffstats
path: root/ansible_collections/dellemc/openmanage/tests/unit/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-05 16:18:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-05 16:18:34 +0000
commit3667197efb7b18ec842efd504785965911f8ac4b (patch)
tree0b986a4bc6879d080b100666a97cdabbc9ca1f28 /ansible_collections/dellemc/openmanage/tests/unit/plugins
parentAdding upstream version 9.5.1+dfsg. (diff)
downloadansible-upstream/10.0.0+dfsg.tar.xz
ansible-upstream/10.0.0+dfsg.zip
Adding upstream version 10.0.0+dfsg.upstream/10.0.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/dellemc/openmanage/tests/unit/plugins')
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_idrac_redfish.py6
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_ome.py4
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_redfish.py6
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_session_utils.py415
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_diagnostics.py1057
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_reset.py639
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_session.py590
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_storage_volume.py1178
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_user.py379
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_application_console_preferences.py8
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_local_access_configuration.py18
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_location.py38
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_mgmt_network.py4
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_power_settings.py155
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_quick_deploy.py4
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_devices.py8
-rw-r--r--ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_redfish_storage_volume.py161
17 files changed, 4180 insertions, 490 deletions
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_idrac_redfish.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_idrac_redfish.py
index fc3b3543d..8d83057e9 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_idrac_redfish.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_idrac_redfish.py
@@ -44,7 +44,7 @@ class TestIdracRedfishRest(object):
@pytest.fixture
def module_params(self):
- module_parameters = {'idrac_ip': '192.168.0.1', 'idrac_user': 'username',
+ module_parameters = {'idrac_ip': 'xxx.xxx.x.x', 'idrac_user': 'username',
'idrac_password': 'password', 'idrac_port': '443'}
return module_parameters
@@ -125,7 +125,7 @@ class TestIdracRedfishRest(object):
])
def test_build_url(self, query_params, mocker, idrac_redfish_object):
"""builds complete url"""
- base_uri = 'https://192.168.0.1:443/api'
+ base_uri = 'https://xxx.xxx.x.x:443/api'
path = "/AccountService/Accounts"
mocker.patch(MODULE_UTIL_PATH + 'idrac_redfish.iDRACRedfishAPI._get_url',
return_value=base_uri + path)
@@ -137,7 +137,7 @@ class TestIdracRedfishRest(object):
def test_build_url_none(self, mocker, idrac_redfish_object):
"""builds complete url"""
- base_uri = 'https://192.168.0.1:443/api'
+ base_uri = 'https://xxx.xxx.x.x:443/api'
mocker.patch(MODULE_UTIL_PATH + 'redfish.Redfish._get_base_url',
return_value=base_uri)
url = idrac_redfish_object._build_url("", None)
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_ome.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_ome.py
index 93892a744..60c5341a1 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_ome.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_ome.py
@@ -47,7 +47,7 @@ class TestOMERest(object):
@pytest.fixture
def module_params(self):
- module_parameters = {'hostname': '192.168.0.1', 'username': 'username',
+ module_parameters = {'hostname': 'xxx.xxx.x.x', 'username': 'username',
'password': 'password', "port": 443}
return module_parameters
@@ -150,7 +150,7 @@ class TestOMERest(object):
])
def test_build_url(self, query_param, mocker, module_params):
"""builds complete url"""
- base_uri = 'https://192.168.0.1:443/api'
+ base_uri = 'https://xxx.xxx.x.x:443/api'
path = "AccountService/Accounts"
mocker.patch(MODULE_UTIL_PATH + 'ome.RestOME._get_base_url',
return_value=base_uri)
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_redfish.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_redfish.py
index 2e092af15..1dd3ab8b4 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_redfish.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_redfish.py
@@ -39,7 +39,7 @@ class TestRedfishRest(object):
@pytest.fixture
def module_params(self):
- module_parameters = {'baseuri': '192.168.0.1:443', 'username': 'username',
+ module_parameters = {'baseuri': 'xxx.xxx.x.x:443', 'username': 'username',
'password': 'password'}
return module_parameters
@@ -120,7 +120,7 @@ class TestRedfishRest(object):
])
def test_build_url(self, query_params, mocker, redfish_object):
"""builds complete url"""
- base_uri = 'https://192.168.0.1:443/api'
+ base_uri = 'https://xxx.xxx.x.x:443/api'
path = "/AccountService/Accounts"
mocker.patch(MODULE_UTIL_PATH + 'redfish.Redfish._get_base_url',
return_value=base_uri)
@@ -132,7 +132,7 @@ class TestRedfishRest(object):
def test_build_url_none(self, mocker, redfish_object):
"""builds complete url"""
- base_uri = 'https://192.168.0.1:443/api'
+ base_uri = 'https://xxx.xxx.x.x:443/api'
mocker.patch(MODULE_UTIL_PATH + 'redfish.Redfish._get_base_url',
return_value=base_uri)
url = redfish_object._build_url("", None)
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_session_utils.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_session_utils.py
new file mode 100644
index 000000000..c53c81b01
--- /dev/null
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/module_utils/test_session_utils.py
@@ -0,0 +1,415 @@
+# -*- coding: utf-8 -*-
+
+#
+# Dell OpenManage Ansible Modules
+# Version 9.2.0
+# Copyright (C) 2024 Dell Inc.
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# All rights reserved. Dell, EMC, and other trademarks are trademarks of Dell Inc. or its subsidiaries.
+# Other trademarks may be trademarks of their respective owners.
+#
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import MagicMock
+from ansible.module_utils.urls import SSLValidationError
+from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
+from ansible_collections.dellemc.openmanage.plugins.module_utils.session_utils import SessionAPI, OpenURLResponse
+
+MODULE_UTIL_PATH = 'ansible_collections.dellemc.openmanage.plugins.module_utils.'
+OPEN_URL = 'session_utils.open_url'
+TEST_PATH = "/testpath"
+INVOKE_REQUEST = 'session_utils.SessionAPI.invoke_request'
+JOB_COMPLETE = 'session_utils.SessionAPI.wait_for_job_complete'
+API_TASK = '/api/tasks'
+SLEEP_TIME = 'session_utils.time.sleep'
+
+
+class TestSessionRest(object):
+ """
+ Main class for testing the SessionUtils class.
+ """
+ @pytest.fixture
+ def mock_response(self):
+ """
+ Returns a MagicMock object representing a mock HTTP response.
+
+ The mock response has the following properties:
+ - `getcode()` method returns 200
+ - `headers` property is a dictionary containing the headers of the response
+ - `getheaders()` method returns the same dictionary as `headers`
+ - `read()` method returns a JSON string representing a dictionary with a "value" key and
+ "data" as its value
+
+ :return: A MagicMock object representing a mock HTTP response.
+ :rtype: MagicMock
+ """
+ mock_response = MagicMock()
+ mock_response.getcode.return_value = 200
+ mock_response.headers = mock_response.getheaders.return_value = {
+ 'X-Auth-Token': 'token_id'}
+ mock_response.read.return_value = json.dumps({"value": "data"})
+ return mock_response
+
+ @pytest.fixture
+ def module_params(self):
+ """
+ Fixture that returns a dictionary containing module parameters.
+
+ :return: A dictionary with the following keys:
+ - 'hostname': The hostname of the module.
+ - 'username': The username for authentication.
+ - 'password': The password for authentication.
+ - 'port': The port number for the module.
+ """
+ module_parameters = {'hostname': 'xxx.xxx.x.x', 'username': 'username',
+ 'password': 'password', 'port': '443'}
+ return module_parameters
+
+ @pytest.fixture
+ def session_utils_object(self, module_params):
+ """
+ Creates a SessionAPI object using the provided `module_params` and returns it.
+
+ :param module_params: A dictionary containing the parameters for the SessionAPI object.
+ :type module_params: dict
+ :return: A SessionAPI object.
+ :rtype: SessionAPI
+ """
+ session_utils_obj = SessionAPI(module_params)
+ return session_utils_obj
+
+ def test_invoke_request_with_session(self, mock_response, mocker, module_params):
+ """
+ Test the invoke_request method of the SessionAPI class with a session.
+
+ Args:
+ mock_response (MagicMock): A mocked response object.
+ mocker (MockerFixture): A fixture for mocking objects.
+ module_params (dict): The parameters for the module.
+
+ Returns:
+ None
+
+ Assertions:
+ - Asserts that the response status code is 200.
+ - Asserts that the response JSON data is {"value": "data"}.
+ - Asserts that the response success attribute is True.
+ """
+ mocker.patch(MODULE_UTIL_PATH + OPEN_URL,
+ return_value=mock_response)
+ obj = SessionAPI(module_params)
+ response = obj.invoke_request(TEST_PATH, "GET")
+ assert response.status_code == 200
+ assert response.json_data == {"value": "data"}
+ assert response.success is True
+
+ def test_invoke_request_without_session(self, mock_response, mocker):
+ """
+ Test the `invoke_request` method of the `SessionAPI` class without using a session.
+
+ This test case mocks the `open_url` function from the `MODULE_UTIL_PATH` module to return a
+ mock response.
+ It then creates an instance of the `SessionAPI` class with mock module parameters.
+ The `invoke_request` method is called with a test path and a GET method.
+ The test asserts that the response status code is 200, the response JSON data is
+ {"value": "data"},
+ and the response success flag is True.
+
+ Parameters:
+ - mock_response (MagicMock): A mock response object to be returned by the `open_url`
+ function.
+ - mocker (MockerFixture): A fixture provided by the pytest library for mocking
+ functions.
+
+ Returns:
+ None
+ """
+ mocker.patch(MODULE_UTIL_PATH + OPEN_URL,
+ return_value=mock_response)
+ module_params = {'hostname': 'XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX', 'username':
+ 'username',
+ 'password': 'password', "port": '443'}
+ obj = SessionAPI(module_params)
+ response = obj.invoke_request(TEST_PATH, "GET")
+ assert response.status_code == 200
+ assert response.json_data == {"value": "data"}
+ assert response.success is True
+
+ def test_invoke_request_without_session_with_header(self, mock_response, mocker,
+ module_params):
+ """
+ Test the `invoke_request` method of the `SessionAPI` class when a session is not used and a
+ header is provided.
+
+ This test method mocks the `open_url` function from the `module_utils` module to return a
+ mock response object. It then creates an instance of the `SessionAPI` class with the
+ provided `module_params`. The `invoke_request` method is called with a test path, a request
+ method of "POST", and a headers dictionary containing a single key-value pair.
+
+ The test asserts that the response status code is 200, the response JSON data is
+ `{"value": "data"}`, and the response success flag is `True`.
+
+ Parameters:
+ - `mock_response` (MagicMock): A mock response object to be returned by the `open_url`
+ function.
+ - `mocker` (MockerFixture): A fixture for patching and mocking objects.
+ - `module_params` (dict): A dictionary containing the module parameters.
+
+ Returns:
+ None
+ """
+ mocker.patch(MODULE_UTIL_PATH + OPEN_URL,
+ return_value=mock_response)
+ obj = SessionAPI(module_params)
+ response = obj.invoke_request(TEST_PATH, "POST", headers={"application": "octstream"})
+ assert response.status_code == 200
+ assert response.json_data == {"value": "data"}
+ assert response.success is True
+
+ @pytest.mark.parametrize("exc", [URLError, SSLValidationError, ConnectionError])
+ def test_invoke_request_error_case_handling(self, exc, mocker, module_params):
+ """
+ Test the error handling in the `invoke_request` method of the `SessionAPI` class.
+
+ This function tests the handling of different types of exceptions that can occur during an
+ HTTP request. It uses the `pytest.mark.parametrize` decorator to run the test multiple
+ times with different exception types. The test mocks the `open_url` method of the
+ `SessionAPI` class to raise the specified exception. It then asserts that the correct
+ exception is raised when calling the `invoke_request` method.
+
+ Args:
+ exc (Exception): The exception type to test.
+ mocker (MockerFixture): The mocker fixture used for mocking dependencies.
+ module_params (dict): The parameters for the `SessionAPI` object.
+
+ Raises:
+ exc: The specified exception type if it is raised during the `invoke_request` call.
+ """
+ mocker.patch(MODULE_UTIL_PATH + OPEN_URL,
+ side_effect=exc("test"))
+ with pytest.raises(exc):
+ obj = SessionAPI(module_params)
+ obj.invoke_request(TEST_PATH, "GET")
+
+ def test_invoke_request_http_error_handling(self, mock_response, mocker, module_params):
+ """
+ Test the HTTP error handling in the `invoke_request` method of the `SessionAPI` class.
+
+ Args:
+ mock_response (Mock): A mock object representing the response from the HTTP request.
+ mocker (MockerFixture): A fixture for mocking objects.
+ module_params (dict): The parameters for the module.
+
+ Raises:
+ HTTPError: If an HTTP error occurs during the invocation of the request.
+
+ Returns:
+ None
+ """
+ open_url_mock = mocker.patch(MODULE_UTIL_PATH + OPEN_URL,
+ return_value=mock_response)
+ open_url_mock.side_effect = HTTPError('https://testhost.com/', 400,
+ 'Bad Request Error', {}, None)
+ with pytest.raises(HTTPError):
+ obj = SessionAPI(module_params)
+ obj.invoke_request(TEST_PATH, "GET")
+
+ @pytest.mark.parametrize("query_params", [
+ {"inp": {"$filter": "UserName eq 'admin'"},
+ "out": "%24filter=UserName+eq+%27admin%27"},
+ {"inp": {"$top": 1, "$skip": 2, "$filter": "JobType/Id eq 8"}, "out":
+ "%24top=1&%24skip=2&%24filter=JobType%2FId+eq+8"},
+ {"inp": {"$top": 1, "$skip": 3}, "out": "%24top=1&%24skip=3"}
+ ])
+ def test_build_url(self, query_params, mocker, session_utils_object):
+ """
+ builds complete url
+ """
+ base_uri = 'https://xxx.xxx.x.x:443/api'
+ path = "/AccountService/Accounts"
+ mocker.patch(MODULE_UTIL_PATH + 'session_utils.SessionAPI._get_url',
+ return_value=base_uri + path)
+ inp = query_params["inp"]
+ out = query_params["out"]
+ url = session_utils_object._build_url(
+ path, query_param=inp)
+ assert url == base_uri + path + "?" + out
+
+ def test_build_url_none(self, mocker, session_utils_object):
+ """
+ builds complete url
+ """
+ base_uri = 'https://xxx.xxx.x.x:443/api'
+ mocker.patch(MODULE_UTIL_PATH + 'redfish.Redfish._get_base_url',
+ return_value=base_uri)
+ url = session_utils_object._build_url("", None)
+ assert url == ""
+
+ def test_invalid_json_openurlresp(self):
+ """
+ Test the behavior when an invalid JSON string is passed to the `OpenURLResponse` object.
+
+ This test case creates an instance of the `OpenURLResponse` class with an empty dictionary
+ as the initial data.
+ Then, it sets the `body` attribute of the object to an invalid JSON string.
+ Finally, it asserts that calling the `json_data` attribute raises a `ValueError` with the
+ message "Unable to parse json".
+
+ Parameters:
+ self (TestCase): The current test case instance.
+
+ Returns:
+ None
+ """
+ obj = OpenURLResponse({})
+ obj.body = 'invalid json'
+ with pytest.raises(ValueError) as e:
+ obj.json_data
+ assert e.value.args[0] == "Unable to parse json"
+
+ def test_reason(self):
+ """
+ Test the `reason` property of the `OpenURLResponse` class.
+
+ This test case mocks the `read` method of the `obj` object to return an empty JSON string.
+ It then creates an instance of the `OpenURLResponse` class with the mocked `obj` object.
+ The `reason` property of the `OpenURLResponse` instance is then accessed and stored in the
+ `reason_ret` variable. Finally, the test asserts that the value of `reason_ret` is equal to
+ the expected value of "returning reason".
+
+ Parameters:
+ self (TestCase): The test case object.
+
+ Returns:
+ None
+ """
+ def mock_read():
+ return "{}"
+ obj = MagicMock()
+ obj.reason = "returning reason"
+ obj.read = mock_read
+ ourl = OpenURLResponse(obj)
+ reason_ret = ourl.reason
+ assert reason_ret == "returning reason"
+
+ def test_requests_ca_bundle_set(self, mocker, mock_response, session_utils_object):
+ """
+ Test if the `REQUESTS_CA_BUNDLE` environment variable is set correctly.
+
+ This function tests if the `REQUESTS_CA_BUNDLE` environment variable is set to the expected
+ value. It does this by setting the environment variable to a specific path, patching the
+ `invoke_request` method of the `session_utils_object` to return a mock response, and then
+ calling the `_get_omam_ca_env` method of the `session_utils_object`. Finally, it asserts
+ that the result of the `_get_omam_ca_env` method is equal to the expected path.
+
+ Parameters:
+ - mocker (MockerFixture): A fixture provided by the pytest library used to patch the
+ `invoke_request` method.
+ - mock_response (Mock): A mock object representing the response returned by the
+ `invoke_request` method.
+ - session_utils_object (SessionUtils): An instance of the `SessionUtils` class.
+
+ Returns:
+ None
+ """
+ os.environ["REQUESTS_CA_BUNDLE"] = "/path/to/requests_ca_bundle.pem"
+ mocker.patch(MODULE_UTIL_PATH + INVOKE_REQUEST,
+ return_value=mock_response)
+ result = session_utils_object._get_omam_ca_env()
+ assert result == "/path/to/requests_ca_bundle.pem"
+ del os.environ["REQUESTS_CA_BUNDLE"]
+
+ def test_curl_ca_bundle_set(self, mocker, mock_response, session_utils_object):
+ """
+ Test the functionality of the `curl_ca_bundle_set` method.
+
+ This test case verifies that the `curl_ca_bundle_set` method correctly sets the
+ `CURL_CA_BUNDLE` environment variable and retrieves the value using the `_get_omam_ca_env`
+ method.
+
+ Parameters:
+ - mocker (MockerFixture): A fixture provided by the pytest-mock library used to patch
+ the `invoke_request` method.
+ - mock_response (MagicMock): A mock object representing the response returned by the
+ `invoke_request` method.
+ - session_utils_object (SessionUtils): An instance of the `SessionUtils` class.
+
+ Returns:
+ None
+
+ Raises:
+ AssertionError: If the retrieved value from `_get_omam_ca_env` does not match the
+ expected value.
+
+ Note:
+ - The test case sets the `CURL_CA_BUNDLE` environment variable to
+ "/path/to/curl_ca_bundle.pem" before executing the test.
+ - The test case deletes the `CURL_CA_BUNDLE` environment variable after the test is
+ completed.
+ """
+ os.environ["CURL_CA_BUNDLE"] = "/path/to/curl_ca_bundle.pem"
+ mocker.patch(MODULE_UTIL_PATH + INVOKE_REQUEST,
+ return_value=mock_response)
+ result = session_utils_object._get_omam_ca_env()
+ assert result == "/path/to/curl_ca_bundle.pem"
+ del os.environ["CURL_CA_BUNDLE"]
+
+ def test_omam_ca_bundle_set(self, mocker, mock_response, session_utils_object):
+ """
+ Test the functionality of the `_get_omam_ca_env` method in the `SessionUtils` class.
+
+ This test case verifies that the `_get_omam_ca_env` method correctly retrieves the value of
+ the `OMAM_CA_BUNDLE` environment variable and returns it.
+
+ Parameters:
+ - mocker (MockerFixture): A fixture provided by the pytest library used for mocking
+ objects.
+ - mock_response (MagicMock): A mock object representing the response returned by the
+ `invoke_request` method.
+ - session_utils_object (SessionUtils): An instance of the `SessionUtils` class.
+
+ Returns:
+ None
+
+ Raises:
+ AssertionError: If the returned value from `_get_omam_ca_env` does not match the
+ expected value.
+
+ Side Effects:
+ - Sets the value of the `OMAM_CA_BUNDLE` environment variable to
+ "/path/to/omam_ca_bundle.pem".
+ - Deletes the `OMAM_CA_BUNDLE` environment variable after the test case is complete.
+ """
+ os.environ["OMAM_CA_BUNDLE"] = "/path/to/omam_ca_bundle.pem"
+ mocker.patch(MODULE_UTIL_PATH + INVOKE_REQUEST,
+ return_value=mock_response)
+ result = session_utils_object._get_omam_ca_env()
+ assert result == "/path/to/omam_ca_bundle.pem"
+ del os.environ["OMAM_CA_BUNDLE"]
+
+ def test_no_env_variable_set(self, mocker, mock_response, session_utils_object):
+ """
+ Test the case when no environment variable is set.
+
+ Args:
+ mocker (MockerFixture): The mocker fixture used to mock functions and objects.
+ mock_response (MagicMock): The mock response object used to simulate API responses.
+ session_utils_object (SessionUtils): The SessionUtils object under test.
+
+ Returns:
+ None
+
+ Asserts:
+ - The result of the _get_omam_ca_env() method is None.
+ """
+ mocker.patch(MODULE_UTIL_PATH + INVOKE_REQUEST,
+ return_value=mock_response)
+ result = session_utils_object._get_omam_ca_env()
+ assert result is None
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_diagnostics.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_diagnostics.py
new file mode 100644
index 000000000..987ff83d2
--- /dev/null
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_diagnostics.py
@@ -0,0 +1,1057 @@
+# -*- coding: utf-8 -*-
+
+#
+# Dell OpenManage Ansible Modules
+# Version 9.0.0
+# Copyright (C) 2024 Dell Inc. or its subsidiaries. All Rights Reserved.
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+
+from io import StringIO
+import json
+import tempfile
+
+import pytest
+from urllib.error import HTTPError, URLError
+from ansible.module_utils.urls import ConnectionError, SSLValidationError
+from ansible.module_utils._text import to_text
+from ansible_collections.dellemc.openmanage.plugins.modules import idrac_diagnostics
+from ansible_collections.dellemc.openmanage.tests.unit.plugins.modules.common import FakeAnsibleModule
+from mock import MagicMock
+from ansible_collections.dellemc.openmanage.plugins.modules.idrac_diagnostics import main
+
+MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.idrac_diagnostics.'
+MODULE_UTILS_PATH = 'ansible_collections.dellemc.openmanage.plugins.module_utils.utils.'
+
+SUCCESS_EXPORT_MSG = "Successfully exported the diagnostics."
+FAILURE_EXPORT_MSG = "Unable to copy the ePSA Diagnostics results file to the network share."
+SUCCESS_RUN_MSG = "Successfully ran the diagnostics operation."
+SUCCESS_RUN_AND_EXPORT_MSG = "Successfully ran and exported the diagnostics."
+RUNNING_RUN_MSG = "Successfully triggered the job to run diagnostics."
+ALREADY_RUN_MSG = "The diagnostics job is already present."
+INVALID_DIRECTORY_MSG = "Provided directory path '{path}' is not valid."
+NO_OPERATION_SKIP_MSG = "The operation is skipped."
+INSUFFICIENT_DIRECTORY_PERMISSION_MSG = "Provided directory path '{path}' is not writable. " \
+ "Please check if the directory has appropriate permissions"
+UNSUPPORTED_FIRMWARE_MSG = "iDRAC firmware version is not supported."
+TIMEOUT_NEGATIVE_OR_ZERO_MSG = "The parameter `job_wait_timeout` value cannot be negative or zero."
+WAIT_TIMEOUT_MSG = "The job is not complete after {0} seconds."
+START_TIME = "The specified scheduled time occurs in the past, " \
+ "provide a future time to schedule the job."
+INVALID_TIME = "The specified date and time `{0}` to schedule the diagnostics is not valid. Enter a valid date and time."
+END_START_TIME = "The end time `{0}` to schedule the diagnostics must be greater than the start time `{1}`."
+CHANGES_FOUND_MSG = "Changes found to be applied."
+NO_FILE = "The diagnostics file does not exist."
+
+PROXY_SERVER = "proxy.example.com"
+PAYLOAD_FUNC = "Diagnostics.get_payload_details"
+VALIDATE_TIME_FUNC = "RunDiagnostics._RunDiagnostics__validate_time"
+EXPORT_FUNC = "ExportDiagnostics._ExportDiagnostics__export_diagnostics"
+RUN_EXEC_FUNC = "RunDiagnostics.execute"
+MESSAGE_EXTENDED = "@Message.ExtendedInfo"
+DIAGS_ODATA = "/DiagnosticsService"
+REDFISH = "/redfish/v1"
+REDFISH_DIAGNOSTICS_URL = "/redfish/v1/diagnostics"
+REDFISH_BASE_API = '/redfish/v1/api'
+MANAGER_URI_ONE = "/redfish/v1/managers/1"
+API_ONE = "/local/action"
+EXPORT_URL_MOCK = '/redfish/v1/export_diagnostics'
+RUN_URL_MOCK = '/redfish/v1/import_diagnostics'
+API_INVOKE_MOCKER = "iDRACRedfishAPI.invoke_request"
+ODATA = "@odata.id"
+DIAGS_FILE_NAME = 'test_diagnostics.txt'
+SHARE_NAME = tempfile.gettempdir()
+IP = "X.X.X.X"
+HTTPS_PATH = "https://testhost.com"
+HTTP_ERROR = "http error message"
+APPLICATION_JSON = "application/json"
+
+
+class TestDiagnostics(FakeAnsibleModule):
+ module = idrac_diagnostics
+
+ @pytest.fixture
+ def idrac_diagnostics_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_diagnostics_mock(self, mocker, idrac_diagnostics_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_diagnostics_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_diagnostics_mock
+ return idrac_conn_mock
+
+ def test_execute(self, idrac_default_args, idrac_connection_diagnostics_mock):
+ obj = MagicMock()
+ diagnostics_obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, obj)
+ diagnostics_obj.execute()
+
+ def test_get_payload_details(self, idrac_connection_diagnostics_mock):
+ obj = MagicMock()
+ diags_obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, obj)
+ # Scenario 1: With all values
+ obj.params.get.return_value = {
+ 'ip_address': IP,
+ 'share_name': 'my_share',
+ 'username': 'my_user',
+ 'password': 'my_password',
+ 'file_name': DIAGS_FILE_NAME,
+ 'share_type': 'http',
+ 'ignore_certificate_warning': 'on',
+ 'proxy_support': 'parameters_proxy',
+ 'proxy_type': 'socks',
+ 'proxy_server': PROXY_SERVER,
+ 'proxy_port': 8080,
+ 'proxy_username': 'my_username',
+ 'proxy_password': 'my_password'
+ }
+ result = diags_obj.get_payload_details()
+ expected_result = {
+ 'IPAddress': IP,
+ 'ShareName': 'my_share',
+ 'UserName': 'my_user',
+ 'Password': 'my_password',
+ 'FileName': DIAGS_FILE_NAME,
+ 'ShareType': 'HTTP',
+ 'IgnoreCertWarning': 'On',
+ 'ProxySupport': 'ParametersProxy',
+ 'ProxyType': 'SOCKS',
+ 'ProxyServer': PROXY_SERVER,
+ 'ProxyPort': '8080',
+ 'ProxyUname': 'my_username',
+ 'ProxyPasswd': 'my_password'
+ }
+ assert result == expected_result
+
+ # Scenario 2: With no proxy values
+ obj.params.get.return_value = {
+ 'ip_address': IP,
+ 'share_name': 'my_share',
+ 'username': 'my_user',
+ 'password': 'my_password',
+ 'file_name': DIAGS_FILE_NAME,
+ 'share_type': 'http',
+ 'ignore_certificate_warning': 'on'
+ }
+ result = diags_obj.get_payload_details()
+ expected_result = {
+ 'IPAddress': IP,
+ 'ShareName': 'my_share',
+ 'UserName': 'my_user',
+ 'Password': 'my_password',
+ 'FileName': DIAGS_FILE_NAME,
+ 'ShareType': 'HTTP',
+ 'IgnoreCertWarning': 'On'
+ }
+ assert result == expected_result
+
+ # Scenario 3: With no proxy username and password values
+ obj.params.get.return_value = {
+ 'ip_address': IP,
+ 'share_name': 'my_share',
+ 'username': 'my_user',
+ 'password': 'my_password',
+ 'file_name': DIAGS_FILE_NAME,
+ 'share_type': 'http',
+ 'ignore_certificate_warning': 'on',
+ 'proxy_support': 'parameters_proxy',
+ 'proxy_type': 'socks',
+ 'proxy_server': PROXY_SERVER,
+ 'proxy_port': 8080
+ }
+ result = diags_obj.get_payload_details()
+ expected_result = {
+ 'IPAddress': IP,
+ 'ShareName': 'my_share',
+ 'UserName': 'my_user',
+ 'Password': 'my_password',
+ 'FileName': DIAGS_FILE_NAME,
+ 'ShareType': 'HTTP',
+ 'IgnoreCertWarning': 'On',
+ 'ProxySupport': 'ParametersProxy',
+ 'ProxyType': 'SOCKS',
+ 'ProxyServer': PROXY_SERVER,
+ 'ProxyPort': '8080'
+ }
+ assert result == expected_result
+
+ def test_network_share(self, idrac_connection_diagnostics_mock, idrac_default_args, mocker):
+ # Scenario 1: ShareType is LOCAL and directory is invalid
+ payload = {"FileName": DIAGS_FILE_NAME, "ShareType": "LOCAL", "ShareName": "my_share"}
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value=payload)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ diagnostics_obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ diagnostics_obj.test_network_share()
+ assert exc.value.args[0] == INVALID_DIRECTORY_MSG.format(path="my_share")
+
+ # Scenario 2: ShareType is LOCAL and directory is not writable
+ payload = {"FileName": DIAGS_FILE_NAME, "ShareType": "HTTP", "ShareName": SHARE_NAME}
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value=payload)
+ mocker.patch(MODULE_PATH + "Diagnostics.get_test_network_share_url", return_value=API_ONE)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ diagnostics_obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, f_module)
+ ob = diagnostics_obj.test_network_share()
+ assert ob is None
+
+ # Scenario 3: ShareType is not LOCAL
+ obj = MagicMock()
+ payload = {"FileName": DIAGS_FILE_NAME, "ShareType": "HTTP", "ShareName": "my_share"}
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value=payload)
+ mocker.patch(MODULE_PATH + "Diagnostics.get_test_network_share_url", return_value=API_ONE)
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ diagnostics_obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, f_module)
+ diagnostics_obj.test_network_share()
+
+ # Scenario 4: HTTP Error
+ payload = {"FileName": DIAGS_FILE_NAME, "ShareType": "HTTP", "ShareName": "my_share"}
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value=payload)
+ json_str = to_text(json.dumps({"error": {MESSAGE_EXTENDED: [
+ {
+ 'MessageId': "123",
+ "Message": "Error"
+ }
+ ]}}))
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ side_effect=HTTPError(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ diagnostics_obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ diagnostics_obj.test_network_share()
+ assert exc.value.args[0] == 'Error'
+
+ def test_get_test_network_share_url(self, idrac_connection_diagnostics_mock, idrac_default_args, mocker):
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ return_value={"Links": {"Oem": {"Dell": {"DellLCService": {ODATA: DIAGS_ODATA}}}},
+ "Actions": {"#DellLCService.TestNetworkShare": {"target": API_ONE}}})
+
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, f_module)
+ resp = obj.get_test_network_share_url()
+ assert resp == API_ONE
+
+ # Scenario 2: for error message
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, "Error"))
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ obj = self.module.Diagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ obj.get_test_network_share_url()
+ assert exc.value.args[0] == "Error"
+
+
+class TestRunDiagnostics(FakeAnsibleModule):
+ module = idrac_diagnostics
+
+ @pytest.fixture
+ def idrac_diagnostics_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_diagnostics_mock(self, mocker, idrac_diagnostics_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_diagnostics_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_diagnostics_mock
+ return idrac_conn_mock
+
+ def test_execute(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+ # Scenario 1: JobState is completed
+ job = {"JobState": "Completed"}
+ mocker.patch(MODULE_PATH + "Diagnostics.test_network_share", return_value=None)
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__get_run_diagnostics_url", return_value=None)
+ mocker.patch(MODULE_PATH + "RunDiagnostics.check_diagnostics_jobs", return_value=None)
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__run_diagnostics", return_value=obj)
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__perform_job_wait", return_value=job)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ msg, job_status, file_path = run_diagnostics_obj.execute()
+ assert msg == SUCCESS_RUN_MSG
+ assert job_status == job
+ assert file_path is None
+
+ # Scenario 2: JobState is scheduled
+ job = {"JobState": "Scheduled"}
+ idrac_default_args.update({'export': True})
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__perform_job_wait", return_value=job)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ msg, job_status, file_path = run_diagnostics_obj.execute()
+ assert msg == RUNNING_RUN_MSG
+ assert job_status == job
+ assert file_path is None
+
+ def test_run_diagnostics(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__get_run_diagnostics_url", return_value=API_ONE)
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__validate_time_format", return_value=True)
+ mocker.patch(MODULE_PATH + VALIDATE_TIME_FUNC, return_value=True)
+ mocker.patch(MODULE_PATH + "RunDiagnostics._RunDiagnostics__validate_end_time", return_value=True)
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+
+ # Scenario 1: With start and end time
+ run_params = {
+ 'run_mode': 'express',
+ 'reboot_type': 'power_cycle',
+ 'scheduled_start_time': '20240715235959',
+ 'scheduled_end_time': '20250715235959'
+ }
+ idrac_default_args.update(run_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ status = run_diagnostics_obj._RunDiagnostics__run_diagnostics()
+ assert status == obj
+
+ # Scenario 2: Without time
+ run_params = {
+ 'run_mode': 'express',
+ 'reboot_type': 'force'
+ }
+ idrac_default_args.update(run_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ status = run_diagnostics_obj._RunDiagnostics__run_diagnostics()
+ assert status == obj
+
+ # Scenario 3: With start and end time as empty
+ run_params = {
+ 'run_mode': 'express',
+ 'reboot_type': 'power_cycle',
+ 'scheduled_start_time': '',
+ 'scheduled_end_time': ''
+ }
+ idrac_default_args.update(run_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ status = run_diagnostics_obj._RunDiagnostics__run_diagnostics()
+ assert status == obj
+
+ # Scenario 4: With start time
+ run_params = {
+ 'run_mode': 'express',
+ 'reboot_type': 'power_cycle',
+ 'scheduled_start_time': '20200715235959'
+ }
+ mocker.patch(MODULE_PATH + VALIDATE_TIME_FUNC, return_value=False)
+ idrac_default_args.update(run_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ status = run_diagnostics_obj._RunDiagnostics__run_diagnostics()
+ assert status == obj
+
+ # Scenario 5: With end time
+ run_params = {
+ 'run_mode': 'express',
+ 'reboot_type': 'power_cycle',
+ 'scheduled_end_time': '20200715235959'
+ }
+ mocker.patch(MODULE_PATH + VALIDATE_TIME_FUNC, return_value=False)
+ idrac_default_args.update(run_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ status = run_diagnostics_obj._RunDiagnostics__run_diagnostics()
+ assert status == obj
+
+ def test_get_run_diagnostics_url(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ # Scenario 1: With url
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ return_value={"Links": {"Oem": {"Dell": {"DellLCService": {ODATA: DIAGS_ODATA}}}},
+ "Actions": {"#DellLCService.RunePSADiagnostics": {"target": API_ONE}}})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ run_diagnostics_obj._RunDiagnostics__get_run_diagnostics_url()
+ assert run_diagnostics_obj.run_url == API_ONE
+
+ # Scenario 2: When url is empty for Links
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ return_value={"Links": {}})
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__get_run_diagnostics_url()
+ assert exc.value.args[0] == UNSUPPORTED_FIRMWARE_MSG
+
+ # Scenario 3: For error message
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, "error"))
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__get_run_diagnostics_url()
+ assert exc.value.args[0] == "error"
+
+ def test_check_diagnostics_jobs(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ temp_list = {"Members": [{"Id": "JID_123", "JobType": "RemoteDiagnostics", "JobState": "New"}]}
+ obj.json_data = temp_list
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+
+ # Scenario 1: Check mode with job id
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj.check_diagnostics_jobs()
+ assert exc.value.args[0] == ALREADY_RUN_MSG
+
+ # Scenario 2: Check mode without job id
+ temp_list = {"Members": [{"Id": "", "JobType": "Test", "JobState": "New"}]}
+ obj.json_data = temp_list
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj.check_diagnostics_jobs()
+ assert exc.value.args[0] == CHANGES_FOUND_MSG
+
+ # Scenario 3: Normal mode with job id
+ temp_list = {"Members": [{"Id": "666", "JobType": "RemoteDiagnostics", "JobState": "New"}]}
+ obj.json_data = temp_list
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj.check_diagnostics_jobs()
+ assert exc.value.args[0] == ALREADY_RUN_MSG
+
+ # Scenario 4: Normal mode without job id
+ temp_list = {"Members": [{"Id": "", "JobType": "RemoteDiagnostics", "JobState": "New"}]}
+ obj.json_data = temp_list
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ resp = run_diagnostics_obj.check_diagnostics_jobs()
+ assert resp is None
+
+ def test_validate_job_timeout(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ # Scenario 1: Negative timeout
+ idrac_default_args.update({'job_wait': True, 'job_wait_timeout': -120})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__validate_job_timeout()
+ assert exc.value.args[0] == TIMEOUT_NEGATIVE_OR_ZERO_MSG
+
+ # Scenario 2: Valid timeout
+ idrac_default_args.update({'job_wait': True, 'job_wait_timeout': 120})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ resp = run_diagnostics_obj._RunDiagnostics__validate_job_timeout()
+ assert resp is None
+
+ def test_validate_time_format(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ idrac_default_args.update({'time': "20250715235959"})
+ # Scenario 1: Time with offset
+ time = "2024-09-14T05:59:35-05:00"
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ formatted_time = run_diagnostics_obj._RunDiagnostics__validate_time_format(time)
+ assert formatted_time == "20240914055935"
+
+ # Scenario 2: Time without offset
+ time = "20250715235959"
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ formatted_time = run_diagnostics_obj._RunDiagnostics__validate_time_format(time)
+ assert formatted_time == "20250715235959"
+
+ # Scenario 3: Invalid time
+ time = "2025"
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__validate_time_format(time)
+ assert exc.value.args[0] == INVALID_TIME.format(time)
+
+ def test_validate_time(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ resp = ("2024-09-14T05:59:35-05:00", "-05:00")
+ mocker.patch(MODULE_PATH + "get_current_time", return_value=resp)
+
+ # Scenario 1: Future time
+ idrac_default_args.update({'time': "20250715235959"})
+ time = idrac_default_args['time']
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ assert run_diagnostics_obj._RunDiagnostics__validate_time(time) is True
+
+ # Scenario 2: Past time
+ idrac_default_args.update({'time': "20230715235959"})
+ time = idrac_default_args['time']
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__validate_time(time)
+ assert exc.value.args[0] == START_TIME
+
+ def test_validate_end_time(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ # Scenario 1: start_time less than end_time
+ start_time = "20230715235959"
+ end_time = "20240715235959"
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ assert run_diagnostics_obj._RunDiagnostics__validate_end_time(start_time, end_time) is True
+
+ # Scenario 2: start_time greater than end_time
+ start_time = "20250715235959"
+ end_time = "20240715235959"
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__validate_end_time(start_time, end_time)
+ assert exc.value.args[0] == END_START_TIME.format(end_time, start_time)
+
+ def test_perform_job_wait(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ # Scenario 1: When JobState is completed
+ obj = MagicMock()
+ obj.headers = {'Location': REDFISH_BASE_API}
+ obj.json_data = {'JobState': 'Completed'}
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ mocker.patch(MODULE_PATH + "idrac_redfish_job_tracking",
+ return_value=(False, 'msg', obj.json_data, 120))
+ idrac_default_args.update({'job_wait': True, 'job_wait_timeout': 1200})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ job_dict = run_diagnostics_obj._RunDiagnostics__perform_job_wait(obj)
+ assert job_dict == obj.json_data
+
+ # Scenario 2: When wait time is less
+ obj = MagicMock()
+ obj.headers = {'Location': REDFISH_BASE_API}
+ obj.json_data = {'JobState': 'Scheduled'}
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ mocker.patch(MODULE_PATH + "idrac_redfish_job_tracking",
+ return_value=(False, 'msg', obj.json_data, 120))
+ idrac_default_args.update({'job_wait': True, 'job_wait_timeout': 10})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__perform_job_wait(obj)
+ assert exc.value.args[0] == WAIT_TIMEOUT_MSG.format(10)
+
+ # Scenario 3: When JobState is Failed
+ obj = MagicMock()
+ obj.headers = {'Location': REDFISH_BASE_API}
+ obj.json_data = {'JobState': 'Failed', 'Message': 'Job Failed'}
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ mocker.patch(MODULE_PATH + "idrac_redfish_job_tracking",
+ return_value=(True, 'msg', obj.json_data, 120))
+ idrac_default_args.update({'job_wait': True, 'job_wait_timeout': 1200})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ run_diagnostics_obj._RunDiagnostics__perform_job_wait(obj)
+ assert exc.value.args[0] == 'Job Failed'
+
+ # Scenario 4: When job_wait is False
+ obj = MagicMock()
+ obj.headers = {'Location': REDFISH_BASE_API}
+ obj.json_data = {'JobState': 'Scheduled'}
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ mocker.patch(MODULE_PATH + "idrac_redfish_job_tracking",
+ return_value=(True, 'msg', obj.json_data, 120))
+ idrac_default_args.update({'job_wait': False, 'job_wait_timeout': 1200})
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ job_dict = run_diagnostics_obj._RunDiagnostics__perform_job_wait(obj)
+ assert job_dict == obj.json_data
+
+ # Scenario 5: When there's no job uri
+ obj = MagicMock()
+ obj.headers = {'Location': ''}
+ idrac_default_args.update({'job_wait': False, 'job_wait_timeout': 1200})
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_diagnostics_obj = self.module.RunDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ job_dict = run_diagnostics_obj._RunDiagnostics__perform_job_wait(obj)
+ assert job_dict == {}
+
+
+class TestExportDiagnostics(FakeAnsibleModule):
+ module = idrac_diagnostics
+
+ @pytest.fixture
+ def idrac_diagnostics_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_diagnostics_mock(self, mocker, idrac_diagnostics_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_diagnostics_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_diagnostics_mock
+ return idrac_conn_mock
+
+ def test_execute(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.headers = {"Location": REDFISH}
+ obj.status_code = 200
+ obj.share_name = SHARE_NAME
+ obj.file_name = DIAGS_FILE_NAME
+ mocker.patch(MODULE_PATH + "Diagnostics.test_network_share", return_value=None)
+ mocker.patch(MODULE_PATH + "ExportDiagnostics._ExportDiagnostics__get_export_diagnostics_url", return_value=None)
+ mocker.patch(MODULE_PATH + "ExportDiagnostics._ExportDiagnostics__export_diagnostics_local", return_value=obj)
+
+ # Scenario 1: share_type = local
+ export_params = {'share_parameters': {'share_type': "local"}}
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ msg, job_status, file_path = export_diagnostics_obj.execute()
+ assert msg == SUCCESS_EXPORT_MSG
+ assert job_status == {}
+ assert file_path == 'None/None'
+
+ # Scenario 2: share_type = nfs
+ job = {"JobState": "Completed"}
+ export_params = {'share_parameters': {'share_type': "nfs"}}
+ mocker.patch(MODULE_PATH + "ExportDiagnostics._ExportDiagnostics__export_diagnostics_nfs", return_value=obj)
+ mocker.patch(MODULE_PATH + "ExportDiagnostics.get_job_status", return_value=job)
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ msg, job_status, file_path = export_diagnostics_obj.execute()
+ assert msg == SUCCESS_EXPORT_MSG
+ assert job_status == job
+ assert file_path == 'None/None'
+
+ # Scenario 3: Check mode
+ obj.status = 400
+ mocker.patch(MODULE_PATH + "ExportDiagnostics.perform_check_mode", return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ export_diagnostics_obj.execute()
+
+ def test_export_diagnostics_local(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ export_params = {
+ 'share_parameters': {
+ 'share_name': SHARE_NAME,
+ 'file_name': DIAGS_FILE_NAME
+ }
+ }
+ obj = MagicMock()
+ obj.status = 200
+ obj.headers = {'Location': REDFISH_BASE_API}
+ obj.filename = DIAGS_FILE_NAME
+ mocker.patch(MODULE_PATH + 'ExportDiagnostics._ExportDiagnostics__export_diagnostics', return_value=obj)
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception):
+ export_diagnostics_obj._ExportDiagnostics__export_diagnostics_local()
+
+ def test_export_diagnostics_http(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value=None)
+ mocker.patch(MODULE_PATH + EXPORT_FUNC, return_value=obj)
+ # Scenario 1: With ipv4
+ export_params = {
+ 'share_parameters': {
+ 'ip_address': IP,
+ 'file_name': 'test_diags',
+ 'share_type': 'http',
+ 'share_name': 'myshare'
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics_http()
+ assert result == obj
+
+ # Scenario 2: With ipv6
+ export_params = {
+ 'share_parameters': {
+ 'ip_address': 'XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX',
+ 'file_name': 'test_diags',
+ 'share_type': 'http',
+ 'share_name': 'myshare'
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics_http()
+ assert result == obj
+
+ def test_export_diagnostics_cifs(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value={})
+ mocker.patch(MODULE_PATH + EXPORT_FUNC, return_value=obj)
+ # Scenario 1: With workgroup
+ export_params = {
+ 'share_parameters': {
+ 'file_name': 'test_diags',
+ 'share_type': 'cifs',
+ 'share_name': 'myshare',
+ 'ignore_certificate_warning': 'off',
+ 'workgroup': 'myworkgroup'
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics_cifs()
+ assert result == obj
+
+ # Scenario 2: Without workgroup
+ export_params = {
+ 'share_parameters': {
+ 'file_name': 'test_diags',
+ 'share_type': 'cifs',
+ 'share_name': 'myshare',
+ 'ignore_certificate_warning': 'off'
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics_cifs()
+ assert result == obj
+
+ def test_export_diagnostics_nfs(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+ mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value={"UserName": "user", "Password": "password"})
+ mocker.patch(MODULE_PATH + EXPORT_FUNC, return_value=obj)
+ export_params = {
+ 'share_parameters': {
+ 'share_name': 'share',
+ 'share_type': 'nfs',
+ 'ignore_certificate_warning': 'off'
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics_nfs()
+ assert result == obj
+
+ def test_get_export_diagnostics_url(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ export_params = {
+ 'share_parameters': {
+ 'file_name': DIAGS_FILE_NAME,
+ 'share_type': 'local',
+ 'ignore_certificate_warning': 'off'
+ }
+ }
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, None))
+ # Scenario 1: With url
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ return_value={"Links": {"Oem": {"Dell": {"DellLCService": {ODATA: DIAGS_ODATA}}}},
+ "Actions": {"#DellLCService.ExportePSADiagnosticsResult": {"target": API_ONE}}})
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ export_diagnostics_obj._ExportDiagnostics__get_export_diagnostics_url()
+ assert export_diagnostics_obj.export_url == API_ONE
+
+ # Scenario 2: When url is empty
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ return_value={"Links": {}})
+ with pytest.raises(Exception) as exc:
+ export_diagnostics_obj._ExportDiagnostics__get_export_diagnostics_url()
+ assert exc.value.args[0] == UNSUPPORTED_FIRMWARE_MSG
+
+ # Scenario 3: For error message
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, "error"))
+ with pytest.raises(Exception) as exc:
+ export_diagnostics_obj._ExportDiagnostics__get_export_diagnostics_url()
+ assert exc.value.args[0] == "error"
+
+ def test_export_diagnostics(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+ payload = mocker.patch(MODULE_PATH + PAYLOAD_FUNC, return_value={})
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ mocker.patch(MODULE_PATH + "ExportDiagnostics._ExportDiagnostics__get_export_diagnostics_url", return_value=API_ONE)
+ # Scenario 1: With file name
+ export_params = {
+ 'share_parameters': {
+ 'file_name': DIAGS_FILE_NAME
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics(payload)
+ assert result == obj
+
+ # Scenario 2: Without file name
+ export_params = {
+ 'idrac_ip': IP,
+ 'share_parameters': {
+ 'file_name': ''
+ }
+ }
+ idrac_default_args.update(export_params)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ result = export_diagnostics_obj._ExportDiagnostics__export_diagnostics(payload)
+ assert result == obj
+
+ def test_get_job_status_success(self, mocker, idrac_diagnostics_mock):
+ obj = self.get_module_mock()
+ diagnostics_job_response_mock = mocker.MagicMock()
+ diagnostics_job_response_mock.headers.get.return_value = "HTTPS_PATH/job_tracking/12345"
+ mocker.patch(MODULE_PATH + "remove_key", return_value={"job_details": "mocked_job_details"})
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri", return_value=[MANAGER_URI_ONE])
+ obj_under_test = self.module.ExportDiagnostics(idrac_diagnostics_mock, obj)
+ mocker.patch(MODULE_PATH + "idrac_redfish_job_tracking", return_value=(False, "mocked_message", {"job_details": "mocked_job_details"}, 0))
+ result = obj_under_test.get_job_status(diagnostics_job_response_mock)
+ assert result == {"job_details": "mocked_job_details"}
+
+ def test_get_job_status_failure(self, mocker, idrac_diagnostics_mock):
+ obj = self.get_module_mock()
+ diagnostics_job_response_mock = mocker.MagicMock()
+ diagnostics_job_response_mock.headers.get.return_value = "HTTPS_PATH/job_tracking/12345"
+ mocker.patch(MODULE_PATH + "remove_key", return_value={"Message": "None"})
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri", return_value=[MANAGER_URI_ONE])
+ obj_under_test = self.module.ExportDiagnostics(idrac_diagnostics_mock, obj)
+ mocker.patch(MODULE_PATH + "idrac_redfish_job_tracking", return_value=(True, "None", {"Message": "None"}, 0))
+ exit_json_mock = mocker.patch.object(obj, "exit_json")
+ result = obj_under_test.get_job_status(diagnostics_job_response_mock)
+ exit_json_mock.assert_called_once_with(msg="None", failed=True, job_details={"Message": "None"})
+ assert result == {"Message": "None"}
+
+ def test_perform_check_mode(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ # Scenario 1: With status code 200
+ obj.status_code = 200
+ idrac_default_args.update({'ShareType': 'Local'})
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ export_diagnostics_obj.perform_check_mode()
+ assert exc.value.args[0] == CHANGES_FOUND_MSG
+
+ # Scenario 2: With status code 400
+ obj.status_code = 400
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ val = export_diagnostics_obj.perform_check_mode()
+ assert val is None
+
+ # Scenario 3: HTTP Error with message id SYS099
+ json_str = to_text(json.dumps({"error": {MESSAGE_EXTENDED: [
+ {
+ 'MessageId': "SYS099",
+ "Message": NO_FILE
+ }
+ ]}}))
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ side_effect=HTTPError(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ export_diagnostics_obj.perform_check_mode()
+ assert exc.value.args[0] == NO_FILE
+
+ # Scenario 4: HTTP Error without message id
+ json_str = to_text(json.dumps({"error": {MESSAGE_EXTENDED: [
+ {
+ 'MessageId': "123",
+ "Message": "error"
+ }
+ ]}}))
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER,
+ side_effect=HTTPError(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ export_diagnostics_obj = self.module.ExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ val = export_diagnostics_obj.perform_check_mode()
+ assert val is None
+
+
+class TestRunAndExportDiagnostics(FakeAnsibleModule):
+ module = idrac_diagnostics
+
+ @pytest.fixture
+ def idrac_diagnostics_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_diagnostics_mock(self, mocker, idrac_diagnostics_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_diagnostics_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_diagnostics_mock
+ return idrac_conn_mock
+
+ def test_execute(self, idrac_default_args, idrac_connection_diagnostics_mock, mocker):
+ obj = MagicMock()
+ obj.status_code = 200
+
+ def export_execute():
+ msg = SUCCESS_EXPORT_MSG
+ job_status = "None"
+ file_path = SHARE_NAME
+ return msg, job_status, file_path
+
+ # Scenario 1: When job wait is true
+ idrac_default_args.update({'job_wait': True})
+ mocker.patch(MODULE_PATH + "RunDiagnostics", return_value=obj)
+ obj.execute = export_execute
+ mocker.patch(MODULE_PATH + "ExportDiagnostics", return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_and_export_obj = self.module.RunAndExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ msg, job_status, file_path = run_and_export_obj.execute()
+ assert msg == SUCCESS_RUN_AND_EXPORT_MSG
+
+ # Scenario 2: When job wait is false
+ def run_execute():
+ msg = RUNNING_RUN_MSG
+ job_status = "None"
+ file_path = "None"
+ return msg, job_status, file_path
+
+ idrac_default_args.update({'job_wait': False})
+ obj.execute = run_execute
+ mocker.patch(MODULE_PATH + "RunDiagnostics", return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ run_obj = self.module.RunAndExportDiagnostics(idrac_connection_diagnostics_mock, f_module)
+ msg, job_status, file_path = run_obj.execute()
+ assert msg == RUNNING_RUN_MSG
+
+
+class TestDiagnosticsType(FakeAnsibleModule):
+ module = idrac_diagnostics
+
+ @pytest.fixture
+ def idrac_diagnostics_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_diagnostics_mock(self, mocker, idrac_diagnostics_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_diagnostics_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_diagnostics_mock
+ return idrac_conn_mock
+
+ def test_diagnostics_operation(self, idrac_default_args, idrac_connection_diagnostics_mock):
+ idrac_default_args.update({"run": True, "export": False})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ diags_class = self.module.DiagnosticsType.diagnostics_operation(idrac_connection_diagnostics_mock, f_module)
+ assert isinstance(diags_class, self.module.RunDiagnostics)
+
+ idrac_default_args.update({"run": False, "export": True})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ diags_class = self.module.DiagnosticsType.diagnostics_operation(idrac_connection_diagnostics_mock, f_module)
+ assert isinstance(diags_class, self.module.ExportDiagnostics)
+
+ idrac_default_args.update({"run": True, "export": True})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ diags_class = self.module.DiagnosticsType.diagnostics_operation(idrac_connection_diagnostics_mock, f_module)
+ assert isinstance(diags_class, self.module.RunAndExportDiagnostics)
+
+ idrac_default_args.update({"run": False, "export": False})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ with pytest.raises(Exception) as exc:
+ self.module.DiagnosticsType.diagnostics_operation(idrac_connection_diagnostics_mock, f_module)
+ assert exc.value.args[0] == NO_OPERATION_SKIP_MSG
+
+ @pytest.mark.parametrize("exc_type",
+ [URLError, HTTPError, SSLValidationError, ConnectionError, TypeError, ValueError])
+ def test_idrac_diagnostics_main_exception_handling_case(self, exc_type, mocker, idrac_default_args):
+ idrac_default_args.update({"run": True})
+ # Scenario 1: HTTPError with message id SYS099
+ json_str = to_text(json.dumps({"error": {MESSAGE_EXTENDED: [
+ {
+ 'MessageId': "SYS099",
+ "Message": "Error"
+ }
+ ]}}))
+ if exc_type in [HTTPError, SSLValidationError]:
+ mocker.patch(MODULE_PATH + RUN_EXEC_FUNC,
+ side_effect=exc_type(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ else:
+ mocker.patch(MODULE_PATH + RUN_EXEC_FUNC,
+ side_effect=exc_type('test'))
+ result = self._run_module(idrac_default_args)
+ if exc_type == URLError:
+ assert result['unreachable'] is True
+ assert 'msg' in result
+
+ # Scenario 2: HTTPError with message id SYS098
+ json_str = to_text(json.dumps({"error": {MESSAGE_EXTENDED: [
+ {
+ 'MessageId': "SYS098",
+ "Message": "Error"
+ }
+ ]}}))
+ if exc_type in [HTTPError, SSLValidationError]:
+ mocker.patch(MODULE_PATH + RUN_EXEC_FUNC,
+ side_effect=exc_type(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ result = self._run_module(idrac_default_args)
+ assert 'msg' in result
+
+ # Scenario 3: HTTPError with random message id
+ json_str = to_text(json.dumps({"error": {MESSAGE_EXTENDED: [
+ {
+ 'MessageId': "123",
+ "Message": "Error"
+ }
+ ]}}))
+ if exc_type in [HTTPError, SSLValidationError]:
+ mocker.patch(MODULE_PATH + RUN_EXEC_FUNC,
+ side_effect=exc_type(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ result = self._run_module(idrac_default_args)
+ assert 'msg' in result
+
+ def test_main(self, mocker):
+ module_mock = mocker.MagicMock()
+ idrac_mock = mocker.MagicMock()
+ diagnostics_mock = mocker.MagicMock()
+ diagnostics_mock.execute.return_value = (None, None, None)
+
+ mocker.patch(MODULE_PATH + 'get_argument_spec', return_value={})
+ mocker.patch(MODULE_PATH + 'idrac_auth_params', {})
+ mocker.patch(MODULE_PATH + 'AnsibleModule', return_value=module_mock)
+ mocker.patch(MODULE_PATH + 'iDRACRedfishAPI', return_value=idrac_mock)
+ mocker.patch(MODULE_PATH + 'DiagnosticsType.diagnostics_operation', return_value=diagnostics_mock)
+ main()
+ diagnostics_mock.execute.return_value = (None, None, SHARE_NAME)
+ mocker.patch(MODULE_PATH + 'DiagnosticsType.diagnostics_operation', return_value=diagnostics_mock)
+ main()
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_reset.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_reset.py
index a6fbb1d04..d8c23160e 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_reset.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_reset.py
@@ -2,94 +2,615 @@
#
# Dell OpenManage Ansible Modules
-# Version 7.0.0
-# Copyright (C) 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+# Version 9.2.0
+# Copyright (C) 2020-2024 Dell Inc. or its subsidiaries. All Rights Reserved.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
__metaclass__ = type
-import pytest
import json
-from ansible_collections.dellemc.openmanage.plugins.modules import idrac_reset
-from ansible_collections.dellemc.openmanage.tests.unit.plugins.modules.common import FakeAnsibleModule
-from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
-from ansible.module_utils.urls import ConnectionError, SSLValidationError
-from mock import MagicMock, Mock
+import pytest
from io import StringIO
from ansible.module_utils._text import to_text
+from urllib.error import HTTPError, URLError
+from ansible.module_utils.urls import ConnectionError, SSLValidationError
+from ansible_collections.dellemc.openmanage.plugins.modules import idrac_reset
+from ansible_collections.dellemc.openmanage.tests.unit.plugins.modules.common import FakeAnsibleModule
+from mock import MagicMock
+
+MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.idrac_reset.'
+MODULE_UTILS_PATH = 'ansible_collections.dellemc.openmanage.plugins.module_utils.utils.'
+
+MANAGERS_URI = "/redfish/v1/Managers"
+OEM = "Oem"
+MANUFACTURER = "Dell"
+ACTIONS = "Actions"
+IDRAC_RESET_RETRIES = 50
+LC_STATUS_CHECK_SLEEP = 30
+IDRAC_URI = "/redfish/v1/Managers/iDRAC.Embedded.1"
+IDRAC_JOB_URI = "/redfish/v1/Managers/iDRAC.Embedded.1/Jobs/{job_id}"
+RESET_TO_DEFAULT_ERROR = "{reset_to_default} is not supported. The supported values are {supported_values}. Enter the valid values and retry the operation."
+RESET_TO_DEFAULT_ERROR_MSG = "{reset_to_default} is not supported."
+CUSTOM_ERROR = "{reset_to_default} is not supported on this firmware version of iDRAC. The supported values are {supported_values}. \
+Enter the valid values and retry the operation."
+IDRAC_RESET_RESTART_SUCCESS_MSG = "iDRAC restart operation completed successfully."
+IDRAC_RESET_SUCCESS_MSG = "Successfully performed iDRAC reset."
+IDRAC_RESET_RESET_TRIGGER_MSG = "iDRAC reset operation triggered successfully."
+IDRAC_RESET_RESTART_TRIGGER_MSG = "iDRAC restart operation triggered successfully."
+INVALID_DIRECTORY_MSG = "Provided directory path '{path}' is invalid."
+FAILED_RESET_MSG = "Failed to perform the reset operation."
+RESET_UNTRACK = "iDRAC reset is in progress. Changes will apply once the iDRAC reset operation is successfully completed."
+TIMEOUT_NEGATIVE_OR_ZERO_MSG = "The value of `job_wait_timeout` parameter cannot be negative or zero. Enter the valid value and retry the operation."
+INVALID_FILE_MSG = "File extension is invalid. Supported extension for 'custom_default_file' is: .xml."
+LC_STATUS_MSG = "Lifecycle controller status check is {lc_status} after {retries} number of retries, Exiting.."
+INSUFFICIENT_DIRECTORY_PERMISSION_MSG = "Provided directory path '{path}' is not writable. Please check if the directory has appropriate permissions."
+UNSUPPORTED_LC_STATUS_MSG = "Lifecycle controller status check is not supported."
+CHANGES_NOT_FOUND = "No changes found to commit!"
+CHANGES_FOUND = "Changes found to commit!"
+MINIMUM_SUPPORTED_FIRMWARE_VERSION = "7.00.00"
+SUCCESS_STATUS = "Success"
+FAILED_STATUS = "Failed"
+STATUS_SUCCESS = [200, 202, 204]
+ERR_STATUS_CODE = [400, 404]
+RESET_KEY = "Oem.#DellManager.ResetToDefaults"
+RESTART_KEY = "#Manager.Reset"
+GET_BASE_URI_KEY = "Validation.get_base_uri"
+INVOKE_REQ_KEY = "iDRACRedfishAPI.invoke_request"
+GET_CUSTOM_DEFAULT_KEY = "CustomDefaultsDownloadURI"
+SET_CUSTOM_DEFAULT_KEY = "#DellManager.SetCustomDefaults"
+CHECK_LC_STATUS = "FactoryReset.check_lcstatus"
+RESET_ALLOWABLE_KEY = "ResetType@Redfish.AllowableValues"
+VALIDATE_RESET_OPTION_KEY = "Validation.validate_reset_options"
+FILE_PATH = "/root/custom_default_content.xml"
+CHECK_IDRAC_VERSION = "FactoryReset.is_check_idrac_latest"
+EXECUTE_KEY = "FactoryReset.execute"
+HTTP_ERROR_MSG = "http error message"
+RETURN_TYPE = "application/json"
+FILE_PATH = "abc/test"
+
+
+class TestValidation(FakeAnsibleModule):
+ module = idrac_reset
+ allowed_values = ["All", "Default", "CustomDefaults", "ResetAllWithRootDefaults"]
+ allowed_values_api = {
+ 'Actions':
+ {
+ "#Manager.Reset": {
+ "ResetType@Redfish.AllowableValues": [
+ "Test"
+ ]
+ },
+ "Oem": {
+ "#DellManager.ResetToDefaults": {
+ RESET_ALLOWABLE_KEY: [
+ "All",
+ "Default",
+ "ResetAllWithRootDefaults"
+ ]
+ }
+ }
+ },
+ "Oem": {
+ "Dell": {
+ "CustomDefaultsDownloadURI": "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/CustomDefaultsDownloadURI"
+ }
+ }
+ }
+
+ @pytest.fixture
+ def idrac_reset_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_reset_mock(self, mocker, idrac_reset_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_reset_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_reset_mock
+ return idrac_conn_mock
-from pytest import importorskip
+ def test_get_base_uri(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - when validate_and_get_first_resource_id_uri return proper uri
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(IDRAC_URI, ''))
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ data = idr_obj.get_base_uri()
+ assert data == IDRAC_URI
-importorskip("omsdk.sdkfile")
-importorskip("omsdk.sdkcreds")
+ def test_validate_reset_options(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - when key 'OEM' doesn't exist in output from invoke_request
+ obj = MagicMock()
+ obj.json_data = {'Actions': {}}
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idrac_default_args.update({"reset_to_default": 'All'})
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ allowed_values, res = idr_obj.validate_reset_options(RESET_KEY)
+ assert res is False
+
+ # Scenario - when reset_to_default is not in allowable values
+ obj.json_data = self.allowed_values_api
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idrac_default_args.update({"reset_to_default": 'CustomDefaults'})
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ allowed_values, res = idr_obj.validate_reset_options(RESET_KEY)
+ assert res is False
+
+ def test_validate_graceful_restart_option(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - when key doesn't exist in output from invoke_request
+ obj = MagicMock()
+ obj.json_data = {'Actions': {}}
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ res = idr_obj.validate_graceful_restart_option(RESTART_KEY)
+ assert res is False
-MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.'
+ # Scenario - when 'GracefulRestart is not in allowable values
+ obj.json_data = self.allowed_values_api
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ res = idr_obj.validate_graceful_restart_option(RESTART_KEY)
+ assert res is False
+ def test_validate_path(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - when custom default file path doesn't exist
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + 'os.path.exists', return_value=False)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_path(FILE_PATH)
+ assert exc.value.args[0] == INVALID_DIRECTORY_MSG.format(path=FILE_PATH)
-@pytest.fixture
-def idrac_reset_connection_mock(mocker, idrac_mock):
- idrac_connection_class_mock = mocker.patch(MODULE_PATH + 'idrac_reset.iDRACConnection')
- idrac_connection_class_mock.return_value.__enter__.return_value = idrac_mock
- return idrac_mock
+ # Scenario - when custom default file path exist but not accessible
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + 'os.path.exists', return_value=True)
+ mocker.patch(MODULE_PATH + 'os.access', return_value=False)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_path(FILE_PATH)
+ assert exc.value.args[0] == INSUFFICIENT_DIRECTORY_PERMISSION_MSG.format(path=FILE_PATH)
+ def test_validate_file_format(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - when custom default file is not in XML format
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_file_format('abc/test.json')
+ assert exc.value.args[0] == INVALID_FILE_MSG
-class TestReset(FakeAnsibleModule):
+ def test_validate_custom_option_exception_case(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ obj = MagicMock()
+ obj.json_data = self.allowed_values_api
+ json_str = to_text(json.dumps({"data": "out"}))
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + 'get_dynamic_uri', return_value=obj)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, side_effect=HTTPError("https://test.com", 404, HTTP_ERROR_MSG,
+ {"accept-type": RETURN_TYPE},
+ StringIO(json_str)))
+ idrac_default_args.update({"reset_to_default": 'CustomDefaults'})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(
+ idrac_connection_reset_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_custom_option('CustomDefaults', self.allowed_values)
+ assert exc.value.args[0] == RESET_TO_DEFAULT_ERROR.format(reset_to_default='CustomDefaults', supported_values=self.allowed_values)
+
+ def test_validate_job_wait_negative_values(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - when job_wait_timeout is negative
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY,
+ return_value=IDRAC_URI)
+ idrac_default_args.update({"wait_for_idrac": True, "job_wait_timeout": -120})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(idrac_connection_reset_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_job_timeout()
+ assert exc.value.args[0] == TIMEOUT_NEGATIVE_OR_ZERO_MSG
+
+ # Scenario - when job_wait_timeout is positive
+ idrac_default_args.update({"job_wait": True, "job_wait_timeout": 120})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.Validation(idrac_connection_reset_mock, f_module)
+ idr_obj.validate_job_timeout()
+
+
+class TestFactoryReset(FakeAnsibleModule):
module = idrac_reset
+ lc_status_api_links = {
+ "Oem": {
+ "Dell": {
+ "DellLCService": {
+ "@odata.id": "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService"
+ }
+ }
+ }
+ }
+
+ action_api_resp = {
+ "Actions": {
+ "#DellLCService.GetRemoteServicesAPIStatus": {
+ "target": "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService/Actions/DellLCService.GetRemoteServicesAPIStatus"
+ }
+ }
+ }
+
+ action_api_resp_restart = {
+ RESTART_KEY: {
+ RESET_ALLOWABLE_KEY: [
+ "GracefulRestart"
+ ],
+ "target": "/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Manager.Reset"
+ }
+ }
+
+ lc_status_invoke = {
+ "LCStatus": "Ready"
+ }
+ lc_status_invoke_not_ready = {
+ "LCStatus": "Not Initialized"
+ }
+
+ validate_allowed_values = {
+ "Actions": {
+ RESTART_KEY: {
+ RESET_ALLOWABLE_KEY: [
+ "GracefulRestart"
+ ],
+ "target": "/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Manager.Reset"
+ },
+ "#Manager.ResetToDefaults": {
+ RESET_ALLOWABLE_KEY: [
+ "ResetAll",
+ "PreserveNetworkAndUsers"
+ ],
+ "target": "/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Manager.ResetToDefaults"
+ },
+ "Oem": {
+ "#DellManager.ResetToDefaults": {
+ RESET_ALLOWABLE_KEY: [
+ "All",
+ "CustomDefaults",
+ "Default",
+ "ResetAllWithRootDefaults"
+ ],
+ "target": "/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/DellManager.ResetToDefaults"
+ },
+ "#DellManager.SetCustomDefaults": {
+ "target": "/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/DellManager.SetCustomDefaults"
+ },
+ }
+ },
+ "Oem": {
+ "Dell": {
+ "CustomDefaultsDownloadURI": "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/CustomDefaultsDownloadURI"
+ }
+ }
+ }
+
+ custom_default_content = "<SystemConfiguration Model=\"PowerEdge R7525\" ServiceTag=\"2V4TK93\">\n<Component FQDD=\"iDRAC.Embedded.1\">\n \
+ <Attribute Name=\"IPMILan.1#Enable\">Disabled</Attribute>\n </Component>\n\n</SystemConfiguration>"
@pytest.fixture
- def idrac_mock(self, mocker):
- omsdk_mock = MagicMock()
+ def idrac_reset_mock(self):
idrac_obj = MagicMock()
- omsdk_mock.config_mgr = idrac_obj
- type(idrac_obj).reset_idrac = Mock(return_value="idracreset")
return idrac_obj
@pytest.fixture
- def idrac_config_mngr_reset_mock(self, mocker):
- try:
- config_manager_obj = mocker.patch(MODULE_PATH + 'idrac_reset.config_mgr')
- except AttributeError:
- config_manager_obj = MagicMock()
+ def idrac_connection_reset_mock(self, mocker, idrac_reset_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_reset_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_reset_mock
+ return idrac_conn_mock
+
+ def test_is_check_idrac_latest(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ allowed_values = ["All", "Default", "ResetAllWithRootDefaults"]
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ res = reset_obj.is_check_idrac_latest()
+ assert res is True
+
+ def test_check_mode_output(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ # Scenario - When Reset to default is not passed and check mode is true
+ allowed_values = ["All", "Default", "ResetAllWithRootDefaults"]
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + "Validation.validate_graceful_restart_option", return_value=False)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.check_mode_output(True)
+ assert exc.value.args[0] == CHANGES_NOT_FOUND
+
+ def test_execute(self, idrac_default_args, idrac_connection_reset_mock, mocker):
+ allowed_values = ["All", "Default", "ResetAllWithRootDefaults", "CustomDefaults"]
+ allowed_values_without_cd = ["All", "Default", "ResetAllWithRootDefaults"]
+ # Scenario - When 'GracefulRestart' is not supported and iDRAC8 and check_mode True
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="2.81.81")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + "Validation.validate_graceful_restart_option", return_value=False)
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=False)
+ idrac_default_args.update({})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.execute()
+ assert exc.value.args[0] == CHANGES_NOT_FOUND
+
+ # Scenario: when success message is returned for graceful restart for IDRAC8 or IDRAC9
obj = MagicMock()
- config_manager_obj.config_mgr.return_value = obj
- config_manager_obj.config_mgr.reset_idrac().return_value = obj
- return config_manager_obj
-
- def test_main_idrac_reset_success_case01(self, idrac_reset_connection_mock, idrac_default_args, mocker):
- mocker.patch(MODULE_PATH + "idrac_reset.run_idrac_reset",
- return_value=({"Status": "Success"}, False))
- idrac_reset_connection_mock.config_mgr.reset_idrac.return_value = {"Status": "Success"}
- idrac_reset_connection_mock.config_mgr.reset_idrac.return_value = "Success"
- result = self._run_module(idrac_default_args)
- assert result == {'msg': 'Successfully performed iDRAC reset.',
- 'reset_status': ({'Status': 'Success'}, False), 'changed': False}
+ obj.status_code = 204
+ obj.json_data = self.lc_status_invoke
+
+ def mock_get_dynamic_uri_request(*args, **kwargs):
+ if len(args) > 2 and args[2] == 'Links':
+ return self.lc_status_api_links
+ elif len(args) > 2 and args[2] == 'Actions':
+ return self.action_api_resp_restart
+ return self.action_api_resp
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=True)
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, return_value=obj)
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=mock_get_dynamic_uri_request)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ msg_resp, resp = reset_obj.execute()
+ assert msg_resp['msg'] == IDRAC_RESET_SUCCESS_MSG
+
+ # Scenario: when success message reset_to_default is passed as 'Default' for idrac9 with job_wait set to True
+ obj.status_code = 200
+ obj2 = MagicMock()
+ obj3 = MagicMock()
+ obj2.json_data = self.validate_allowed_values
+ obj3.json_data = self.lc_status_invoke_not_ready
+
+ def mock_get_dynamic_uri_request(*args, **kwargs):
+ if len(args) > 2 and args[2] == 'Links':
+ return self.lc_status_api_links
+ elif len(args) > 2 and args[2] == 'Actions':
+ return self.validate_allowed_values
+ return self.action_api_resp
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=True)
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, side_effect=[obj, obj2, obj, URLError('URL error occurred'), obj, URLError('URL error occurred'), obj3, obj])
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=mock_get_dynamic_uri_request)
+ idrac_default_args.update({"reset_to_default": "Default"})
+ idrac_default_args.update({"wait_for_idrac": True})
+ idrac_default_args.update({"job_wait_timeout": 300})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ msg_resp, resp = reset_obj.execute()
+ assert msg_resp['msg'] == IDRAC_RESET_SUCCESS_MSG
+
+ # Scenario: when success message reset_to_default is passed as 'CustomDefaults' with custom_default_buffer
+ obj4 = MagicMock()
+ obj4.json_data = {'LCStatus': 'NOTINITIALIZED'}
+ obj2.headers = {'Location': "/joburl/JID12345"}
+ obj2.status_code = 200
+ # allowed_values.append("CustomDefaults")
+ job_resp_completed = {'JobStatus': 'Completed'}
+ idrac_redfish_resp = (False, 'Job Success', job_resp_completed, 1200)
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=True)
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, side_effect=[(allowed_values, True), (allowed_values, True)])
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, side_effect=[obj, obj2, obj, obj2])
+ mocker.patch(MODULE_PATH + 'idrac_redfish_job_tracking', return_value=idrac_redfish_resp)
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=[self.lc_status_api_links, self.action_api_resp_restart,
+ self.validate_allowed_values, self.validate_allowed_values,
+ self.validate_allowed_values, self.lc_status_api_links, self.action_api_resp_restart])
+ idrac_default_args.update({"reset_to_default": "CustomDefaults", "custom_defaults_buffer": self.custom_default_content})
+ idrac_default_args.update({"wait_for_idrac": False})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ msg_resp, resp = reset_obj.execute()
+ assert msg_resp['msg'] == IDRAC_RESET_RESET_TRIGGER_MSG
- def test_run_idrac_reset_success_case01(self, idrac_reset_connection_mock, idrac_default_args):
- f_module = self.get_module_mock(params=idrac_default_args)
- result = self.module.run_idrac_reset(idrac_reset_connection_mock, f_module)
- assert result == idrac_reset_connection_mock.config_mgr.reset_idrac()
+ # Scenario - When reset_to_default is passed and iDRAC8 and check_mode True
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="2.81.81")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=False)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, return_value=(None, False))
+ idrac_default_args.update({"reset_to_default": "CustomDefaults"})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.execute()
+ assert exc.value.args[0] == CHANGES_NOT_FOUND
+
+ # Scenario - When reset_to_default is passed and iDRAC8 and check_mode False
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="2.81.81")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, return_value=(None, False))
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=False)
+ idrac_default_args.update({"reset_to_default": "CustomDefaults"})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.execute()
+ assert exc.value.args[0] == RESET_TO_DEFAULT_ERROR_MSG.format(reset_to_default='CustomDefaults')
+
+ # Scenario - When reset_to_default is CustomDefaults and iDRAC9 firmware version not supported
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="6.99.99")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, return_value=(allowed_values_without_cd, True))
+ mocker.patch(MODULE_PATH + CHECK_LC_STATUS, return_value=None)
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=False)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.execute()
+ assert exc.value.args[0] == CUSTOM_ERROR.format(reset_to_default="CustomDefaults",
+ supported_values=allowed_values_without_cd)
+
+ # Scenario - When reset_to_default is passed and iDRAC9 and check_mode True
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.60")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, return_value=(allowed_values, False))
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=True)
+ idrac_default_args.update({"reset_to_default": "CustomDefaults", "custom_defaults_buffer": self.custom_default_content})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.execute()
+ assert exc.value.args[0] == CHANGES_FOUND
- def test_run_idrac_reset_status_success_case02(self, idrac_reset_connection_mock, idrac_default_args):
+ # Scenario - When reset_to_default is passed and iDRAC9 with firmware version not supported and check_mode True
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="6.81.81")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=True)
+ idrac_default_args.update({"reset_to_default": "CustomDefaults", "custom_defaults_buffer": self.custom_default_content})
f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
- result = self.module.run_idrac_reset(idrac_reset_connection_mock, f_module)
- assert result == {'Message': 'Changes found to commit!', 'Status': 'Success', 'changes_applicable': True}
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ with pytest.raises(Exception) as exc:
+ reset_obj.execute()
+ assert exc.value.args[0] == CHANGES_NOT_FOUND
- @pytest.mark.parametrize("exc_type", [SSLValidationError, URLError, ValueError, TypeError,
- ConnectionError, HTTPError])
- def test_main_exception_handling_case(self, exc_type, mocker, idrac_reset_connection_mock, idrac_default_args):
+ # Scenario - When reset_to_default is 'CustomDefaults' and iDRAC9 and custom_defaults_file is passed
json_str = to_text(json.dumps({"data": "out"}))
- if exc_type not in [HTTPError, SSLValidationError]:
- mocker.patch(MODULE_PATH + 'idrac_reset.run_idrac_reset', side_effect=exc_type('test'))
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + CHECK_IDRAC_VERSION, return_value=True)
+ mocker.patch(MODULE_PATH + CHECK_LC_STATUS, return_value=None)
+ mocker.patch(MODULE_PATH + "Validation.validate_path", return_value=None)
+ mocker.patch(MODULE_PATH + "Validation.validate_file_format", return_value=None)
+ mocker.patch(MODULE_PATH + "Validation.validate_custom_option", return_value=None)
+ mocker.patch(MODULE_PATH + 'open', mocker.mock_open(read_data=self.custom_default_content))
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, side_effect=[(allowed_values, True), (allowed_values, True)])
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, side_effect=[obj2, obj, HTTPError("https://test.com",
+ 401, HTTP_ERROR_MSG, {"accept-type": RETURN_TYPE},
+ StringIO(json_str))])
+ mocker.patch(MODULE_PATH + 'idrac_redfish_job_tracking', return_value=idrac_redfish_resp)
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=[self.validate_allowed_values, self.validate_allowed_values,
+ self.validate_allowed_values, self.lc_status_api_links, self.action_api_resp_restart])
+ idrac_default_args.update({"reset_to_default": "CustomDefaults", "custom_defaults_file": FILE_PATH})
+ idrac_default_args.update({"wait_for_idrac": True})
+ idrac_default_args.update({"job_wait_timeout": 300})
+ idrac_default_args.update({"force_reset": True})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ msg_resp, resp = reset_obj.execute()
+ assert msg_resp['msg'] == IDRAC_RESET_SUCCESS_MSG
+
+ # Scenario: Failure - when reset_to_default is passed as 'ResetAllWithRootDefaults' for idrac9 with job_wait set to True
+ def mock_get_dynamic_uri_request(*args, **kwargs):
+ if len(args) > 2 and args[2] == 'Links':
+ return self.lc_status_api_links
+ elif len(args) > 2 and args[2] == 'Actions':
+ return self.validate_allowed_values
+ return self.action_api_resp
+ obj.status_code = 400
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + CHECK_LC_STATUS, return_value=None)
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + VALIDATE_RESET_OPTION_KEY, return_value=(allowed_values, True))
+ mocker.patch(MODULE_PATH + INVOKE_REQ_KEY, side_effect=[obj])
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=mock_get_dynamic_uri_request)
+ idrac_default_args.update({"reset_to_default": "ResetAllWithRootDefaults"})
+ idrac_default_args.update({"wait_for_idrac": False})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ reset_obj = self.module.FactoryReset(idrac_connection_reset_mock, f_module, allowed_choices=allowed_values)
+ msg_resp, resp = reset_obj.execute()
+ assert msg_resp['msg'] == FAILED_RESET_MSG
+
+ def test_idrac_reset_main_positive_case(self, idrac_default_args,
+ idrac_connection_reset_mock, mocker):
+ # Scenario - When reset_to_default is passed and successful
+ msg_resp = {'msg': "Success", 'changed': True}
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + EXECUTE_KEY, return_value=(msg_resp, {}))
+ data = self._run_module(idrac_default_args)
+ assert data['msg'] == "Success"
+
+ # Scenario - When reset_to_default is passed and Failed
+ msg_resp = {'msg': "Failure", 'changed': False}
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + EXECUTE_KEY, return_value=(msg_resp, {}))
+ data = self._run_module(idrac_default_args)
+ assert data['msg'] == "Failure" and data['failed'] is True
+
+ # Scenario - When reset_to_default is None and successful
+ msg_resp = {'msg': "Success", 'changed': True}
+ output = {
+ "reset_status": {
+ "idracreset": {
+ "Data": {
+ "StatusCode": 204
+ },
+ "Message": "Success",
+ "Status": "Success",
+ "StatusCode": 204,
+ "retval": True
+ }
+ }
+ }
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + EXECUTE_KEY, return_value=(msg_resp, output))
+ data = self._run_module(idrac_default_args)
+ assert data['msg'] == "Success" and data['reset_status'] == output
+
+ # Scenario - When reset_to_default is None and Failed
+ output['reset_status']['idracreset']['Message'] = "Failure"
+ output['reset_status']['idracreset']['Status'] = "Failure"
+ output['reset_status']['idracreset']['StatusCode'] = 404
+ msg_resp = {'msg': "Failure", 'changed': False}
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="7.10.05")
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ mocker.patch(MODULE_PATH + EXECUTE_KEY, return_value=(msg_resp, output))
+ data = self._run_module(idrac_default_args)
+ assert data['msg'] == "Failure" and data['reset_status'] == output
+
+ @pytest.mark.parametrize("exc_type",
+ [URLError, HTTPError, SSLValidationError, ConnectionError, TypeError, ValueError])
+ def test_idrac_reset_main_exception_handling_case(self, exc_type, idrac_default_args,
+ idrac_connection_reset_mock, mocker):
+ json_str = to_text(json.dumps({"data": "out"}))
+ mocker.patch(MODULE_PATH + GET_BASE_URI_KEY, return_value=IDRAC_URI)
+ if exc_type in [HTTPError, SSLValidationError]:
+ mocker.patch(MODULE_PATH + EXECUTE_KEY,
+ side_effect=exc_type('https://testhost.com', 400,
+ HTTP_ERROR_MSG,
+ {"accept-type": RETURN_TYPE},
+ StringIO(json_str)))
else:
- mocker.patch(MODULE_PATH + 'idrac_reset.run_idrac_reset',
- side_effect=exc_type('https://testhost.com', 400, 'http error message',
- {"accept-type": "application/json"}, StringIO(json_str)))
- if not exc_type == URLError:
- result = self._run_module_with_fail_json(idrac_default_args)
- assert result['failed'] is True
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version",
+ side_effect=exc_type('test'))
+ result = self._run_module(idrac_default_args)
+ if exc_type == URLError:
+ assert result['unreachable'] is True
else:
- result = self._run_module(idrac_default_args)
+ assert result['failed'] is True
assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_session.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_session.py
new file mode 100644
index 000000000..a28aab255
--- /dev/null
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_session.py
@@ -0,0 +1,590 @@
+# -*- coding: utf-8 -*-
+
+#
+# Dell OpenManage Ansible Modules
+# Version 9.2.0
+# Copyright (C) 2024 Dell Inc. or its subsidiaries. All Rights Reserved.
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+
+
+from io import StringIO
+import json
+
+
+from urllib.error import HTTPError, URLError
+import pytest
+from mock import MagicMock
+from ansible_collections.dellemc.openmanage.plugins.modules import idrac_session
+from ansible_collections.dellemc.openmanage.tests.unit.plugins.modules.common import FakeAnsibleModule
+from ansible_collections.dellemc.openmanage.tests.unit.plugins.modules.common import AnsibleFailJSonException
+from ansible.module_utils.urls import SSLValidationError
+from ansible.module_utils._text import to_text
+
+
+MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.idrac_session.'
+MODULE_UTILS_PATH = 'ansible_collections.dellemc.openmanage.plugins.module_utils.utils.'
+
+REDFISH = "/redfish/v1"
+SESSIONS = "Sessions"
+ODATA = "@odata.id"
+ODATA_REGEX = "(.*?)@odata"
+
+SESSION_URL = "/redfish/v1/SessionService/Sessions"
+GET_SESSION_URL = "Session.get_session_url"
+
+CREATE_SUCCESS_MSG = "The session has been created successfully."
+DELETE_SUCCESS_MSG = "The session has been deleted successfully."
+FAILURE_MSG = "Unable to '{operation}' a session."
+CHANGES_FOUND_MSG = "Changes found to be applied."
+NO_CHANGES_FOUND_MSG = "No changes found to be applied."
+HTTPS_PATH = "https://testhost.com"
+HTTP_ERROR = "http error message"
+APPLICATION_JSON = "application/json"
+
+
+class TestSession(FakeAnsibleModule):
+ """
+ Main class for testing the idrac_session module.
+ """
+ module = idrac_session
+
+ @pytest.fixture
+ def idrac_session_mock(self):
+ """
+ Creates a mock object for the `idrac_session` fixture.
+
+ This function uses the `MagicMock` class from the `unittest.mock` module to create a mock
+ object. The mock object is then returned by the function.
+
+ Returns:
+ MagicMock: A mock object representing the `idrac_session`.
+ """
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_session_mock(self, mocker, idrac_session_mock):
+ """
+ Returns a mock object for the `SessionAPI` class from the `MODULE_PATH` module.
+ The mock object is initialized with the `idrac_session_mock` as the return value.
+ The `__enter__` method of the mock object is also mocked to return `idrac_session_mock`.
+
+ :param mocker: The pytest fixture for mocking objects.
+ :type mocker: pytest_mock.plugin.MockerFixture
+ :param idrac_session_mock: The mock object for the `idrac_session_mock`.
+ :type idrac_session_mock: Any
+ :return: The mock object for the `SessionAPI` class.
+ :rtype: MagicMock
+ """
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'SessionAPI',
+ return_value=idrac_session_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_session_mock
+ return idrac_conn_mock
+
+ def test_get_session_url(self, idrac_default_args, idrac_connection_session_mock, mocker):
+ """
+ Test the `get_session_url` method of the `Session` class.
+
+ This test function mocks the `get_dynamic_uri` function to return a dictionary
+ containing the session URL. It then creates a `f_module` object with the
+ `idrac_default_args` and `check_mode` set to `False`. It initializes a
+ `session_obj` with the `idrac_connection_session_mock` and `f_module`.
+ Finally, it calls the `get_session_url` method on the `session_obj` and
+ asserts that the returned session URL is equal to the `SESSION_URL` constant.
+
+ Args:
+ self (TestGetSessionUrl): The test case object.
+ idrac_default_args (dict): The default arguments for the IDRAC connection.
+ idrac_connection_session_mock (MagicMock): The mock object for the IDRAC
+ connection session.
+ mocker (MagicMock): The mocker object for mocking functions and modules.
+
+ Returns:
+ None
+ """
+ v1_resp = {'Links': {'Sessions': {'@odata.id': SESSION_URL}}}
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ return_value=v1_resp)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ session_obj = self.module.Session(
+ idrac_connection_session_mock, f_module)
+ sessions_url = session_obj.get_session_url()
+ assert sessions_url == SESSION_URL
+
+
+class TestCreateSession(FakeAnsibleModule):
+ """
+ Main class for testing the create_session module.
+ """
+ module = idrac_session
+
+ @pytest.fixture
+ def create_session_mock(self):
+ """
+ Creates a mock object for the `idrac_session` fixture.
+
+ This function is a pytest fixture that creates a mock object of type `MagicMock` and
+ assigns it to the variable `idrac_obj`. The `idrac_obj` mock object is then returned
+ by the fixture.
+
+ Returns:
+ MagicMock: A mock object representing the `idrac_session` fixture.
+ """
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_session_mock(self, mocker, create_session_mock):
+ """
+ Creates a fixture for mocking the IDRAC connection session.
+
+ This fixture uses the `mocker` fixture from the `pytest` library to patch the
+ `SessionAPI` class from the `MODULE_PATH` module. It returns a mock object of the
+ `SessionAPI` class with the `create_session_mock` object as the return value.
+ The `__enter__` method of the mock object is also patched to return the
+ `create_session_mock` object.
+
+ Parameters:
+ - `self` (TestCase): The test case instance.
+ - `mocker` (MockerFixture): The `mocker` fixture from the `pytest` library.
+ - `create_session_mock` (Mock): The mock object representing the `create_session_mock`.
+
+ Returns:
+ - `idrac_conn_mock` (MagicMock): The mock object of the `SessionAPI` class.
+ """
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'SessionAPI',
+ return_value=create_session_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = create_session_mock
+ return idrac_conn_mock
+
+ def test_session_operation(self, idrac_default_args, idrac_connection_session_mock):
+ """
+ Test the session operation of the module.
+
+ Args:
+ idrac_default_args (dict): The default arguments for the IDRAC connection.
+ idrac_connection_session_mock (MagicMock): The mock object for the IDRAC
+ connection session.
+
+ Returns:
+ None
+
+ This function tests the session operation of the module by creating a session and deleting
+ a session.
+ It updates the `idrac_default_args` dictionary with the appropriate state parameter and
+ creates a `f_module` object with the updated arguments. It then creates a
+ `session_operation_obj` object using the `CreateSession` class of the module and asserts
+ that it is an instance of `CreateSession`.
+ It repeats the same process for deleting a session by updating the `idrac_default_args`
+ dictionary with the state parameter set to "absent" and creating a `session_operation_obj`
+ object using the
+ `DeleteSession` class of the module. It asserts that it is an instance of `DeleteSession`.
+ """
+ idrac_default_args.update({"state": "present"})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ session_operation_obj = self.module.CreateSession(idrac_connection_session_mock, f_module)
+ assert isinstance(session_operation_obj, self.module.CreateSession)
+
+ idrac_default_args.update({"state": "absent"})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ session_operation_obj = self.module.DeleteSession(idrac_connection_session_mock, f_module)
+ assert isinstance(session_operation_obj, self.module.DeleteSession)
+
+ def test_create_session_failure(self, idrac_connection_session_mock, mocker):
+ """
+ Test the failure scenario of creating a session.
+
+ Args:
+ idrac_connection_session_mock (MagicMock): A mock object for the
+ idrac_connection_session.
+ mocker (MockerFixture): A fixture for mocking objects.
+
+ Returns:
+ None
+
+ This test function creates a session object using the `idrac_connection_session_mock` and
+ `f_module` objects.
+ It sets the `session_obj.get_session_url` to return a session URL.
+ It sets the `f_module.check_mode` to False and `f_module.params` to a dictionary containing
+ the username and password.
+ It mocks the `idrac_connection_session_mock.invoke_request` method to return a response
+ with a status code of 201.
+ It calls the `session_obj.execute()` method to create the session.
+ It asserts that the `f_module.exit_json` method is called once with the message "Unable to
+ 'create' a session." and `failed` set to True.
+ """
+ f_module = MagicMock()
+ session_obj = idrac_session.CreateSession(
+ idrac_connection_session_mock, f_module)
+ session_obj.get_session_url = MagicMock(return_value=SESSION_URL)
+ f_module.check_mode = False
+ f_module.params = {
+ "username": "admin",
+ "password": "password"
+ }
+ response_mock = MagicMock()
+ response_mock.status_code = 201
+ mocker.patch.object(idrac_connection_session_mock.return_value, 'invoke_request',
+ return_value=response_mock)
+
+ session_obj.execute()
+ f_module.exit_json.assert_called_once_with(
+ msg="Unable to 'create' a session.",
+ failed=True
+ )
+
+ def test_create_session_check_mode(self, idrac_connection_session_mock):
+ """
+ Test the create session functionality in check mode.
+
+ Args:
+ idrac_connection_session_mock (MagicMock): A mock object for the IDRAC connection
+ session.
+
+ Returns:
+ None
+
+ This function tests the create session functionality in check mode. It creates an instance
+ of the `CreateSession` class with the provided `idrac_connection_session_mock` and a mock
+ `f_module` object.
+ It sets the required parameters for the `f_module` object and mocks the `get_session_url`
+ method of the `session_obj` to return the session URL. It also mocks the `exit_json` method
+ of the `f_module` object.
+
+ Finally, it calls the `execute` method of the `session_obj` to execute the create session
+ functionality in check mode.
+
+ Note:
+ This function assumes that the necessary imports and setup for the test are already
+ done.
+ """
+ f_module = MagicMock()
+ session_obj = idrac_session.CreateSession(
+ idrac_connection_session_mock, f_module)
+ f_module = self.get_module_mock(
+ params={"session_id": "1234", "hostname": "X.X.X.X"}, check_mode=True)
+ session_obj.get_session_url = MagicMock(return_value=SESSION_URL)
+ f_module.exit_json = MagicMock()
+
+ session_obj.execute()
+
+ def test_create_session_success(self, idrac_connection_session_mock):
+ """
+ Test the successful creation of a session.
+
+ Args:
+ idrac_connection_session_mock (MagicMock): A mock object representing the IDRAC
+ connection session.
+
+ This test case verifies the successful creation of a session by mocking the necessary
+ objects and invoking the `execute()` method of the `CreateSession` class. It sets the
+ parameters for the `f_module` object, initializes the `session_obj` with the mocked
+ `idrac_connection_session_mock` and `f_module`, and mocks the necessary methods and
+ attributes of the `idrac` object. It then asserts that the `exit_json` method of the
+ `f_module` object is called with the expected arguments.
+
+ Returns:
+ None
+ """
+ f_module = self.get_module_mock(
+ params={"username": "admin", "password": "password"}, check_mode=False)
+ session_obj = idrac_session.CreateSession(idrac_connection_session_mock, f_module)
+ session_obj.get_session_url = MagicMock(return_value=SESSION_URL)
+ session_obj.idrac.invoke_request.return_value.status_code = 201
+ session_obj.idrac.invoke_request.return_value.json_data = {"SessionID": "123456"}
+ session_obj.idrac.invoke_request.return_value.headers.get.return_value = "token123"
+ f_module.exit_json = MagicMock()
+
+ session_obj.execute()
+ f_module.exit_json.assert_called_once_with(
+ msg=CREATE_SUCCESS_MSG,
+ changed=True,
+ session_data={"SessionID": "123456"},
+ x_auth_token="token123"
+ )
+
+
+class TestDeleteSession(FakeAnsibleModule):
+ """
+ Main class for testing the delete session module.
+ """
+ module = idrac_session
+
+ @pytest.fixture
+ def idrac_session_mock(self):
+ """
+ Creates a mock object for the `idrac_session` fixture.
+
+ This function uses the `MagicMock` class from the `unittest.mock` module to create a mock
+ object.
+ The mock object is then returned by the function.
+
+ Returns:
+ MagicMock: A mock object representing the `idrac_session`.
+ """
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_session_mock(self, mocker, idrac_session_mock):
+ """
+ Returns a mocked instance of the SessionAPI class from the specified module path.
+ The mocked instance is created using the `mocker.patch` function. The `idrac_session_mock`
+ parameter is passed as the return value of the mocked instance. The `__enter__` method
+ of the mocked instance is also mocked to return the `idrac_session_mock`.
+ :param mocker: The mocker fixture provided by the pytest framework.
+ :type mocker: _pytest.monkeypatch.MonkeyPatch
+ :param idrac_session_mock: The mocked instance of the idrac session.
+ :type idrac_session_mock: Any
+ :return: The mocked instance of the SessionAPI class.
+ :rtype: MagicMock
+ """
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'SessionAPI',
+ return_value=idrac_session_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_session_mock
+ return idrac_conn_mock
+
+ def test_delete_session_success_check_mode_changes(self, idrac_connection_session_mock):
+ """
+ Test the `delete_session_success_check_mode_changes` method of the `DeleteSession` class.
+
+ This method is responsible for testing the success case when the `delete_session` method
+ is called in check mode.
+ It verifies that the `exit_json` method of the `f_module` object is called with the
+ appropriate arguments when the session is successfully deleted.
+
+ Parameters:
+ - idrac_connection_session_mock (MagicMock): A mock object representing the
+ `idrac_connection_session` object.
+
+ Returns:
+ None
+ """
+ f_module = MagicMock()
+ delete_session_obj = idrac_session.DeleteSession(idrac_connection_session_mock, f_module)
+ delete_session_obj.idrac.invoke_request.return_value.status_code = 200
+ delete_session_obj.execute()
+ f_module.exit_json.assert_called_once_with(msg=CHANGES_FOUND_MSG, changed=True)
+
+ def test_delete_session_success_check_mode_no_changes(self, idrac_connection_session_mock):
+ """
+ Test the success case of deleting a session in check mode when no changes are expected.
+
+ Args:
+ idrac_connection_session_mock (MagicMock): A mock object representing the IDRAC
+ connection session.
+
+ This function tests the scenario where the deletion of a session is successful in check
+ mode and no changes are expected. It sets up the necessary mock objects and asserts that
+ the `exit_json` method of the `f_module` object is called once with the `msg` parameter
+ set to `NO_CHANGES_FOUND_MSG`.
+
+ Returns:
+ None
+ """
+ f_module = MagicMock()
+ delete_session_obj = idrac_session.DeleteSession(idrac_connection_session_mock, f_module)
+ delete_session_obj.idrac.invoke_request.return_value.status_code = 201
+ delete_session_obj.execute()
+ f_module.exit_json.assert_called_once_with(msg=NO_CHANGES_FOUND_MSG)
+
+ def test_delete_session_success(self, idrac_connection_session_mock):
+ """
+ Test the successful deletion of a session.
+
+ This test function verifies the behavior of the `DeleteSession` class when a session is
+ successfully deleted. It mocks the `idrac_connection_session_mock` object and sets up the
+ necessary parameters for the `f_module` object. It then creates an instance of the
+ `DeleteSession` class with the mocked `idrac_connection_session_mock` and the
+ `f_module` object.
+
+ The `get_session_url` method of the `session_obj` is mocked to return a specific session
+ URL. The `invoke_request` method of the `idrac` object of the `session_obj` is also mocked
+ to return a response with a status code of 200. The `exit_json` method of the `f_module`
+ object is mocked as well.
+
+ The `execute` method of the `session_obj` is called to execute the deletion of the session.
+ Finally, the `exit_json` method of the `f_module` object is asserted to have been called
+ with the expected arguments, including the success message and the changed flag set to
+ `True`.
+
+ Parameters:
+ - idrac_connection_session_mock (MagicMock): A mocked object representing the
+ `idrac_connection_session_mock` object.
+
+ Returns:
+ None
+ """
+ f_module = self.get_module_mock(
+ params={"session_id": "1234", "hostname": "X.X.X.X"}, check_mode=False)
+ session_obj = idrac_session.DeleteSession(idrac_connection_session_mock, f_module)
+ session_obj.get_session_url = MagicMock(return_value=SESSION_URL)
+ session_obj.idrac.invoke_request.return_value.status_code = 200
+ f_module.exit_json = MagicMock()
+ session_obj.execute()
+ f_module.exit_json.assert_called_once_with(msg=DELETE_SUCCESS_MSG, changed=True)
+
+ def test_delete_session_check_mode_false_no_changes(self, idrac_connection_session_mock):
+ """
+ Test the scenario where the delete session is executed in check mode with `check_mode` set
+ to False and no changes are expected.
+
+ Args:
+ idrac_connection_session_mock (MagicMock): A mock object representing the IDRAC
+ connection session.
+
+ Returns:
+ None
+
+ This function creates a mock module object with the specified parameters and
+ initializes the `DeleteSession` object with the mock IDRAC connection and module. It sets
+ the `get_session_url` method of the session object to return a specific session URL. It
+ sets the status code of the invoke request to 201. It then asserts that the `exit_json`
+ method of the module object is called once with the `msg` parameter set to the
+ `NO_CHANGES_FOUND_MSG` constant.
+ """
+ f_module = self.get_module_mock(
+ params={"session_id": "1234", "hostname": "X.X.X.X"}, check_mode=False)
+ session_obj = idrac_session.DeleteSession(idrac_connection_session_mock, f_module)
+ session_obj.get_session_url = MagicMock(return_value=SESSION_URL)
+ session_obj.idrac.invoke_request.return_value.status_code = 201
+ f_module.exit_json = MagicMock()
+ session_obj.execute()
+ f_module.exit_json.assert_called_once_with(msg=NO_CHANGES_FOUND_MSG)
+
+ def test_delete_session_http_error(self, idrac_connection_session_mock):
+ """
+ Test the behavior of the `DeleteSession` class when an HTTP error occurs during the
+ deletion of a session.
+
+ This test case creates a mock `f_module` object with the necessary parameters and
+ initializes a `DeleteSession` object with the mock `idrac_connection_session_mock` and the
+ `f_module` object. It then sets up the necessary mock functions and side effects to
+ simulate an HTTP error during the deletion of a session. Finally, it executes the
+ `execute()` method of the `DeleteSession` object and asserts that an
+ `AnsibleFailJSonException` is raised with the expected failure message and error
+ information.
+
+ Parameters:
+ - idrac_connection_session_mock (MagicMock): A mock object representing the
+ `idrac_connection_session_mock` parameter.
+
+ Raises:
+ - AssertionError: If the expected failure message or error information is not present
+ in the raised exception.
+
+ Returns:
+ None
+ """
+ f_module = self.get_module_mock(
+ params={"session_id": "1234", "hostname": "X.X.X.X"}, check_mode=False)
+ session_obj = idrac_session.DeleteSession(idrac_connection_session_mock, f_module)
+ session_obj.get_session_url = MagicMock(return_value=SESSION_URL)
+ session_obj.get_session_status = MagicMock(return_value=200)
+ json_str = to_text(json.dumps({"data": "out"}))
+ session_obj.idrac.invoke_request.side_effect = HTTPError(HTTPS_PATH, 200,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str))
+ try:
+ session_obj.execute()
+ except AnsibleFailJSonException as ex:
+ assert ex.fail_msg == "Unable to 'delete' a session."
+ assert ex.fail_kwargs == {'error_info': {'data': 'out'}, 'failed': True}
+
+
+class TestMain(FakeAnsibleModule):
+ """
+ Class for testing the main.
+ """
+ module = idrac_session
+
+ @pytest.fixture
+ def idrac_session_mock(self):
+ """
+ Creates a mock object for the `idrac_session` fixture.
+
+ This function uses the `MagicMock` class from the `unittest.mock` module to create a mock
+ object.
+ The mock object is then returned by the function.
+
+ Returns:
+ MagicMock: A mock object representing the `idrac_session`.
+ """
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_session_mock(self, mocker, idrac_session_mock):
+ """
+ Returns a mock object for the `SessionAPI` class from the `MODULE_PATH` module.
+ The mock object is initialized with the `idrac_session_mock` as the return value.
+ The `__enter__` method of the mock object is also mocked to return `idrac_session_mock`.
+
+ :param mocker: The pytest fixture for mocking objects.
+ :type mocker: pytest_mock.plugin.MockerFixture
+ :param idrac_session_mock: The mock object for the `idrac_session_mock`.
+ :type idrac_session_mock: Any
+ :return: The mock object for the `SessionAPI` class.
+ :rtype: MagicMock
+ """
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'SessionAPI',
+ return_value=idrac_session_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_session_mock
+ return idrac_conn_mock
+
+ @pytest.mark.parametrize("exc_type",
+ [URLError, HTTPError, SSLValidationError, ConnectionError,
+ TypeError, ValueError])
+ def test_idrac_session_main_exception_handling_case(self, exc_type, ome_default_args, mocker):
+ """
+ Test the exception handling of the `idrac_session_main` module.
+
+ This function tests the exception handling of the `idrac_session_main` module by mocking
+ different exceptions and verifying the expected behavior.
+
+ Parameters:
+ - exc_type (Exception): The type of exception to be raised.
+ - ome_default_args (dict): The default arguments for the module.
+ - mocker (MockerFixture): The mocker fixture for mocking functions.
+
+ Returns:
+ None
+
+ Raises:
+ AssertionError: If the expected result does not match the actual result.
+
+ Notes:
+ - The function uses the `pytest.mark.parametrize` decorator to parameterize the test
+ cases.
+ - The `exc_type` parameter represents the type of exception to be raised.
+ - The `ome_default_args` parameter contains the default arguments for the module.
+ - The `mocker` parameter is used to mock functions and simulate different exceptions.
+ - The function calls the `_run_module` method with the `ome_default_args` to execute
+ the module.
+ - The function verifies the expected result based on the raised exception type.
+
+ """
+ json_str = to_text(json.dumps({"data": "out"}))
+ if exc_type in [HTTPError, SSLValidationError]:
+ mocker.patch(MODULE_PATH + "CreateSession.get_session_url",
+ side_effect=exc_type(HTTPS_PATH, 400,
+ HTTP_ERROR,
+ {"accept-type": APPLICATION_JSON},
+ StringIO(json_str)))
+ else:
+ ome_default_args.update({"state": "absent", "session_id": "1234",
+ "auth_token": "token123"})
+ mocker.patch(MODULE_PATH + "DeleteSession.get_session_url",
+ side_effect=exc_type('test'))
+ result = self._run_module(ome_default_args)
+ if exc_type == URLError:
+ assert result['unreachable'] is True
+ else:
+ assert result['failed'] is True
+ assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_storage_volume.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_storage_volume.py
new file mode 100644
index 000000000..3cdf742d2
--- /dev/null
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_storage_volume.py
@@ -0,0 +1,1178 @@
+# -*- coding: utf-8 -*-
+
+#
+# Dell OpenManage Ansible Modules
+# Version 9.0.0
+# Copyright (C) 2024 Dell Inc. or its subsidiaries. All Rights Reserved.
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+
+import json
+import pytest
+from io import StringIO
+from ansible.module_utils._text import to_text
+from urllib.error import HTTPError, URLError
+from ansible.module_utils.urls import ConnectionError, SSLValidationError
+from ansible_collections.dellemc.openmanage.plugins.modules import idrac_storage_volume
+from ansible_collections.dellemc.openmanage.tests.unit.plugins.modules.common import FakeAnsibleModule
+from mock import MagicMock
+from copy import deepcopy
+
+MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.idrac_storage_volume.'
+MODULE_UTILS_PATH = 'ansible_collections.dellemc.openmanage.plugins.module_utils.utils.'
+
+SYSTEMS_URI = "/redfish/v1/Systems"
+iDRAC_JOB_URI = "/redfish/v1/Managers/iDRAC.Embedded.1/Jobs/{job_id}"
+CONTROLLER_NOT_EXIST_ERROR = "Specified Controller {controller_id} does not exist in the System."
+CONTROLLER_NOT_DEFINED = "Controller ID is required."
+SUCCESSFUL_OPERATION_MSG = "Successfully completed the {operation} storage volume operation."
+DRIVES_NOT_EXIST_ERROR = "No Drive(s) are attached to the specified Controller Id: {controller_id}."
+DRIVES_NOT_MATCHED = "Following Drive(s) {specified_drives} are not attached to the specified Controller Id: {controller_id}."
+NEGATIVE_OR_ZERO_MSG = "The value for the `{parameter}` parameter cannot be negative or zero."
+NEGATIVE_MSG = "The value for the `{parameter}` parameter cannot be negative."
+INVALID_VALUE_MSG = "The value for the `{parameter}` parameter is invalid."
+ID_AND_LOCATION_BOTH_DEFINED = "Either id or location is allowed."
+ID_AND_LOCATION_BOTH_NOT_DEFINED = "Either id or location should be specified."
+DRIVES_NOT_DEFINED = "Drives must be defined for volume creation."
+NOT_ENOUGH_DRIVES = "Number of sufficient disks not found in Controller '{controller_id}'!"
+WAIT_TIMEOUT_MSG = "The job is not complete after {0} seconds."
+JOB_TRIGERRED = "Successfully triggered the {0} storage volume operation."
+VOLUME_NAME_REQUIRED_FOR_DELETE = "Virtual disk name is a required parameter for remove virtual disk operations."
+VOLUME_NOT_FOUND = "Unable to find the virtual disk."
+CHANGES_NOT_FOUND = "No changes found to commit!"
+CHANGES_FOUND = "Changes found to commit!"
+ODATA_ID = "@odata.id"
+ODATA_REGEX = "(.*?)@odata"
+ATTRIBUTE = "</Attribute>"
+VIEW_OPERATION_FAILED = "Failed to fetch storage details."
+VIEW_CONTROLLER_DETAILS_NOT_FOUND = "Failed to find the controller {controller_id}."
+VIEW_OPERATION_CONTROLLER_NOT_SPECIFIED = "Controller identifier parameter is missing."
+VIEW_VIRTUAL_DISK_DETAILS_NOT_FOUND = "Failed to find the volume : {volume_id} in controller : {controller_id}."
+SUCCESS_STATUS = "Success"
+FAILED_STATUS = "Failed"
+CONTROLLER_BATTERY = "Battery.Integrated.1:RAID.SL.5-1"
+CONTROLLER_ID_FIRST = "AHCI.Embedded.1-1"
+CONTROLLER_ID_SECOND = "AHCI.Embedded.1-2"
+CONTROLLER_ID_THIRD = "AHCI.Embedded.1-3"
+CONTROLLER_ID_FOURTH = "RAID.SL.5-1"
+CONTROLLER_ID_FIFTH = "RAID.SL.5-3"
+SYSTEM = 'System.Embedded.1'
+ENCLOSURE_ID = 'Enclosure.Internal.0-1:RAID.SL.5-1'
+PHYSICAL_DISK_FIRST = 'Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.5-1'
+PHYSICAL_DISK_SECOND = 'Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.5-3'
+VIRTUAL_DISK_FIRST = 'Disk.Virtual.0:RAID.SL.5-1'
+VIRTUAL_DISK_SECOND = 'Disk.Virtual.1:RAID.SL.5-1'
+ALL_STORAGE_DATA_METHOD = "StorageData.all_storage_data"
+FETCH_STORAGE_DATA_METHOD = "StorageData.fetch_storage_data"
+FILTER_DISK = 'StorageCreate.filter_disk'
+VIEW_EXECUTE = 'StorageView.execute'
+DATA_XML = '<Data></Data>'
+REDFISH = "/redfish/v1"
+API_INVOKE_MOCKER = "iDRACRedfishAPI.invoke_request"
+BASE_IDRAC_API = "/redfish/v1/Chassis/System.Embedded.1"
+
+
+class TestStorageData(FakeAnsibleModule):
+ module = idrac_storage_volume
+ storage_controllers = {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage"
+ }
+ volumes_list = [
+ {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-1/Volumes/Disk.Virtual.0:RAID.SL.5-1"
+ },
+ {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-1/Volumes/Disk.Virtual.1:RAID.SL.5-1"
+ }]
+ controllers_list = {
+ "Members": [
+ {
+ "Controllers": {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-1/Controllers"
+ },
+ "Drives": [
+ {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-1/Drives/Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.5-1"
+ }
+ ],
+ "Id": CONTROLLER_ID_FOURTH,
+ "Links": {
+ "Enclosures": [
+ {
+ ODATA_ID: "/redfish/v1/Chassis/Enclosure.Internal.0-1:RAID.SL.5-1"
+ }
+ ]
+ },
+ "Volumes": {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-1/Volumes"
+ },
+ "Oem": {
+ "Dell": {
+ "DellControllerBattery": {
+ "Id": CONTROLLER_BATTERY
+ }}
+ }
+ },
+ {
+ "Drives": [
+ {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/CPU.1/Drives/Disk.Bay.23:Enclosure.Internal.0-3"
+ }
+ ],
+ "Drives@odata.count": 1,
+ "Id": "CPU.1",
+ "Links": {
+ "Enclosures": [
+ {
+ ODATA_ID: "/redfish/v1/Chassis/Enclosure.Internal.0-3"
+ }
+ ],
+ },
+ "Volumes": {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/CPU.1/Volumes"
+ }
+ },
+ {
+ "Controllers": {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Controllers"
+ },
+ "Drives": [],
+ "Id": CONTROLLER_ID_FIRST,
+ "Links": {
+ "Enclosures": [
+ {
+ ODATA_ID: BASE_IDRAC_API
+ }
+ ]
+ },
+ "Volumes": {
+ ODATA_ID: "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Volumes"
+ }
+ }
+ ]
+ }
+
+ storage_data = {
+ 'Controllers': {
+ CONTROLLER_ID_FIRST: {
+ 'Controllers': {
+ ODATA_ID: '/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Controllers',
+ },
+ 'Drives': {},
+ 'Id': CONTROLLER_ID_FIRST,
+ 'Links': {
+ 'Enclosures': {
+ SYSTEM: BASE_IDRAC_API,
+ },
+ },
+ 'Volumes': {},
+ "Oem": {
+ "Dell": {
+ "CPUAffinity": []
+ }
+ }
+ },
+ CONTROLLER_ID_SECOND: {
+ 'Controllers': {
+ ODATA_ID: '/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-2/Controllers',
+ },
+ 'Drives': {
+ 'Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Embedded.1-2': '/redfish/v1/\
+ Systems/System.Embedded.1/Storage/RAID.SL.5-1/Drives/Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.5-1',
+ },
+ 'Id': CONTROLLER_ID_SECOND,
+ 'Links': {
+ 'Enclosures': {
+ SYSTEM: BASE_IDRAC_API,
+ },
+ },
+ 'Volumes': {},
+ "Oem": {
+ "Dell": {
+ "CPUAffinity": []
+ }
+ }
+ },
+ CONTROLLER_ID_THIRD: {
+ 'Controllers': {
+ ODATA_ID: '/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-2/Controllers',
+ },
+ 'Drives': {
+ 'Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Embedded.1-3': '/redfish/v1/\
+ Systems/System.Embedded.1/Storage/AHCI.Embedded.1-3/Drives/Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Embedded.1-3',
+ },
+ 'Id': CONTROLLER_ID_THIRD,
+ 'Links': {
+ 'Enclosures': {
+ ENCLOSURE_ID: {
+ "Links": {
+ "Drives": []
+ }
+ },
+ },
+ },
+ 'Volumes': {},
+ "Oem": {
+ "Dell": {
+ "CPUAffinity": []
+ }
+ }
+ },
+ CONTROLLER_ID_FOURTH: {
+ 'Controllers': {
+ ODATA_ID: '/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-1/Controllers',
+ },
+ 'Drives': {
+ PHYSICAL_DISK_FIRST: '/redfish/v1/Systems\
+ /System.Embedded.1/Storage/RAID.SL.5-1/Drives/Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.5-1',
+ },
+ 'Id': CONTROLLER_ID_FOURTH,
+ 'Links': {
+ 'Enclosures': {
+ ENCLOSURE_ID: {"Links": {
+ "Drives": [
+ {
+ ODATA_ID: PHYSICAL_DISK_FIRST
+ }
+ ]}}
+ },
+ },
+ 'Volumes': {
+ VIRTUAL_DISK_FIRST: {
+ "Links": {
+ "Drives": [
+ {
+ ODATA_ID: PHYSICAL_DISK_FIRST
+ }
+ ]
+ },
+ },
+ VIRTUAL_DISK_SECOND: {
+ "Links": {
+ "Drives": [
+ {
+ ODATA_ID: PHYSICAL_DISK_FIRST
+ }
+ ]
+ },
+ },
+ },
+ "Oem": {
+ "Dell": {
+ "DellControllerBattery": {
+ "Id": CONTROLLER_BATTERY
+ }}
+ }
+ }
+ }
+ }
+
+ storage_data_expected = {
+ 'Controller': {
+ CONTROLLER_ID_FIRST: {
+ 'ControllerSensor': {
+ CONTROLLER_ID_FIRST: {},
+ },
+ },
+ CONTROLLER_ID_SECOND: {
+ 'ControllerSensor': {
+ CONTROLLER_ID_SECOND: {},
+ },
+ 'PhysicalDisk': [
+ 'Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Embedded.1-2',
+ ],
+ },
+ CONTROLLER_ID_THIRD: {
+ 'ControllerSensor': {
+ CONTROLLER_ID_THIRD: {}
+ },
+ 'Enclosure': {
+ ENCLOSURE_ID: {
+ 'EnclosureSensor': {
+ ENCLOSURE_ID: {},
+ },
+ },
+ },
+ },
+ CONTROLLER_ID_FOURTH: {
+ 'ControllerSensor': {
+ CONTROLLER_ID_FOURTH: {
+ 'ControllerBattery': [
+ 'Battery.Integrated.1:RAID.SL.5-1',
+ ],
+ },
+ },
+ 'Enclosure': {
+ ENCLOSURE_ID: {
+ 'EnclosureSensor': {
+ ENCLOSURE_ID: {},
+ },
+ 'PhysicalDisk': [
+ PHYSICAL_DISK_FIRST,
+ ],
+ },
+ },
+ 'VirtualDisk': {
+ VIRTUAL_DISK_FIRST: {
+ 'PhysicalDisk': [
+ PHYSICAL_DISK_FIRST,
+ ],
+ },
+ VIRTUAL_DISK_SECOND: {
+ 'PhysicalDisk': [
+ PHYSICAL_DISK_FIRST,
+ ],
+ },
+ },
+ },
+ }
+ }
+
+ storage_data_idrac8 = {
+ 'Controllers': {
+ CONTROLLER_ID_FIFTH: {
+ 'Controllers': {
+ ODATA_ID: '/redfish/v1/Systems/System.Embedded.1/Storage/RAID.SL.5-3/Controllers',
+ },
+ 'Drives': {
+ PHYSICAL_DISK_SECOND: '/redfish/v1/Systems\
+ /System.Embedded.1/Storage/RAID.SL.5-3/Drives/Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.5-3',
+ },
+ 'Id': CONTROLLER_ID_FIFTH,
+ 'Links': {
+ 'Enclosures': {
+ ENCLOSURE_ID: {"Links": {
+ "Drives": [
+ {
+ ODATA_ID: PHYSICAL_DISK_SECOND
+ }
+ ]}}
+ },
+ },
+ 'Volumes': {
+ 'Disk.Virtual.0:RAID.SL.5-3': {
+ "Links": {
+ "Drives": [
+ {
+ ODATA_ID: PHYSICAL_DISK_SECOND
+ }
+ ]
+ },
+ },
+ 'Disk.Virtual.1:RAID.SL.5-3': {
+ "Links": {
+ "Drives": [
+ {
+ ODATA_ID: PHYSICAL_DISK_SECOND
+ }
+ ]
+ },
+ },
+ },
+ "Oem": {
+ "Dell": {
+ "DellControllerBattery": {
+ "Id": "Battery.Integrated.1:RAID.SL.5-3"
+ }}
+ }
+ }
+ }
+ }
+
+ storage_data_expected_idrac8 = {
+ 'Controller': {
+ CONTROLLER_ID_FIFTH: {
+ 'ControllerSensor': {
+ CONTROLLER_ID_FIFTH: {},
+ },
+ 'Enclosure': {
+ ENCLOSURE_ID: {
+ 'EnclosureSensor': {
+ ENCLOSURE_ID: {},
+ },
+ 'PhysicalDisk': [
+ PHYSICAL_DISK_SECOND,
+ ],
+ },
+ },
+ 'VirtualDisk': {
+ 'Disk.Virtual.0:RAID.SL.5-3': {
+ 'PhysicalDisk': [
+ PHYSICAL_DISK_SECOND,
+ ],
+ },
+ 'Disk.Virtual.1:RAID.SL.5-3': {
+ 'PhysicalDisk': [
+ PHYSICAL_DISK_SECOND,
+ ],
+ },
+ },
+ },
+ }
+ }
+
+ @pytest.fixture
+ def idrac_storage_volume_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_storage_volume_mock(self, mocker, idrac_storage_volume_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_storage_volume_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_storage_volume_mock
+ return idrac_conn_mock
+
+ def test_fetch_controllers_uri(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ def mock_get_dynamic_uri_request(*args, **kwargs):
+ return self.storage_controllers
+
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(SYSTEM, ''))
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=mock_get_dynamic_uri_request)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageData(
+ idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.fetch_controllers_uri()
+ assert data == self.storage_controllers
+
+ # Scenario 2: for error message
+ mocker.patch(MODULE_PATH + "validate_and_get_first_resource_id_uri",
+ return_value=(REDFISH, "Error"))
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageData(
+ idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.fetch_controllers_uri()
+ assert exc.value.args[0] == "Error"
+
+ def test_fetch_api_data(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ key = "Storage"
+ obj = MagicMock()
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageData(idrac_connection_storage_volume_mock, f_module)
+ key_out, uri_data_out = idr_obj.fetch_api_data(self.storage_controllers[ODATA_ID], -1)
+ assert key == key_out
+ assert obj == uri_data_out
+
+ def test_all_storage_data(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ def mock_get_dynamic_uri_request(*args, **kwargs):
+ if len(args) == 3 and args[2] == "Members":
+ return self.volumes_list
+ else:
+ return self.controllers_list
+ mocker.patch(MODULE_PATH + "StorageData.fetch_controllers_uri",
+ return_value=self.storage_controllers)
+ mocker.patch(MODULE_PATH + "get_dynamic_uri",
+ side_effect=mock_get_dynamic_uri_request)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageData(idrac_connection_storage_volume_mock, f_module)
+ storage_info = idr_obj.all_storage_data()
+ assert set(storage_info.keys()) == {'Controllers'}
+ assert set(storage_info["Controllers"].keys()) == {CONTROLLER_ID_FIRST, CONTROLLER_ID_FOURTH}
+
+ def test_fetch_storage_data(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=self.storage_data)
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version",
+ return_value="3.20.00")
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageData(idrac_connection_storage_volume_mock, f_module)
+ storage_info = idr_obj.fetch_storage_data()
+ assert storage_info == self.storage_data_expected
+
+ # Scenario - for idrac 8
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=self.storage_data_idrac8)
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version",
+ return_value="2.00")
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageData(idrac_connection_storage_volume_mock, f_module)
+ storage_info = idr_obj.fetch_storage_data()
+ assert storage_info == self.storage_data_expected_idrac8
+
+
+class TestStorageView(TestStorageData):
+ module = idrac_storage_volume
+
+ @pytest.fixture
+ def idrac_storage_volume_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_storage_volume_mock(self, mocker, idrac_storage_volume_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_storage_volume_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_storage_volume_mock
+ return idrac_conn_mock
+
+ def test_execute(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data_expected)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageView(idrac_connection_storage_volume_mock, f_module)
+ out = idr_obj.execute()
+ assert out == {"Message": TestStorageData.storage_data_expected, "Status": SUCCESS_STATUS}
+
+ # Scenario - When controller_id is passed
+ data_when_controller_id_passed = deepcopy(TestStorageData.storage_data_expected)
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=data_when_controller_id_passed)
+ idrac_default_args.update({"controller_id": CONTROLLER_ID_FIRST})
+ out = idr_obj.execute()
+ assert out == {"Message": data_when_controller_id_passed, "Status": SUCCESS_STATUS}
+
+ # Scenario - When invalid controller_id is passed
+ data_when_invlid_controller_id_passed = deepcopy(TestStorageData.storage_data_expected)
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=data_when_invlid_controller_id_passed)
+ controller_id = "AHCI.Embedded.1-invalid"
+ idrac_default_args.update({"controller_id": controller_id})
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == VIEW_OPERATION_FAILED
+
+ # Scenario - When volume_id and invalid controller_id is passed
+ data_when_invlid_volume_id_passed = deepcopy(TestStorageData.storage_data_expected)
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=data_when_invlid_volume_id_passed)
+ idrac_default_args.update({"volume_id": VIRTUAL_DISK_FIRST})
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == VIEW_OPERATION_FAILED
+ # VIEW_CONTROLLER_DETAILS_NOT_FOUND.format(controller_id=controller_id)
+
+ # Scenario - When volume_id and valid controller_id is passed
+ data_when_controller_id_and_volume_id_passed = deepcopy(TestStorageData.storage_data_expected)
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=data_when_controller_id_and_volume_id_passed)
+ idrac_default_args.update({"controller_id": CONTROLLER_ID_FOURTH, "volume_id": VIRTUAL_DISK_FIRST})
+ out = idr_obj.execute()
+ assert out == {"Message": data_when_controller_id_and_volume_id_passed, "Status": SUCCESS_STATUS}
+
+ # Scenario - When invalid volume_id and valid controller_id is passed
+ data_when_controller_id_and_volume_id_passed = deepcopy(TestStorageData.storage_data_expected)
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=data_when_controller_id_and_volume_id_passed)
+ idrac_default_args.update({"controller_id": CONTROLLER_ID_FIRST, "volume_id": VIRTUAL_DISK_FIRST})
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == VIEW_OPERATION_FAILED
+
+ # Scenario - When volume_id is passed
+ data_when_volume_id_passed = deepcopy(TestStorageData.storage_data_expected)
+ mocker.patch(MODULE_PATH + FETCH_STORAGE_DATA_METHOD,
+ return_value=data_when_volume_id_passed)
+ del idrac_default_args["controller_id"]
+ idrac_default_args.update({"volume_id": VIRTUAL_DISK_FIRST})
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == VIEW_OPERATION_FAILED
+
+
+class TestStorageBase(FakeAnsibleModule):
+ module = idrac_storage_volume
+
+ @pytest.fixture
+ def idrac_storage_volume_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_storage_volume_mock(self, mocker, idrac_storage_volume_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_storage_volume_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_storage_volume_mock
+ return idrac_conn_mock
+
+ def test_module_extend_input(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + 'StorageBase.data_conversion', return_value={})
+ idrac_default_args.update({'span_length': 1, 'span_depth': 1})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.module_extend_input(f_module)
+ # Scenario 1: when volumes is None
+ assert data['volumes'] == [{'drives': {'id': [-1]}}]
+
+ # Scenario 2: when volumes is given
+ idrac_default_args.update({'volumes': [{"drives": {'location': [3]}, 'span_length': '1'}]})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ mocker.patch(MODULE_PATH + 'StorageBase.data_conversion', return_value={"drives": {'location': [3]}, 'span_length': '1'})
+
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.module_extend_input(f_module)
+ assert data['volumes'] == [{"drives": {'location': [3]}, 'span_length': 1}]
+
+ def test_payload_for_disk(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: When drives is given
+ data = idr_obj.payload_for_disk({'drives': {'id': [1, 2]}})
+ assert data == '<Attribute Name="IncludedPhysicalDiskID">1</Attribute><Attribute Name="IncludedPhysicalDiskID">2</Attribute>'
+
+ # Scenario 2: When dedicate_hot_spare is in each_volume
+ data = idr_obj.payload_for_disk({'dedicated_hot_spare': [3, 5]})
+ assert data == '<Attribute Name="RAIDdedicatedSpare">3</Attribute><Attribute Name="RAIDdedicatedSpare">5</Attribute>'
+
+ def test_construct_volume_payloadk(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + 'xml_data_conversion', return_value=DATA_XML)
+ mocker.patch(MODULE_PATH + 'StorageBase.payload_for_disk', return_value='payload_detail_in_xml')
+ # Scenario 1: When state is create
+ idrac_default_args.update({'state': 'create'})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.construct_volume_payload(1, {})
+ assert data == DATA_XML
+
+ def test_constuct_payload(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + 'xml_data_conversion', return_value=DATA_XML)
+ mocker.patch(MODULE_PATH + 'StorageBase.construct_volume_payload', return_value='<Volume></Volume>')
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: Default
+ data = idr_obj.constuct_payload({})
+ assert data == DATA_XML
+
+ # Scenario 2: When raid_reset_config is 'true'
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module_ext_params.update({'raid_reset_config': 'true'})
+ data = idr_obj.constuct_payload({})
+ assert data == DATA_XML
+
+ def test_wait_for_job_completion(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ obj = MagicMock()
+ obj.headers = {'Location': "/joburl/JID12345"}
+ job = {"job_wait": True, "job_wait_timeout": 1200}
+ idrac_default_args.update(job)
+ job_resp_completed = {'JobStatus': 'Completed'}
+ idrac_redfish_resp = (False, 'Job Success', job_resp_completed, 1200)
+ mocker.patch(MODULE_PATH + 'idrac_redfish_job_tracking', return_value=idrac_redfish_resp)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: Job_wait is True, job_wait_timeout match with default
+ with pytest.raises(Exception) as exc:
+ idr_obj.wait_for_job_completion(obj)
+ assert exc.value.args[0] == WAIT_TIMEOUT_MSG.format(1200)
+
+ # Scenario 2: Job_wait is True, job_wait_timeout less than default
+ idrac_redfish_resp = (False, 'Job Success', job_resp_completed, 1000)
+ mocker.patch(MODULE_PATH + 'idrac_redfish_job_tracking', return_value=idrac_redfish_resp)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.wait_for_job_completion(obj)
+ assert data == job_resp_completed
+
+ # Scenario 3: Job failed in resp
+ job_resp_failed = {'JobStatus': 'Failed', 'Message': 'Job failed.'}
+ idrac_redfish_resp = (True, 'Job Failed', job_resp_failed, 1000)
+ mocker.patch(MODULE_PATH + 'idrac_redfish_job_tracking', return_value=idrac_redfish_resp)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.wait_for_job_completion(obj)
+ assert exc.value.args[0] == 'Job failed.'
+
+ # Scenario 4: Job wait is false
+ obj.json_data = {'JobStatus': 'Running'}
+ mocker.patch(MODULE_PATH + API_INVOKE_MOCKER, return_value=obj)
+ job = {"job_wait": False, "job_wait_timeout": 1200}
+ idrac_default_args.update(job)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ f_module.params.update({'state': 'create'})
+ idr_obj = self.module.StorageBase(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.wait_for_job_completion(obj)
+ assert exc.value.args[0] == JOB_TRIGERRED.format('create')
+
+
+class TestStorageValidation(TestStorageBase):
+ module = idrac_storage_volume
+
+ @pytest.fixture
+ def idrac_storage_volume_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_storage_volume_mock(self, mocker, idrac_storage_volume_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_storage_volume_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_storage_volume_mock
+ return idrac_conn_mock
+
+ def test_validate_controller_exists(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ # Scenario - when controller_id is not passed
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_controller_exists()
+ assert exc.value.args[0] == CONTROLLER_NOT_DEFINED
+
+ # Scenario - when invalid controller_id is passed
+ controller_id = "AHCI.Embedded.1-invalid"
+ idrac_default_args.update({"controller_id": controller_id})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_controller_exists()
+ assert exc.value.args[0] == CONTROLLER_NOT_EXIST_ERROR.format(controller_id=controller_id)
+
+ # Scenario - when controller_id is passed
+ controller_id = CONTROLLER_ID_FIRST
+ idrac_default_args.update({"controller_id": controller_id})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.validate_controller_exists()
+
+ def test_validate_job_wait_negative_values(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ # Scenario - when job_wait_timeout is negative
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data)
+ idrac_default_args.update({"job_wait": True, "job_wait_timeout": -120})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_job_wait_negative_values()
+ assert exc.value.args[0] == NEGATIVE_OR_ZERO_MSG.format(parameter="job_wait_timeout")
+
+ # Scenario - when job_wait_timeout is positive
+ idrac_default_args.update({"job_wait": True, "job_wait_timeout": 120})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.validate_job_wait_negative_values()
+
+ @pytest.mark.parametrize("params", [
+ {"span_depth": -1, "span_length": 2, "capacity": 200, "strip_size": 131072},
+ {"span_depth": 1, "span_length": -1, "capacity": 200, "strip_size": 131072},
+ {"span_depth": 1, "span_length": 2, "capacity": -1, "strip_size": 131072},
+ {"span_depth": 1, "span_length": 2, "capacity": 200, "strip_size": -131072},
+ ])
+ def test_validate_negative_values_for_volume_params(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker, params):
+ # Scenario - when job_wait_timeout is negative
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data)
+ # idrac_default_args.update(params)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_negative_values_for_volume_params(params)
+ # TO DO replace job_wait_timeout with key in params which has negative value
+ negative_key = next((k for k, v in params.items() if v < 0), None)
+ assert exc.value.args[0] == NEGATIVE_OR_ZERO_MSG.format(parameter=negative_key)
+
+ def test_validate_negative_values_for_volume_params_with_different_parameter(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ # Scenario - passing different parameter
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.validate_negative_values_for_volume_params({"volume_type": "RAID 0", "number_dedicated_hot_spare": 0})
+
+ # Scenario - when number_dedicated_hot_spare is negative
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_negative_values_for_volume_params({"number_dedicated_hot_spare": -1})
+ assert exc.value.args[0] == NEGATIVE_MSG.format(parameter="number_dedicated_hot_spare")
+
+ # Scenario - when number_dedicated_hot_spare is not negative
+ idr_obj.validate_negative_values_for_volume_params({"number_dedicated_hot_spare": 0})
+
+ def test_validate_volume_drives(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ # Scenario - when volume drives are not defined
+ volumes = {
+ "name": "volume_1"
+ }
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_volume_drives(volumes)
+ assert exc.value.args[0] == DRIVES_NOT_DEFINED
+
+ # Scenario - when in volume drives id and location both defined
+ volumes = {
+ "name": "volume_1",
+ "drives": {
+ "id": [
+ PHYSICAL_DISK_FIRST,
+ PHYSICAL_DISK_SECOND
+ ],
+ "location": [7, 3]
+ }
+ }
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_volume_drives(volumes)
+ assert exc.value.args[0] == ID_AND_LOCATION_BOTH_DEFINED
+
+ # Scenario - when in volume drives id and location both not defined
+ volumes = {
+ "name": "volume_1",
+ "drives": {
+ PHYSICAL_DISK_FIRST: {}
+ }
+ }
+ with pytest.raises(Exception) as exc:
+ idr_obj.validate_volume_drives(volumes)
+ assert exc.value.args[0] == ID_AND_LOCATION_BOTH_NOT_DEFINED
+
+ # Scenario - when in volume drives id is defined
+ volumes = {
+ "name": "volume_1",
+ "drives": {
+ "id": [
+ PHYSICAL_DISK_FIRST,
+ PHYSICAL_DISK_SECOND
+ ]
+ }
+ }
+ mocker.patch(MODULE_PATH + "StorageValidation.raid_std_validation",
+ return_value=True)
+ out = idr_obj.validate_volume_drives(volumes)
+ assert out is True
+
+ def test_raid_std_validation(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD,
+ return_value=TestStorageData.storage_data)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageValidation(idrac_connection_storage_volume_mock, f_module)
+ # Scenario - Invalid span_length
+ params = {"span_depth": 1, "span_length": 4, "pd_count": 2, "volume_type": "RAID 1"}
+ with pytest.raises(Exception) as exc:
+ idr_obj.raid_std_validation(params["span_length"],
+ params["span_depth"],
+ params["volume_type"],
+ params["pd_count"])
+ assert exc.value.args[0] == INVALID_VALUE_MSG.format(parameter="span_length")
+
+ # Scenario - Invalid span_depth for RAID 1
+ params = {"span_depth": 4, "span_length": 2, "pd_count": 3, "volume_type": "RAID 1"}
+ with pytest.raises(Exception) as exc:
+ idr_obj.raid_std_validation(params["span_length"],
+ params["span_depth"],
+ params["volume_type"],
+ params["pd_count"])
+ assert exc.value.args[0] == INVALID_VALUE_MSG.format(parameter="span_depth")
+
+ # Scenario - Invalid span_depth for RAID 10
+ params = {"span_depth": 1, "span_length": 2, "pd_count": 9, "volume_type": "RAID 10"}
+ with pytest.raises(Exception) as exc:
+ idr_obj.raid_std_validation(params["span_length"],
+ params["span_depth"],
+ params["volume_type"],
+ params["pd_count"])
+ assert exc.value.args[0] == INVALID_VALUE_MSG.format(parameter="span_depth")
+
+ # Scenario - Invalid drive count
+ params = {"span_depth": 3, "span_length": 2, "pd_count": 1, "volume_type": "RAID 10"}
+ with pytest.raises(Exception) as exc:
+ idr_obj.raid_std_validation(params["span_length"],
+ params["span_depth"],
+ params["volume_type"],
+ params["pd_count"])
+ assert exc.value.args[0] == INVALID_VALUE_MSG.format(parameter="drives")
+
+ # Scenario - Valid
+ params = {"span_depth": 2, "span_length": 2, "pd_count": 4, "volume_type": "RAID 10"}
+ out = idr_obj.raid_std_validation(params["span_length"],
+ params["span_depth"],
+ params["volume_type"],
+ params["pd_count"])
+ assert out is True
+
+
+class TestStorageCreate(TestStorageBase):
+ module = idrac_storage_volume
+
+ @pytest.fixture
+ def idrac_storage_volume_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_storage_volume_mock(self, mocker, idrac_storage_volume_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_storage_volume_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_storage_volume_mock
+ return idrac_conn_mock
+
+ def test_disk_slot_id_conversion(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ # Scenario 1: location is given in drives
+ volume = {'drives': {'location': [0, 1]}}
+ idrac_default_args.update({"controller_id": CONTROLLER_ID_SECOND})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.disk_slot_location_to_id_conversion(volume)
+ assert data['id'] == TestStorageData.storage_data_expected['Controller'][CONTROLLER_ID_SECOND]['PhysicalDisk']
+
+ # Scenario 2: id is given in drives
+ id_list = ['Disk.Bay.3:Enclosure.Internal.0-1:AHCI.Embedded.1-2',
+ 'Disk.Bay.2:Enclosure.Internal.0-1:AHCI.Embedded.1-2']
+ volume = {'drives': {'id': id_list}}
+ idrac_default_args.update({"controller_id": CONTROLLER_ID_SECOND})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.disk_slot_location_to_id_conversion(volume)
+ assert data['id'] == id_list
+
+ # Scenario 3: When id and location is not given in drives
+ volume = {'drives': {}}
+ data = idr_obj.disk_slot_location_to_id_conversion(volume)
+ assert data == {}
+
+ def test_perform_intersection_on_disk(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ # Scenario 1: When iDRAC has firmware version greater than 3.00.00.00
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="3.10.00")
+ volume = {'media_type': 'HDD', 'protocol': 'SATA'}
+ healthy_disk, available_disk, media_disk, protocol_disk = {1, 2, 3, 4, 5}, {1, 2, 3, 5}, {2, 3, 4, 5}, {1, 5}
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.perform_intersection_on_disk(volume, healthy_disk, available_disk, media_disk, protocol_disk)
+ assert data == [5]
+
+ # Scenario 1: When iDRAC has firmware version less than 3.00.00.00
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="2.00.00")
+ volume = {'media_type': None, 'protocol': None}
+ data = idr_obj.perform_intersection_on_disk(volume, healthy_disk, available_disk, media_disk, protocol_disk)
+ assert data == [1, 2, 3, 4, 5]
+
+ def test_filter_disk(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ drive_resp = {'DriveID1': {'MediaType': 'HDD', 'Protocol': 'SAS', 'Status': {'Health': 'OK'},
+ 'Oem': {'Dell': {'DellPhysicalDisk': {'RaidStatus': 'Ready'}}}},
+ 'DriveID2': {'MediaType': 'SSD', 'Protocol': 'SATA', 'Status': {'Health': 'Not OK'}}}
+ idrac_data = {'Controllers': {CONTROLLER_ID_FIRST: {'Drives': drive_resp}}}
+ # Scenario 1: When iDRAC has firmware version equal to 3.00.00.00
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=idrac_data)
+ mocker.patch(MODULE_PATH + "get_idrac_firmware_version", return_value="3.05.00")
+ volume = {'media_type': 'HDD', 'protocol': 'SAS'}
+ idrac_default_args.update({"controller_id": CONTROLLER_ID_FIRST})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ data = idr_obj.filter_disk(volume)
+ assert data == ['DriveID1']
+
+ def test_updating_drives_module_input_when_given(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: When id is in drives
+ volume = {'drives': {'id': [2, 3, 4, 5]}}
+ filter_disk_output = [1, 3, 5]
+ data = idr_obj.updating_drives_module_input_when_given(volume, filter_disk_output)
+ assert data == [3, 5]
+
+ # Scenario 2: When id is not in drives
+ volume = {'drives': {'location': [2, 3, 4, 5]}}
+ data = idr_obj.updating_drives_module_input_when_given(volume, filter_disk_output)
+ assert data == []
+
+ def test_updating_volume_module_input_for_hotspare(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: number_dedicated_hot_spare is in volume and greator than zero
+ volume = {'number_dedicated_hot_spare': 2}
+ filter_disk_output = [1, 3, 5, 4, 2]
+ reserved_pd = [1]
+ drive_exists_in_id = [3, 5]
+ data = idr_obj.updating_volume_module_input_for_hotspare(volume, filter_disk_output, reserved_pd, drive_exists_in_id)
+ assert data == [4, 2]
+
+ # Scenario 2: number_dedicated_hot_spare is in volume and equal to zero
+ volume = {'number_dedicated_hot_spare': 0}
+ data = idr_obj.updating_volume_module_input_for_hotspare(volume, filter_disk_output, reserved_pd, drive_exists_in_id)
+ assert data == []
+
+ def test_updating_volume_module_input(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ mocker.patch(MODULE_PATH + FILTER_DISK, return_value=[1, 2, 3, 4, 5])
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: When required pd is less than available pd
+ volume = {'volumes': [{'span_depth': 1, 'span_length': 1, 'stripe_size': 65536, 'capacity': 50.45,
+ 'drives': {'id': [2, 3, 4]},
+ 'number_dedicated_hot_spare': 1}]}
+ idr_obj.module_ext_params.update(volume)
+ drive_exists_in_id = [1, 2]
+ idr_obj.updating_volume_module_input(drive_exists_in_id)
+ assert idr_obj.module_ext_params['volumes'][0]['drives']['id'] == [1]
+
+ # Scenario 2: When required pd is less than available pd with check_mode
+ volume = {'volumes': [{'span_depth': 1, 'span_length': 1, 'stripe_size': 65536, 'capacity': 50.45,
+ 'drives': {'id': [2, 3, 4]},
+ 'number_dedicated_hot_spare': 1}]}
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module_ext_params.update(volume)
+ drive_exists_in_id = [1, 2]
+ with pytest.raises(Exception) as exc:
+ idr_obj.updating_volume_module_input(drive_exists_in_id)
+ assert exc.value.args[0] == CHANGES_FOUND
+
+ # Scenario 3: When required pd is greater than available pd
+ mocker.patch(MODULE_PATH + FILTER_DISK, return_value=[1])
+ controller_id = 'Qwerty'
+ volume = {'volumes': [{'span_depth': 2, 'span_length': 1,
+ 'drives': {'id': [1]}, 'number_dedicated_hot_spare': 0}],
+ 'controller_id': controller_id}
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module_ext_params.update(volume)
+ drive_exists_in_id = [1, 2]
+ with pytest.raises(Exception) as exc:
+ idr_obj.updating_volume_module_input(drive_exists_in_id)
+ assert exc.value.args[0] == NOT_ENOUGH_DRIVES.format(controller_id=controller_id)
+
+ # Scenario 4: When required pd is greater than available pd with check_mode
+ mocker.patch(MODULE_PATH + FILTER_DISK, return_value=[1])
+ controller_id = 'Qwerty'
+ volume = {'volumes': [{'span_depth': 2, 'span_length': 1,
+ 'drives': {'id': [1, 2]}, 'number_dedicated_hot_spare': 0}],
+ 'controller_id': controller_id}
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module_ext_params.update(volume)
+ drive_exists_in_id = [1]
+ with pytest.raises(Exception) as exc:
+ idr_obj.updating_volume_module_input(drive_exists_in_id)
+ assert exc.value.args[0] == CHANGES_NOT_FOUND
+
+ def test_validate_create(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ mocker.patch(MODULE_PATH + 'StorageValidation.validate_controller_exists', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageValidation.validate_job_wait_negative_values', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageValidation.validate_negative_values_for_volume_params', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageValidation.validate_volume_drives', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageCreate.updating_volume_module_input', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageCreate.disk_slot_location_to_id_conversion', return_value={'id': []})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ # Scenario 1: When required pd is less than available pd
+ volume = {'volumes': [{'drives': {'location': [2, 3, 4]}},
+ {'drives': {'id': [1]}}]}
+ idr_obj.module_ext_params.update(volume)
+ idr_obj.validate()
+ assert idr_obj.module_ext_params['volumes'][0]['drives']['id'] == []
+
+ def test_execute_create(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=TestStorageData.storage_data)
+ mocker.patch(MODULE_PATH + 'StorageCreate.validate', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageBase.constuct_payload', return_value=None)
+ mocker.patch(MODULE_PATH + 'iDRACRedfishAPI.import_scp', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageBase.wait_for_job_completion', return_value={})
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageCreate(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.controller_id = CONTROLLER_ID_FOURTH
+ data = idr_obj.execute()
+ assert data == {}
+
+
+class TestStorageDelete(TestStorageBase):
+ module = idrac_storage_volume
+
+ @pytest.fixture
+ def idrac_storage_volume_mock(self):
+ idrac_obj = MagicMock()
+ return idrac_obj
+
+ @pytest.fixture
+ def idrac_connection_storage_volume_mock(self, mocker, idrac_storage_volume_mock):
+ idrac_conn_mock = mocker.patch(MODULE_PATH + 'iDRACRedfishAPI',
+ return_value=idrac_storage_volume_mock)
+ idrac_conn_mock.return_value.__enter__.return_value = idrac_storage_volume_mock
+ return idrac_conn_mock
+
+ def test_execute_delete(self, idrac_default_args, idrac_connection_storage_volume_mock, mocker):
+ idrac_resp = {'Controllers': {'Cntrl1': {'Volumes': {'Volume_ID1': {'Name': 'Volume Name 1'}}}}}
+ mocker.patch(MODULE_PATH + ALL_STORAGE_DATA_METHOD, return_value=idrac_resp)
+ mocker.patch(MODULE_PATH + 'StorageDelete.validate', return_value=None)
+ mocker.patch(MODULE_PATH + 'iDRACRedfishAPI.import_scp', return_value=None)
+ mocker.patch(MODULE_PATH + 'StorageBase.wait_for_job_completion', return_value={})
+ mocker.patch(MODULE_PATH + 'StorageBase.module_extend_input', return_value={})
+
+ # Scenario 1: When Non existing volume is passed as input
+ volume = {'volumes': [{'name': 'volume-1', 'span_depth': 1, 'span_length': 1},
+ {'name': 'volume-2', 'span_depth': 1, 'span_length': 1}]}
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageDelete(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module.params.update(volume)
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == VOLUME_NOT_FOUND
+
+ # Scenario 2: When Non existing volume is passed as input with check_mode
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageDelete(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module.params.update(volume)
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == VOLUME_NOT_FOUND
+
+ # Scenario 3: When Existing volume is passed as input
+ volume = {'volumes': [{'name': 'Volume Name 1', 'span_depth': 1, 'span_length': 1}]}
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idr_obj = self.module.StorageDelete(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module.params.update(volume)
+ idr_obj.module_ext_params.update({'state': 'delete', 'volumes': volume})
+ data = idr_obj.execute()
+ assert data == {}
+
+ # Scenario 3: When Existing volume is passed as input with check_mode
+ f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ idr_obj = self.module.StorageDelete(idrac_connection_storage_volume_mock, f_module)
+ idr_obj.module.params.update(volume)
+ idr_obj.module_ext_params.update({'state': 'delete', 'volumes': volume})
+ with pytest.raises(Exception) as exc:
+ idr_obj.execute()
+ assert exc.value.args[0] == CHANGES_FOUND
+
+ def test_idrac_storage_volume_main_positive_case(self, idrac_default_args,
+ idrac_connection_storage_volume_mock, mocker):
+ def returning_none():
+ return None
+ mocker.patch(MODULE_PATH + VIEW_EXECUTE, return_value=returning_none)
+ view = 'view'
+ idrac_default_args.update({'state': view})
+ data = self._run_module(idrac_default_args)
+ assert data['msg'] == SUCCESSFUL_OPERATION_MSG.format(operation=view)
+
+ @pytest.mark.parametrize("exc_type",
+ [URLError, HTTPError, SSLValidationError, ConnectionError, TypeError, ValueError])
+ def test_idrac_storage_volume_main_exception_handling_case(self, exc_type, idrac_default_args,
+ idrac_connection_storage_volume_mock, mocker):
+
+ json_str = to_text(json.dumps({"data": "out"}))
+ if exc_type in [HTTPError, SSLValidationError]:
+ mocker.patch(MODULE_PATH + VIEW_EXECUTE,
+ side_effect=exc_type('https://testhost.com', 400,
+ 'http error message',
+ {"accept-type": "application/json"},
+ StringIO(json_str)))
+ else:
+ mocker.patch(MODULE_PATH + VIEW_EXECUTE,
+ side_effect=exc_type('test'))
+ result = self._run_module(idrac_default_args)
+ if exc_type == URLError:
+ assert result['unreachable'] is True
+ else:
+ assert result['failed'] is True
+ assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_user.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_user.py
index 0ef6e6da3..6087f140f 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_user.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_idrac_user.py
@@ -22,6 +22,24 @@ from ansible.module_utils._text import to_text
from io import StringIO
MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.'
+VERSION = "3.60.60.60"
+VERSION13G = "2.70.70.70"
+SLOT_API = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/"
+CHANGES_FOUND = "Changes found to commit!"
+SLEEP_PATH = 'idrac_user.time.sleep'
+USERNAME2 = "Users.2#UserName"
+GET_PAYLOAD = "idrac_user.get_payload"
+PAYLOAD_XML = "idrac_user.convert_payload_xml"
+XML_DATA = "<xml-data>"
+USERNAME1 = "Users.1#UserName"
+IMPORT_SCP = "idrac_user.iDRACRedfishAPI.import_scp"
+USER2 = "User.2#UserName"
+SUCCESS_CREATED = "Successfully created a request."
+SUCCESS_MSG = "Successfully created user account."
+SUCCESS_UPDATED = "Successfully updated user account."
+INVOKE_REQUEST = "idrac_user.iDRACRedfishAPI.invoke_request"
+CM_ACCOUNT = "idrac_user.create_or_modify_account"
+USER_PRIVILAGE = "Users.1#Privilege"
class TestIDRACUser(FakeAnsibleModule):
@@ -78,7 +96,7 @@ class TestIDRACUser(FakeAnsibleModule):
"Users.1.ProtocolEnable": idrac_default_args["protocol_enable"],
"Users.1.AuthenticationProtocol": idrac_default_args["authentication_protocol"],
"Users.1.PrivacyProtocol": idrac_default_args["privacy_protocol"]}
- xml_payload, json_payload = self.module.convert_payload_xml(payload)
+ _xml, json_payload = self.module.convert_payload_xml(payload)
assert json_payload["Users.1#SolEnable"] is True
def test_remove_user_account_check_mode_1(self, idrac_connection_user_mock, idrac_default_args, mocker):
@@ -87,12 +105,14 @@ class TestIDRACUser(FakeAnsibleModule):
"ipmi_serial_privilege": None, "enable": False, "sol_enable": False,
"protocol_enable": False, "authentication_protocol": "SHA",
"privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=True)
slot_id = 1
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
+ slot_uri = SLOT_API.format(slot_id)
with pytest.raises(Exception) as exc:
- self.module.remove_user_account(f_module, idrac_connection_user_mock, slot_uri, slot_id)
- assert exc.value.args[0] == "Changes found to commit!"
+ self.module.remove_user_account(
+ f_module, idrac_connection_user_mock, slot_uri, slot_id)
+ assert exc.value.args[0] == CHANGES_FOUND
def test_remove_user_account_check_mode_2(self, idrac_connection_user_mock, idrac_default_args, mocker):
idrac_default_args.update({"state": "absent", "user_name": "user_name", "new_user_name": None,
@@ -100,9 +120,11 @@ class TestIDRACUser(FakeAnsibleModule):
"ipmi_serial_privilege": None, "enable": False, "sol_enable": False,
"protocol_enable": False, "authentication_protocol": "SHA",
"privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=True)
with pytest.raises(Exception) as exc:
- self.module.remove_user_account(f_module, idrac_connection_user_mock, None, None)
+ self.module.remove_user_account(
+ f_module, idrac_connection_user_mock, None, None)
assert exc.value.args[0] == "No changes found to commit!"
def test_remove_user_account_check_mode_3(self, idrac_connection_user_mock, idrac_default_args, mocker):
@@ -111,12 +133,15 @@ class TestIDRACUser(FakeAnsibleModule):
"ipmi_serial_privilege": None, "enable": False, "sol_enable": False,
"protocol_enable": False, "authentication_protocol": "SHA",
"privacy_protocol": "AES"})
- idrac_connection_user_mock.remove_user_account.return_value = {"success": True}
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idrac_connection_user_mock.remove_user_account.return_value = {
+ "success": True}
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
slot_id = 1
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- mocker.patch(MODULE_PATH + 'idrac_user.time.sleep', return_value=None)
- self.module.remove_user_account(f_module, idrac_connection_user_mock, slot_uri, slot_id)
+ slot_uri = SLOT_API.format(slot_id)
+ mocker.patch(MODULE_PATH + SLEEP_PATH, return_value=None)
+ self.module.remove_user_account(
+ f_module, idrac_connection_user_mock, slot_uri, slot_id)
def test_remove_user_account_check_mode_4(self, idrac_connection_user_mock, idrac_default_args, mocker):
idrac_default_args.update({"state": "absent", "user_name": "user_name", "new_user_name": None,
@@ -124,10 +149,13 @@ class TestIDRACUser(FakeAnsibleModule):
"ipmi_serial_privilege": None, "enable": False, "sol_enable": False,
"protocol_enable": False, "authentication_protocol": "SHA",
"privacy_protocol": "AES"})
- idrac_connection_user_mock.remove_user_account.return_value = {"success": True}
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ idrac_connection_user_mock.remove_user_account.return_value = {
+ "success": True}
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
with pytest.raises(Exception) as exc:
- self.module.remove_user_account(f_module, idrac_connection_user_mock, None, None)
+ self.module.remove_user_account(
+ f_module, idrac_connection_user_mock, None, None)
assert exc.value.args[0] == 'The user account is absent.'
def test_get_user_account_1(self, idrac_connection_user_mock, idrac_default_args, mocker):
@@ -140,10 +168,12 @@ class TestIDRACUser(FakeAnsibleModule):
mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.export_scp",
return_value=MagicMock())
mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.get_idrac_local_account_attr",
- return_value={"Users.2#UserName": "test_user", "Users.3#UserName": ""})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- response = self.module.get_user_account(f_module, idrac_connection_user_mock)
- assert response[0]["Users.2#UserName"] == "test_user"
+ return_value={USERNAME2: "test_user", "Users.3#UserName": ""})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ response = self.module.get_user_account(
+ f_module, idrac_connection_user_mock)
+ assert response[0][USERNAME2] == "test_user"
assert response[3] == 3
assert response[4] == "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/3"
@@ -157,9 +187,11 @@ class TestIDRACUser(FakeAnsibleModule):
mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.export_scp",
return_value=MagicMock())
mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.get_idrac_local_account_attr",
- return_value={"Users.2#UserName": "test_user", "Users.3#UserName": "test"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- response = self.module.get_user_account(f_module, idrac_connection_user_mock)
+ return_value={USERNAME2: "test_user", "Users.3#UserName": "test"})
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ response = self.module.get_user_account(
+ f_module, idrac_connection_user_mock)
assert response[2] == 3
assert response[1] == "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/3"
@@ -170,227 +202,93 @@ class TestIDRACUser(FakeAnsibleModule):
"ipmi_serial_privilege": "Administrator", "enable": True,
"sol_enable": True, "protocol_enable": True,
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
with pytest.raises(Exception) as err:
self.module.get_user_account(f_module, idrac_connection_user_mock)
assert err.value.args[0] == "User name is not valid."
- def test_create_or_modify_account_1(self, idrac_connection_user_mock, idrac_default_args, mocker):
+ @pytest.mark.parametrize("params", [
+ {"ret_val": SUCCESS_MSG, "empty_slot_id": 2,
+ "empty_slot_uri": SLOT_API.format(2)},
+ {"ret_val": SUCCESS_UPDATED, "slot_id": 2,
+ "slot_uri": SLOT_API.format(2)},
+ {"firm_ver": (14, VERSION), "ret_val": SUCCESS_MSG,
+ "empty_slot_id": 2, "empty_slot_uri": SLOT_API.format(2)},
+ {"firm_ver": (14, VERSION), "ret_val": SUCCESS_UPDATED,
+ "slot_id": 2, "slot_uri": SLOT_API.format(2)},
+ {"firm_ver": (14, VERSION), "ret_val": SUCCESS_UPDATED, "slot_id": 2, "slot_uri": SLOT_API.format(2),
+ "empty_slot_id": 2, "empty_slot_uri": SLOT_API.format(2)},
+ ])
+ def test_create_or_modify_account(self, idrac_connection_user_mock, idrac_default_args, mocker, params):
idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
"user_name": "test", "user_password": "password",
"privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
"ipmi_serial_privilege": "Administrator", "enable": True,
"sol_enable": True, "protocol_enable": True,
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (13, "2.70.70.70")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.import_scp",
- return_value={"Message": "Successfully created a request."})
- empty_slot_id = 2
- empty_slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(empty_slot_id)
- user_attr = {"User.2#UserName": "test_user"}
- mocker.patch(MODULE_PATH + 'idrac_user.time.sleep', return_value=None)
- response = self.module.create_or_modify_account(f_module, idrac_connection_user_mock, None, None,
- empty_slot_id, empty_slot_uri, user_attr)
- assert response[1] == "Successfully created user account."
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
+ idrac_connection_user_mock.get_server_generation = params.get(
+ "firm_ver", (13, VERSION13G))
+ mocker.patch(MODULE_PATH + GET_PAYLOAD,
+ return_value={USERNAME2: "test_user"})
+ mocker.patch(MODULE_PATH + PAYLOAD_XML,
+ return_value=(XML_DATA, {USERNAME2: "test_user"}))
+ mocker.patch(MODULE_PATH + IMPORT_SCP,
+ return_value={"Message": SUCCESS_CREATED})
+ mocker.patch(MODULE_PATH + SLEEP_PATH, return_value=None)
+ mocker.patch(MODULE_PATH + INVOKE_REQUEST,
+ return_value={"Message": SUCCESS_CREATED})
+
+ empty_slot_id = params.get("empty_slot_id", None)
+ empty_slot_uri = params.get("empty_slot_uri", None)
+ slot_id = params.get("slot_id", None)
+ slot_uri = params.get("slot_uri", None)
+ user_attr = {USER2: "test_user"}
- def test_create_or_modify_account_2(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (13, "2.70.70.70")
- mocker.patch(MODULE_PATH + 'idrac_user.time.sleep', return_value=None)
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.import_scp",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"User.2#UserName": "test_user"}
response = self.module.create_or_modify_account(f_module, idrac_connection_user_mock, slot_uri, slot_id,
- None, None, user_attr)
- assert response[1] == "Successfully updated user account."
-
- def test_create_or_modify_account_3(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (13, "2.70.70.70")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.import_scp",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"Users.1#UserName": "test_user"}
- with pytest.raises(Exception) as exc:
- self.module.create_or_modify_account(f_module, idrac_connection_user_mock, slot_uri, slot_id,
- None, None, user_attr)
- assert exc.value.args[0] == "Requested changes are already present in the user slot."
-
- def test_create_or_modify_account_4(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
- idrac_connection_user_mock.get_server_generation = (13, "2.70.70.70")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.import_scp",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"Users.1#UserName": "test_user"}
- with pytest.raises(Exception) as exc:
- self.module.create_or_modify_account(f_module, idrac_connection_user_mock, slot_uri, slot_id,
- None, None, user_attr)
- assert exc.value.args[0] == "No changes found to commit!"
-
- def test_create_or_modify_account_5(self, idrac_connection_user_mock, idrac_default_args, mocker):
+ empty_slot_id, empty_slot_uri, user_attr)
+ assert response[1] == params.get("ret_val")
+
+ @pytest.mark.parametrize("params", [
+ {"ret_val": "Requested changes are already present in the user slot."},
+ {"firm_ver": (14, VERSION), "slot_id": None, "slot_uri": None,
+ "ret_val": "Maximum number of users reached. Delete a user account and retry the operation."},
+ {"check_mode": True, "ret_val": "No changes found to commit!"},
+ {"check_mode": True, "user_attr": {
+ USERNAME1: "test_user"}, "ret_val": CHANGES_FOUND},
+ {"check_mode": True, "user_attr": {USERNAME1: "test_user"}, "ret_val":
+ CHANGES_FOUND, "empty_slot_id": 2, "empty_slot_uri": SLOT_API.format(2)},
+ ])
+ def test_create_or_modify_account_exception(self, idrac_connection_user_mock, idrac_default_args, mocker, params):
idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
"user_name": "test", "user_password": "password",
"privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
"ipmi_serial_privilege": "Administrator", "enable": True,
"sol_enable": True, "protocol_enable": True,
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
- idrac_connection_user_mock.get_server_generation = (13, "2.70.70.70")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.2#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.import_scp",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"Users.1#UserName": "test_user"}
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=params.get("check_mode", False))
+ idrac_connection_user_mock.get_server_generation = params.get(
+ "firm_ver", (13, VERSION13G))
+ mocker.patch(MODULE_PATH + GET_PAYLOAD,
+ return_value={USERNAME2: "test_user"})
+ mocker.patch(MODULE_PATH + PAYLOAD_XML,
+ return_value=(XML_DATA, {USERNAME2: "test_user"}))
+ mocker.patch(MODULE_PATH + IMPORT_SCP,
+ return_value={"Message": SUCCESS_CREATED})
+ mocker.patch(MODULE_PATH + INVOKE_REQUEST,
+ return_value={"Message": SUCCESS_CREATED})
+ slot_id = params.get("slot_id", 2)
+ slot_uri = params.get("slot_uri", SLOT_API.format(2))
+ empty_slot_id = params.get("empty_slot_id", None)
+ empty_slot_uri = params.get("empty_slot_uri", None)
+ user_attr = params.get("user_attr", {USERNAME2: "test_user"})
with pytest.raises(Exception) as exc:
self.module.create_or_modify_account(f_module, idrac_connection_user_mock, slot_uri, slot_id,
- None, None, user_attr)
- assert exc.value.args[0] == "Changes found to commit!"
-
- def test_create_or_modify_account_6(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (14, "3.60.60.60")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.invoke_request",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"User.2#UserName": "test_user"}
- response = self.module.create_or_modify_account(f_module, idrac_connection_user_mock, None, None,
- slot_id, slot_uri, user_attr)
- assert response[1] == "Successfully created user account."
-
- def test_create_or_modify_account_7(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=True)
- idrac_connection_user_mock.get_server_generation = (14, "3.60.60.60")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.invoke_request",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"User.2#UserName": "test_user"}
- with pytest.raises(Exception) as exc:
- self.module.create_or_modify_account(f_module, idrac_connection_user_mock, None, None,
- slot_id, slot_uri, user_attr)
- assert exc.value.args[0] == "Changes found to commit!"
-
- def test_create_or_modify_account_8(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (14, "3.60.60.60")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.invoke_request",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"User.2#UserName": "test_user"}
- response = self.module.create_or_modify_account(f_module, idrac_connection_user_mock, slot_uri, slot_id,
- None, None, user_attr)
- assert response[1] == "Successfully updated user account."
-
- def test_create_or_modify_account_both_slot_empty_input(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (14, "3.60.60.60")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.invoke_request",
- return_value={"Message": "Successfully created a request."})
- slot_id = 2
- slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"User.2#UserName": "test_user"}
- response = self.module.create_or_modify_account(f_module, idrac_connection_user_mock, slot_id, slot_uri,
- slot_id, slot_uri, user_attr)
- assert response[1] == "Successfully updated user account."
-
- def test_create_or_modify_account_both_slot_empty_none_input(self, idrac_connection_user_mock, idrac_default_args, mocker):
- idrac_default_args.update({"state": "present", "new_user_name": "new_user_name",
- "user_name": "test", "user_password": "password",
- "privilege": "Administrator", "ipmi_lan_privilege": "Administrator",
- "ipmi_serial_privilege": "Administrator", "enable": True,
- "sol_enable": True, "protocol_enable": True,
- "authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
- idrac_connection_user_mock.get_server_generation = (14, "3.60.60.60")
- mocker.patch(MODULE_PATH + "idrac_user.get_payload", return_value={"Users.2#UserName": "test_user"})
- mocker.patch(MODULE_PATH + "idrac_user.convert_payload_xml",
- return_value=("<xml-data>", {"Users.1#UserName": "test_user"}))
- mocker.patch(MODULE_PATH + "idrac_user.iDRACRedfishAPI.invoke_request",
- return_value={"Message": "Successfully created a request."})
- # slot_id = 2
- # slot_uri = "/redfish/v1/Managers/iDRAC.Embedded.1/Accounts/{0}/".format(slot_id)
- user_attr = {"User.2#UserName": "test_user"}
- with pytest.raises(Exception) as exc:
- self.module.create_or_modify_account(f_module, idrac_connection_user_mock, None, None,
- None, None, user_attr)
- assert exc.value.args[0] == "Maximum number of users reached. Delete a user account and retry the operation."
+ empty_slot_id, empty_slot_uri, user_attr)
+ assert exc.value.args[0] == params.get("ret_val")
@pytest.mark.parametrize("exc_type", [SSLValidationError, URLError, ValueError, TypeError,
ConnectionError, HTTPError, ImportError, RuntimeError])
@@ -403,10 +301,10 @@ class TestIDRACUser(FakeAnsibleModule):
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
json_str = to_text(json.dumps({"data": "out"}))
if exc_type not in [HTTPError, SSLValidationError]:
- mocker.patch(MODULE_PATH + "idrac_user.create_or_modify_account",
+ mocker.patch(MODULE_PATH + CM_ACCOUNT,
side_effect=exc_type('test'))
else:
- mocker.patch(MODULE_PATH + "idrac_user.create_or_modify_account",
+ mocker.patch(MODULE_PATH + CM_ACCOUNT,
side_effect=exc_type('https://testhost.com', 400, 'http error message',
{"accept-type": "application/json"}, StringIO(json_str)))
if exc_type != URLError:
@@ -425,7 +323,8 @@ class TestIDRACUser(FakeAnsibleModule):
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
obj = MagicMock()
obj.json_data = {"error": {"message": "Some Error Occured"}}
- mocker.patch(MODULE_PATH + "idrac_user.remove_user_account", return_value=(obj, "error"))
+ mocker.patch(MODULE_PATH + "idrac_user.remove_user_account",
+ return_value=(obj, "error"))
result = self._run_module_with_fail_json(idrac_default_args)
assert result['failed'] is True
assert result['msg'] == "Some Error Occured"
@@ -438,8 +337,10 @@ class TestIDRACUser(FakeAnsibleModule):
"sol_enable": True, "protocol_enable": True,
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
obj = MagicMock()
- obj.json_data = {"Oem": {"Dell": {"Message": "Unable to complete application of configuration profile values."}}}
- mocker.patch(MODULE_PATH + "idrac_user.remove_user_account", return_value=(obj, "error"))
+ obj.json_data = {"Oem": {"Dell": {
+ "Message": "Unable to complete application of configuration profile values."}}}
+ mocker.patch(MODULE_PATH + "idrac_user.remove_user_account",
+ return_value=(obj, "error"))
result = self._run_module_with_fail_json(idrac_default_args)
assert result['failed'] is True
assert result['msg'] == "Unable to complete application of configuration profile values."
@@ -452,8 +353,9 @@ class TestIDRACUser(FakeAnsibleModule):
"sol_enable": True, "protocol_enable": True,
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
obj = MagicMock()
- obj.json_data = {"Oem": {"Dell": {"Message": "This Message Does Not Exists"}}}
- mocker.patch(MODULE_PATH + "idrac_user.create_or_modify_account", return_value=(obj, "created"))
+ obj.json_data = {
+ "Oem": {"Dell": {"Message": "This Message Does Not Exists"}}}
+ mocker.patch(MODULE_PATH + CM_ACCOUNT, return_value=(obj, "created"))
# with pytest.raises(Exception) as exc:
result = self._run_module(idrac_default_args)
assert result['changed'] is True
@@ -477,7 +379,8 @@ class TestIDRACUser(FakeAnsibleModule):
"ipmi_serial_privilege": "Administrator", "enable": True,
"sol_enable": True, "protocol_enable": True,
"authentication_protocol": "SHA", "privacy_protocol": "AES"})
- f_module = self.get_module_mock(params=idrac_default_args, check_mode=False)
+ f_module = self.get_module_mock(
+ params=idrac_default_args, check_mode=False)
with pytest.raises(Exception) as err:
self.module.validate_input(f_module)
assert err.value.args[0] == "custom_privilege value should be from 0 to 511."
@@ -491,12 +394,14 @@ class TestIDRACUser(FakeAnsibleModule):
is_change_required = self.module.compare_payload(json_payload, None)
assert is_change_required is True
- json_payload = {"Users.1#Privilege": "123"}
- idrac_attr = {"Users.1#Privilege": "123"}
- is_change_required = self.module.compare_payload(json_payload, idrac_attr)
+ json_payload = {USER_PRIVILAGE: "123"}
+ idrac_attr = {USER_PRIVILAGE: "123"}
+ is_change_required = self.module.compare_payload(
+ json_payload, idrac_attr)
assert is_change_required is False
- json_payload = {"Users.1#Privilege": "123"}
- idrac_attr = {"Users.1#Privilege": "124"}
- is_change_required = self.module.compare_payload(json_payload, idrac_attr)
+ json_payload = {USER_PRIVILAGE: "123"}
+ idrac_attr = {USER_PRIVILAGE: "124"}
+ is_change_required = self.module.compare_payload(
+ json_payload, idrac_attr)
assert is_change_required is True
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_application_console_preferences.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_application_console_preferences.py
index 627c5e71d..1f51f6cae 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_application_console_preferences.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_application_console_preferences.py
@@ -2,8 +2,8 @@
#
# Dell OpenManage Ansible Modules
-# Version 7.0.0
-# Copyright (C) 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+# Version 9.1.0
+# Copyright (C) 2022-2024 Dell Inc. or its subsidiaries. All Rights Reserved.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
@@ -2227,12 +2227,12 @@ class TestOmeAppConsolePreferences(FakeAnsibleModule):
assert result["unreachable"] is True
elif exc_type not in [HTTPError, SSLValidationError]:
mocker.patch(MODULE_PATH + '_validate_params', side_effect=exc_type("exception message"))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
else:
mocker.patch(MODULE_PATH + '_validate_params',
side_effect=exc_type('https://testhost.com', 400, 'http error message',
{"accept-type": "application/json"}, StringIO(json_str)))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_local_access_configuration.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_local_access_configuration.py
index 9b92bb3c2..50f9e09e6 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_local_access_configuration.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_local_access_configuration.py
@@ -2,8 +2,8 @@
#
# Dell OpenManage Ansible Modules
-# Version 8.1.0
-# Copyright (C) 2021-2023 Dell Inc. or its subsidiaries. All Rights Reserved.
+# Version 9.1.0
+# Copyright (C) 2022-2024 Dell Inc. or its subsidiaries. All Rights Reserved.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
@@ -59,7 +59,7 @@ class TestOMEMDevicePower(FakeAnsibleModule):
"SettingType": "LocalAccessConfiguration", "EnableChassisDirect": False,
"EnableChassisPowerButton": False, "EnableKvmAccess": True, "EnableLcdOverridePin": False,
"LcdAccess": "VIEW_ONLY", "LcdCustomString": "LCD Text", "LcdLanguage": "en",
- "LcdPresence": "Present", "LcdOverridePin": "123456",
+ "LcdPresence": "Present", "LcdPinLength": 6, "LedPresence": "Absent", "LcdOverridePin": "123456",
"QuickSync": {"QuickSyncAccess": True, "TimeoutLimit": 10, "EnableInactivityTimeout": True,
"TimeoutLimitUnit": "MINUTES", "EnableReadAuthentication": True,
"EnableQuickSyncWifi": True, "QuickSyncHardware": "Present"}},
@@ -86,7 +86,7 @@ class TestOMEMDevicePower(FakeAnsibleModule):
"SettingType": "LocalAccessConfiguration", "EnableChassisDirect": False,
"EnableChassisPowerButton": False, "EnableKvmAccess": True, "EnableLcdOverridePin": False,
"LcdAccess": "VIEW_ONLY", "LcdCustomString": "LCD Text", "LcdLanguage": "en",
- "LcdPresence": "Present", "LcdOverridePin": "123456",
+ "LcdPresence": "Present", "LcdPinLength": 6, "LedPresence": "Absent", "LcdOverridePin": "123456",
"QuickSync": {"QuickSyncAccess": True, "TimeoutLimit": 10, "EnableInactivityTimeout": True,
"TimeoutLimitUnit": "MINUTES", "EnableReadAuthentication": True,
"EnableQuickSyncWifi": True, "QuickSyncHardware": "Present"}},
@@ -287,7 +287,7 @@ class TestOMEMDevicePower(FakeAnsibleModule):
def test_check_mode_validation(self, ome_conn_mock_lac, ome_default_args, ome_response_mock, mocker):
loc_data = {"EnableKvmAccess": True, "EnableChassisDirect": True, "EnableChassisPowerButton": True,
"EnableLcdOverridePin": True, "LcdAccess": True, "LcdCustomString": "LCD Text",
- "LcdLanguage": "en", "LcdOverridePin": "123456", "LcdPresence": "Present",
+ "LcdLanguage": "en", "LcdPresence": "Present", "LcdPinLength": 6, "LedPresence": "Absent", "LcdOverridePin": "123456",
"QuickSync": {"QuickSyncAccess": True, "TimeoutLimit": 10, "EnableInactivityTimeout": True,
"TimeoutLimitUnit": "MINUTES", "EnableReadAuthentication": True,
"EnableQuickSyncWifi": True, "QuickSyncHardware": "Present"}, }
@@ -329,18 +329,12 @@ class TestOMEMDevicePower(FakeAnsibleModule):
elif exc_type not in [HTTPError, SSLValidationError]:
mocker.patch(MODULE_PATH + 'check_domain_service',
side_effect=exc_type("exception message"))
- result = self._run_module_with_fail_json(ome_default_args)
- assert result['failed'] is True
- elif exc_type in [HTTPError]:
- mocker.patch(MODULE_PATH + 'check_domain_service',
- side_effect=exc_type(HTTPS_ADDRESS, 400, HTTP_ERROR_MSG,
- {"accept-type": "application/json"}, StringIO(json_str)))
result = self._run_module(ome_default_args)
assert result['failed'] is True
else:
mocker.patch(MODULE_PATH + 'check_domain_service',
side_effect=exc_type(HTTPS_ADDRESS, 400, HTTP_ERROR_MSG,
{"accept-type": "application/json"}, StringIO(json_str)))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_location.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_location.py
index 40fe1b1a2..fd76d6ac9 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_location.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_location.py
@@ -112,36 +112,36 @@ class TestOMEMDeviceLocation(FakeAnsibleModule):
@pytest.mark.parametrize("params", [
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "Successfully updated the location settings.",
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"device_id": 1234, "data_center": "data center",
"room": "room", "aisle": "aisle", "rack": "rack"}
},
{"json_data": {"value": [
{'Id': 1234, 'DeviceServiceTag': 'ABCD123',
- 'PublicAddress': "1.2.3.4", 'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ 'PublicAddress': "xxx.xxx.x.x", 'DeviceId': 1234, "Type": 1000},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "Successfully updated the location settings.",
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"device_service_tag": "ABCD123", "data_center": "data center",
"room": "room", "aisle": "aisle", "rack": "rack"}
},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "Successfully updated the location settings.",
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"data_center": "data center",
"room": "room", "aisle": "aisle", "rack": "rack"}
},
{"json_data": {"value": [
{'Id': 1234, 'PublicAddress': "dummyhost_shouldnotexist",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "Successfully updated the location settings.",
'mparams': {"hostname": "dummyhost_shouldnotexist",
"data_center": "data center",
@@ -159,9 +159,9 @@ class TestOMEMDeviceLocation(FakeAnsibleModule):
@pytest.mark.parametrize("params", [
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "The device location settings operation is supported only on OpenManage Enterprise Modular systems.",
'http_error_json': {
"error": {
@@ -179,14 +179,14 @@ class TestOMEMDeviceLocation(FakeAnsibleModule):
]
}
},
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"data_center": "data center",
"room": "room", "aisle": "aisle", "rack": "rack"}
},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "Unable to complete the operation because the location settings are not supported on the specified device.",
'http_error_json': {
"error": {
@@ -206,16 +206,16 @@ class TestOMEMDeviceLocation(FakeAnsibleModule):
},
'check_domain_service': 'mocked_check_domain_service',
'standalone_chassis': ('Id', 1234),
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"data_center": "data center",
"room": "room", "aisle": "aisle", "rack": "rack"}
},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': "Unable to complete the operation because the entered target device id '123' is invalid.",
- 'mparams': {"hostname": "1.2.3.4", "device_id": 123,
+ 'mparams': {"hostname": "xxx.xxx.x.x.x.x.x.x", "device_id": 123,
"data_center": "data center",
"room": "room", "aisle": "aisle", "rack": "rack"}
},
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_mgmt_network.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_mgmt_network.py
index 004586393..c0bf63e4a 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_mgmt_network.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_mgmt_network.py
@@ -366,11 +366,11 @@ class TestOmeDeviceMgmtNetwork(FakeAnsibleModule):
{"mparams": {"device_id": 123}, "success": True,
"json_data": {"Type": 2000, "Id": 123, "Identifier": "ABCD123"},
"res": {"Type": 2000, "Id": 123, "Identifier": "ABCD123"},
- "diff": {"IPV4": "1.2.3.4"}},
+ "diff": {"IPV4": "xxx.xxx.x.x"}},
{"mparams": {"device_id": 123}, "success": True,
"json_data": {"Type": 4000, "Id": 123, "Identifier": "ABCD123"},
"res": {"Type": 4000, "Id": 123, "Identifier": "ABCD123"},
- "diff": {"IPV4": "1.2.3.4"}},
+ "diff": {"IPV4": "xxx.xxx.x.x"}},
])
def test_get_network_payload(
self, params, ome_connection_mock_for_device_network, ome_response_mock, mocker):
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_power_settings.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_power_settings.py
index 553a57369..9a2255c49 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_power_settings.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_power_settings.py
@@ -35,6 +35,28 @@ POWER_FAIL_MSG = "Unable to complete the operation because the power settings "
"are not supported on the specified device."
DOMAIN_FAIL_MSG = "The device location settings operation is supported only on " \
"OpenManage Enterprise Modular."
+ERROR_JSON = {
+ "error": {
+ "code": "Base.1.0.GeneralError",
+ "message": "A general error has occurred. See ExtendedInfo for more information.",
+ "@Message.ExtendedInfo": [
+ {
+ "MessageId": "CGEN1004",
+ "RelatedProperties": [],
+ "Message": "Unable to process the request because an error occurred.",
+ "MessageArgs": [],
+ "Severity": "Critical",
+ "Resolution": "Retry the operation. If the issue persists, contact your system administrator."
+ }
+ ]
+ }}
+MPARAMS = {"hostname": "xxx.xxx.x.x",
+ "power_configuration": {"enable_power_cap": True, "power_cap": 3424}
+ }
+POWER_JSON_DATA = {"value": [
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
+ 'DeviceId': 1234, "Type": 1000},
+ {'PublicAddress': "xxx.xxx.xx.x", 'DeviceId': 1235, "Type": 1000}]}
@pytest.fixture
@@ -49,11 +71,11 @@ class TestOMEMDevicePower(FakeAnsibleModule):
module = ome_device_power_settings
- @pytest.mark.parametrize("params", [
+ @pytest.mark.parametrize("params_inp", [
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceServiceTag': 'ABCD123', "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}],
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}],
"EnableHotSpare": True,
"EnablePowerCapSettings": True,
"MaxPowerCap": "3424",
@@ -63,15 +85,15 @@ class TestOMEMDevicePower(FakeAnsibleModule):
"RedundancyPolicy": "NO_REDUNDANCY",
"SettingType": "Power"},
'message': SUCCESS_MSG,
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"power_configuration": {"enable_power_cap": True, "power_cap": 3424},
"hot_spare_configuration": {"enable_hot_spare": False, "primary_grid": "GRID_1"},
"device_id": 1234,
}},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceServiceTag': 'ABCD123', "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}],
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}],
"EnableHotSpare": True,
"EnablePowerCapSettings": True,
"MaxPowerCap": "3424",
@@ -81,15 +103,15 @@ class TestOMEMDevicePower(FakeAnsibleModule):
"RedundancyPolicy": "NO_REDUNDANCY",
"SettingType": "Power"},
'message': SUCCESS_MSG,
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"power_configuration": {"enable_power_cap": False, "power_cap": 3424},
"hot_spare_configuration": {"enable_hot_spare": True, "primary_grid": "GRID_1"},
"device_service_tag": 'ABCD123',
}},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}],
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}],
"EnableHotSpare": True,
"EnablePowerCapSettings": True,
"MaxPowerCap": "3424",
@@ -99,14 +121,14 @@ class TestOMEMDevicePower(FakeAnsibleModule):
"RedundancyPolicy": "NO_REDUNDANCY",
"SettingType": "Power"},
'message': SUCCESS_MSG,
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"power_configuration": {"enable_power_cap": False, "power_cap": 3424},
"hot_spare_configuration": {"enable_hot_spare": True, "primary_grid": "GRID_1"}
}},
{"json_data": {"value": [
{'Id': 1234, 'PublicAddress': "dummyhostname_shouldnotexist",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}],
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}],
"EnableHotSpare": True,
"EnablePowerCapSettings": True,
"MaxPowerCap": "3424",
@@ -121,20 +143,17 @@ class TestOMEMDevicePower(FakeAnsibleModule):
"hot_spare_configuration": {"enable_hot_spare": True, "primary_grid": "GRID_1"}
}}
])
- def test_ome_devices_power_settings_success(self, params, ome_conn_mock_power, ome_response_mock,
+ def test_ome_devices_power_settings_success(self, params_inp, ome_conn_mock_power, ome_response_mock,
ome_default_args, module_mock, mocker):
- ome_response_mock.success = params.get("success", True)
- ome_response_mock.json_data = params['json_data']
- ome_default_args.update(params['mparams'])
+ ome_response_mock.success = params_inp.get("success", True)
+ ome_response_mock.json_data = params_inp['json_data']
+ ome_default_args.update(params_inp['mparams'])
result = self._run_module(
- ome_default_args, check_mode=params.get('check_mode', False))
- assert result['msg'] == params['message']
+ ome_default_args, check_mode=params_inp.get('check_mode', False))
+ assert result['msg'] == params_inp['message']
@pytest.mark.parametrize("params", [
- {"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
- 'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {"json_data": POWER_JSON_DATA,
'message': DOMAIN_FAIL_MSG,
'http_error_json': {
"error": {
@@ -151,77 +170,39 @@ class TestOMEMDevicePower(FakeAnsibleModule):
}
]
}},
- 'mparams': {"hostname": "1.2.3.4",
+ 'mparams': {"hostname": "xxx.xxx.x.x",
"device_service_tag": 'ABCD123',
"power_configuration": {"enable_power_cap": True, "power_cap": 3424}
}},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': POWER_FAIL_MSG,
'check_domain_service': 'mocked_check_domain_service',
'get_chassis_device': ('Id', 1234),
- 'http_error_json': {
- "error": {
- "code": "Base.1.0.GeneralError",
- "message": "A general error has occurred. See ExtendedInfo for more information.",
- "@Message.ExtendedInfo": [
- {
- "MessageId": "CGEN1004",
- "RelatedProperties": [],
- "Message": "Unable to process the request because an error occurred.",
- "MessageArgs": [],
- "Severity": "Critical",
- "Resolution": "Retry the operation. If the issue persists, contact your system administrator."
- }
- ]
- }},
- 'mparams': {"hostname": "1.2.3.4",
- "power_configuration": {"enable_power_cap": True, "power_cap": 3424}
- }},
- {"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
- 'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ 'http_error_json': ERROR_JSON,
+ 'mparams': MPARAMS},
+ {"json_data": POWER_JSON_DATA,
'message': POWER_FAIL_MSG,
'check_domain_service': 'mocked_check_domain_service',
'get_chassis_device': ('Id', 1234),
'http_err_code': 404,
- 'http_error_json': {
- "error": {
- "code": "Base.1.0.GeneralError",
- "message": "A general error has occurred. See ExtendedInfo for more information.",
- "@Message.ExtendedInfo": [
- {
- "MessageId": "CGEN1004",
- "RelatedProperties": [],
- "Message": "Unable to process the request because an error occurred.",
- "MessageArgs": [],
- "Severity": "Critical",
- "Resolution": "Retry the operation. If the issue persists, contact your system administrator."
- }
- ]
- }},
- 'mparams': {"hostname": "1.2.3.4",
- "power_configuration": {"enable_power_cap": True, "power_cap": 3424}
- }},
- {"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
- 'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ 'http_error_json': ERROR_JSON,
+ 'mparams': MPARAMS},
+ {"json_data": POWER_JSON_DATA,
'message': DEVICE_FAIL_MSG.format('id', 123),
'check_domain_service': 'mocked_check_domain_service',
'get_chassis_device': ('Id', 1234),
- 'mparams': {"hostname": "1.2.3.4", 'device_id': 123,
+ 'mparams': {"hostname": "xxx.xxx.x.x", 'device_id': 123,
"power_configuration": {"enable_power_cap": True, "power_cap": 3424}
}},
{"json_data": {"value": [
- {'Id': 1234, 'PublicAddress': "1.2.3.4",
+ {'Id': 1234, 'PublicAddress': "xxx.xxx.x.x",
'DeviceId': 1234, "Type": 1000},
- {'PublicAddress': "1.2.3.5", 'DeviceId': 1235, "Type": 1000}]},
+ {'PublicAddress': "X.X.X.X", 'DeviceId': 1235, "Type": 1000}]},
'message': CONFIG_FAIL_MSG,
- 'mparams': {"hostname": "1.2.3.4", "device_id": 123}}
+ 'mparams': {"hostname": "xxx.xxx.x.x", "device_id": 123}}
])
def test_ome_devices_power_settings_failure(self, params, ome_conn_mock_power, ome_response_mock,
ome_default_args, module_mock, mocker):
@@ -303,29 +284,29 @@ class TestOMEMDevicePower(FakeAnsibleModule):
result = self.module.get_ip_from_host("ZZ.ZZ.ZZ.ZZ")
assert result == "ZZ.ZZ.ZZ.ZZ"
- @pytest.mark.parametrize("exc_type",
+ @pytest.mark.parametrize("exc_type_ps",
[IOError, ValueError, SSLError, TypeError, ConnectionError, HTTPError, URLError])
- def test_ome_device_power_main_exception_case(self, exc_type, mocker, ome_default_args,
+ def test_ome_device_power_main_exception_case(self, exc_type_ps, mocker, ome_default_args,
ome_conn_mock_power, ome_response_mock):
ome_default_args.update({"device_id": 25011, "power_configuration": {"enable_power_cap": True,
"power_cap": 3424}})
ome_response_mock.status_code = 400
ome_response_mock.success = False
json_str = to_text(json.dumps({"info": "error_details"}))
- if exc_type == URLError:
+ if exc_type_ps == URLError:
mocker.patch(MODULE_PATH + 'check_domain_service',
- side_effect=exc_type("url open error"))
- result = self._run_module(ome_default_args)
- assert result["unreachable"] is True
- elif exc_type not in [HTTPError, SSLValidationError]:
+ side_effect=exc_type_ps("url open error"))
+ result_ps = self._run_module(ome_default_args)
+ assert result_ps["unreachable"] is True
+ elif exc_type_ps not in [HTTPError, SSLValidationError]:
mocker.patch(MODULE_PATH + 'check_domain_service',
- side_effect=exc_type("exception message"))
- result = self._run_module_with_fail_json(ome_default_args)
- assert result['failed'] is True
+ side_effect=exc_type_ps("exception message"))
+ result_ps = self._run_module_with_fail_json(ome_default_args)
+ assert result_ps['failed'] is True
else:
mocker.patch(MODULE_PATH + 'check_domain_service',
- side_effect=exc_type('https://testhost.com', 400, 'http error message',
- {"accept-type": "application/json"}, StringIO(json_str)))
- result = self._run_module_with_fail_json(ome_default_args)
- assert result['failed'] is True
- assert 'msg' in result
+ side_effect=exc_type_ps('https://testhost.com', 400, 'http error message',
+ {"accept-type": "application/json"}, StringIO(json_str)))
+ result_ps = self._run_module_with_fail_json(ome_default_args)
+ assert result_ps['failed'] is True
+ assert 'msg' in result_ps
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_quick_deploy.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_quick_deploy.py
index 60b8c17cc..78299581d 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_quick_deploy.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_device_quick_deploy.py
@@ -267,13 +267,13 @@ class TestOMEMDevicePower(FakeAnsibleModule):
assert result["unreachable"] is True
elif exc_type not in [HTTPError, SSLValidationError]:
mocker.patch(MODULE_PATH + 'check_domain_service', side_effect=exc_type("exception message"))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
else:
mocker.patch(MODULE_PATH + 'check_domain_service',
side_effect=exc_type(HTTP_ADDRESS, 400, HTTP_ERROR_MSG,
{"accept-type": ACCESS_TYPE}, StringIO(json_str)))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_devices.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_devices.py
index 23148d390..f341911cf 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_devices.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_ome_devices.py
@@ -2,8 +2,8 @@
#
# Dell OpenManage Ansible Modules
-# Version 6.1.0
-# Copyright (C) 2021-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+# Version 9.1.0
+# Copyright (C) 2022-2024 Dell Inc. or its subsidiaries. All Rights Reserved.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
@@ -456,12 +456,12 @@ class TestOmeDevices(FakeAnsibleModule):
assert result["unreachable"] is True
elif exc_type not in [HTTPError, SSLValidationError]:
mocker.patch(MODULE_PATH + 'get_dev_ids', side_effect=exc_type("exception message"))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
else:
mocker.patch(MODULE_PATH + 'get_dev_ids',
side_effect=exc_type('https://testhost.com', 400, 'http error message',
{"accept-type": "application/json"}, StringIO(json_str)))
- result = self._run_module_with_fail_json(ome_default_args)
+ result = self._run_module(ome_default_args)
assert result['failed'] is True
assert 'msg' in result
diff --git a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_redfish_storage_volume.py b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_redfish_storage_volume.py
index 40160edf5..b1413d4bd 100644
--- a/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_redfish_storage_volume.py
+++ b/ansible_collections/dellemc/openmanage/tests/unit/plugins/modules/test_redfish_storage_volume.py
@@ -2,8 +2,8 @@
#
# Dell OpenManage Ansible Modules
-# Version 7.0.0
-# Copyright (C) 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+# Version 9.1.0
+# Copyright (C) 2020-2024 Dell Inc. or its subsidiaries. All Rights Reserved.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
@@ -23,6 +23,8 @@ from ansible.module_utils._text import to_text
MODULE_PATH = 'ansible_collections.dellemc.openmanage.plugins.modules.'
HTTPS_ADDRESS = 'https://testhost.com'
+REDFISH = "/redfish/v1/"
+VOLUME_URI = "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Volumes/"
@pytest.fixture
@@ -40,6 +42,10 @@ class TestStorageVolume(FakeAnsibleModule):
def storage_volume_base_uri(self):
self.module.storage_collection_map.update({"storage_base_uri": "/redfish/v1/Systems/System.Embedded.1/Storage"})
+ @pytest.fixture
+ def greater_version(self):
+ return True
+
arg_list1 = [{"state": "present"}, {"state": "present", "volume_id": "volume_id"},
{"state": "absent", "volume_id": "volume_id"},
{"command": "initialize", "volume_id": "volume_id"},
@@ -61,6 +67,7 @@ class TestStorageVolume(FakeAnsibleModule):
redfish_connection_mock_for_storage_volume, param,
storage_volume_base_uri):
mocker.patch(MODULE_PATH + 'redfish_storage_volume.validate_inputs')
+ mocker.patch(MODULE_PATH + 'redfish_storage_volume.is_fw_ver_greater', return_value=True)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.fetch_storage_resource')
mocker.patch(MODULE_PATH + 'redfish_storage_volume.configure_raid_operation',
return_value={"msg": "Successfully submitted volume task.",
@@ -95,8 +102,8 @@ class TestStorageVolume(FakeAnsibleModule):
def test_redfish_storage_volume_main_exception_handling_case(self, exc_type, mocker, redfish_default_args,
redfish_connection_mock_for_storage_volume,
redfish_response_mock):
- redfish_default_args.update({"state": "present"})
- mocker.patch(MODULE_PATH + 'redfish_storage_volume.validate_inputs')
+ redfish_default_args.update({"state": "present", "controller_id": "controller_id"})
+ mocker.patch(MODULE_PATH + 'redfish_storage_volume.is_fw_ver_greater')
redfish_response_mock.status_code = 400
redfish_response_mock.success = False
json_str = to_text(json.dumps({"data": "out"}))
@@ -150,7 +157,7 @@ class TestStorageVolume(FakeAnsibleModule):
assert message["msg"] == "Successfully submitted {0} volume task.".format(action)
@pytest.mark.parametrize("input", [{"state": "present"}, {"state": "absent"}, {"command": "initialize"}, {"command": None}])
- def test_configure_raid_operation(self, input, redfish_connection_mock_for_storage_volume, mocker):
+ def test_configure_raid_operation(self, input, redfish_connection_mock_for_storage_volume, mocker, greater_version):
f_module = self.get_module_mock(params=input)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.perform_volume_create_modify',
return_value={"msg": "Successfully submitted create volume task.",
@@ -164,7 +171,7 @@ class TestStorageVolume(FakeAnsibleModule):
return_value={"msg": "Successfully submitted initialize volume task.",
"task_uri": "JobService/Jobs",
"task_id": "JID_789"})
- message = self.module.configure_raid_operation(f_module, redfish_connection_mock_for_storage_volume)
+ message = self.module.configure_raid_operation(f_module, redfish_connection_mock_for_storage_volume, greater_version)
val = list(input.values())
if val[0] == "present":
assert message["msg"] == "Successfully submitted create volume task."
@@ -257,7 +264,7 @@ class TestStorageVolume(FakeAnsibleModule):
assert exc.value.args[0] == "No changes found to be applied."
def test_perform_volume_create_modify_success_case_01(self, mocker, storage_volume_base_uri,
- redfish_connection_mock_for_storage_volume):
+ redfish_connection_mock_for_storage_volume, greater_version):
f_module = self.get_module_mock(params={"volume_id": "volume_id", "controller_id": "controller_id"})
message = {"msg": "Successfully submitted create volume task.", "task_uri": "JobService/Jobs",
"task_id": "JID_123"}
@@ -265,13 +272,13 @@ class TestStorageVolume(FakeAnsibleModule):
mocker.patch(MODULE_PATH + 'redfish_storage_volume.volume_payload', return_value={"payload": "value"})
mocker.patch(MODULE_PATH + 'redfish_storage_volume.perform_storage_volume_action', return_value=message)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.check_mode_validation', return_value=None)
- message = self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume)
+ message = self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume, greater_version)
assert message["msg"] == "Successfully submitted create volume task."
assert message["task_id"] == "JID_123"
def test_perform_volume_create_modify_success_case_02(self, mocker, storage_volume_base_uri,
redfish_connection_mock_for_storage_volume,
- redfish_response_mock):
+ redfish_response_mock, greater_version):
f_module = self.get_module_mock(params={"volume_id": "volume_id"})
message = {"msg": "Successfully submitted modify volume task.", "task_uri": "JobService/Jobs",
"task_id": "JID_123"}
@@ -280,13 +287,13 @@ class TestStorageVolume(FakeAnsibleModule):
mocker.patch(MODULE_PATH + 'redfish_storage_volume.volume_payload', return_value={"payload": "value"})
mocker.patch(MODULE_PATH + 'redfish_storage_volume.perform_storage_volume_action', return_value=message)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.check_mode_validation', return_value=None)
- message = self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume)
+ message = self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume, greater_version)
assert message["msg"] == "Successfully submitted modify volume task."
assert message["task_id"] == "JID_123"
def test_perform_volume_create_modify_success_case_03(self, mocker, storage_volume_base_uri,
redfish_connection_mock_for_storage_volume,
- redfish_response_mock):
+ redfish_response_mock, greater_version):
f_module = self.get_module_mock(params={"volume_id": "volume_id"})
message = {"msg": "Successfully submitted modify volume task.", "task_uri": "JobService/Jobs",
"task_id": "JID_123"}
@@ -295,13 +302,13 @@ class TestStorageVolume(FakeAnsibleModule):
mocker.patch(MODULE_PATH + 'redfish_storage_volume.volume_payload', return_value={"payload": "value"})
mocker.patch(MODULE_PATH + 'redfish_storage_volume.perform_storage_volume_action', return_value=message)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.check_mode_validation', return_value=None)
- message = self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume)
+ message = self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume, greater_version)
assert message["msg"] == "Successfully submitted modify volume task."
assert message["task_id"] == "JID_123"
def test_perform_volume_create_modify_failure_case_01(self, mocker, storage_volume_base_uri,
redfish_connection_mock_for_storage_volume,
- redfish_response_mock):
+ redfish_response_mock, greater_version):
f_module = self.get_module_mock(params={"volume_id": "volume_id"})
message = {"msg": "Successfully submitted modify volume task.", "task_uri": "JobService/Jobs",
"task_id": "JID_123"}
@@ -311,7 +318,7 @@ class TestStorageVolume(FakeAnsibleModule):
mocker.patch(MODULE_PATH + 'redfish_storage_volume.perform_storage_volume_action', return_value=message)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.check_mode_validation', return_value=None)
with pytest.raises(Exception) as exc:
- self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume)
+ self.module.perform_volume_create_modify(f_module, redfish_connection_mock_for_storage_volume, greater_version)
assert exc.value.args[0] == "Input options are not provided for the modify volume task."
def test_perform_storage_volume_action_success_case(self, mocker, redfish_response_mock,
@@ -485,7 +492,7 @@ class TestStorageVolume(FakeAnsibleModule):
self.module.check_physical_disk_exists(f_module, drive)
assert exc.value.args[0] == "No Drive(s) are attached to the specified Controller Id: RAID.Mezzanine.1C-1."
- def test_volume_payload_case_01(self, storage_volume_base_uri):
+ def test_volume_payload_case_01(self, storage_volume_base_uri, greater_version):
param = {
"drives": ["Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"],
"capacity_bytes": 299439751168,
@@ -505,7 +512,7 @@ class TestStorageVolume(FakeAnsibleModule):
"SpanLength": 2,
"WriteCachePolicy": "WriteThrough"}}}}
f_module = self.get_module_mock(params=param)
- payload = self.module.volume_payload(f_module)
+ payload = self.module.volume_payload(f_module, greater_version)
assert payload["Drives"][0]["@odata.id"] == "/redfish/v1/Systems/System.Embedded.1/Storage/" \
"Drives/Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"
assert payload["RAIDType"] == "RAID0"
@@ -518,19 +525,19 @@ class TestStorageVolume(FakeAnsibleModule):
assert payload["Dell"]["DellVirtualDisk"]["ReadCachePolicy"] == "NoReadAhead"
assert payload["@Redfish.OperationApplyTime"] == "Immediate"
- def test_volume_payload_case_02(self):
+ def test_volume_payload_case_02(self, greater_version):
param = {"block_size_bytes": 512,
"raid_type": "RAID0",
"name": "VD1",
"optimum_io_size_bytes": 65536}
f_module = self.get_module_mock(params=param)
- payload = self.module.volume_payload(f_module)
+ payload = self.module.volume_payload(f_module, greater_version)
assert payload["RAIDType"] == "RAID0"
assert payload["Name"] == "VD1"
assert payload["BlockSizeBytes"] == 512
assert payload["OptimumIOSizeBytes"] == 65536
- def test_volume_payload_case_03(self, storage_volume_base_uri):
+ def test_volume_payload_case_03(self, storage_volume_base_uri, greater_version):
"""Testing encrypted value in case value is passed false"""
param = {
"drives": ["Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"],
@@ -550,7 +557,7 @@ class TestStorageVolume(FakeAnsibleModule):
"SpanLength": 2,
"WriteCachePolicy": "WriteThrough"}}}}
f_module = self.get_module_mock(params=param)
- payload = self.module.volume_payload(f_module)
+ payload = self.module.volume_payload(f_module, greater_version)
assert payload["Drives"][0]["@odata.id"] == "/redfish/v1/Systems/System.Embedded.1/" \
"Storage/Drives/Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"
assert payload["RAIDType"] == "RAID0"
@@ -562,7 +569,7 @@ class TestStorageVolume(FakeAnsibleModule):
assert payload["EncryptionTypes"] == ["NativeDriveEncryption"]
assert payload["Dell"]["DellVirtualDisk"]["ReadCachePolicy"] == "NoReadAhead"
- def test_volume_payload_case_04(self, storage_volume_base_uri):
+ def test_volume_payload_case_04(self, storage_volume_base_uri, greater_version):
param = {
"drives": ["Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"],
"capacity_bytes": 299439751168,
@@ -581,7 +588,7 @@ class TestStorageVolume(FakeAnsibleModule):
"SpanLength": 2,
"WriteCachePolicy": "WriteThrough"}}}}
f_module = self.get_module_mock(params=param)
- payload = self.module.volume_payload(f_module)
+ payload = self.module.volume_payload(f_module, greater_version)
assert payload["Drives"][0]["@odata.id"] == "/redfish/v1/Systems/System.Embedded.1/Storage/" \
"Drives/Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"
assert payload["RAIDType"] == "RAID0"
@@ -593,7 +600,7 @@ class TestStorageVolume(FakeAnsibleModule):
assert payload["EncryptionTypes"] == ["NativeDriveEncryption"]
assert payload["Dell"]["DellVirtualDisk"]["ReadCachePolicy"] == "NoReadAhead"
- def test_volume_payload_case_05(self, storage_volume_base_uri):
+ def test_volume_payload_case_05(self, storage_volume_base_uri, greater_version):
param = {
"drives": ["Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1",
"Disk.Bay.0:Enclosure.Internal.0-1:RAID.Mezzanine.1C-1",
@@ -615,7 +622,7 @@ class TestStorageVolume(FakeAnsibleModule):
"SpanLength": 2,
"WriteCachePolicy": "WriteThrough"}}}}
f_module = self.get_module_mock(params=param)
- payload = self.module.volume_payload(f_module)
+ payload = self.module.volume_payload(f_module, greater_version)
assert payload["Drives"][0]["@odata.id"] == "/redfish/v1/Systems/System.Embedded.1/Storage/" \
"Drives/Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"
assert payload["RAIDType"] == "RAID6"
@@ -627,7 +634,7 @@ class TestStorageVolume(FakeAnsibleModule):
assert payload["EncryptionTypes"] == ["NativeDriveEncryption"]
assert payload["Dell"]["DellVirtualDisk"]["ReadCachePolicy"] == "NoReadAhead"
- def test_volume_payload_case_06(self, storage_volume_base_uri):
+ def test_volume_payload_case_06(self, storage_volume_base_uri, greater_version):
param = {
"drives": ["Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1",
"Disk.Bay.0:Enclosure.Internal.0-1:RAID.Mezzanine.1C-1",
@@ -653,7 +660,7 @@ class TestStorageVolume(FakeAnsibleModule):
"SpanLength": 2,
"WriteCachePolicy": "WriteThrough"}}}}
f_module = self.get_module_mock(params=param)
- payload = self.module.volume_payload(f_module)
+ payload = self.module.volume_payload(f_module, greater_version)
assert payload["Drives"][0]["@odata.id"] == "/redfish/v1/Systems/System.Embedded.1/Storage/" \
"Drives/Disk.Bay.0:Enclosure.Internal.0-0:RAID.Mezzanine.1C-1"
assert payload["RAIDType"] == "RAID60"
@@ -679,7 +686,7 @@ class TestStorageVolume(FakeAnsibleModule):
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage"
},
}
- redfish_connection_mock_for_storage_volume.root_uri = "/redfish/v1/"
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
self.module.fetch_storage_resource(f_module, redfish_connection_mock_for_storage_volume)
assert self.module.storage_collection_map["storage_base_uri"] == "/redfish/v1/Systems/System.Embedded.1/Storage"
@@ -694,7 +701,7 @@ class TestStorageVolume(FakeAnsibleModule):
}
],
}
- redfish_connection_mock_for_storage_volume.root_uri = "/redfish/v1/"
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
with pytest.raises(Exception) as exc:
self.module.fetch_storage_resource(f_module, redfish_connection_mock_for_storage_volume)
assert exc.value.args[0] == "Target out-of-band controller does not support storage feature using Redfish API."
@@ -707,7 +714,7 @@ class TestStorageVolume(FakeAnsibleModule):
"Members": [
],
}
- redfish_connection_mock_for_storage_volume.root_uri = "/redfish/v1/"
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
with pytest.raises(Exception) as exc:
self.module.fetch_storage_resource(f_module, redfish_connection_mock_for_storage_volume)
assert exc.value.args[0] == "Target out-of-band controller does not support storage feature using Redfish API."
@@ -716,7 +723,7 @@ class TestStorageVolume(FakeAnsibleModule):
redfish_response_mock):
f_module = self.get_module_mock()
msg = "Target out-of-band controller does not support storage feature using Redfish API."
- redfish_connection_mock_for_storage_volume.root_uri = "/redfish/v1/"
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
redfish_connection_mock_for_storage_volume.invoke_request.side_effect = HTTPError(HTTPS_ADDRESS, 404,
json.dumps(msg), {}, None)
with pytest.raises(Exception) as exc:
@@ -726,7 +733,7 @@ class TestStorageVolume(FakeAnsibleModule):
redfish_response_mock):
f_module = self.get_module_mock()
msg = "http error"
- redfish_connection_mock_for_storage_volume.root_uri = "/redfish/v1/"
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
redfish_connection_mock_for_storage_volume.invoke_request.side_effect = HTTPError(HTTPS_ADDRESS, 400,
msg, {}, None)
with pytest.raises(Exception, match=msg) as exc:
@@ -736,13 +743,13 @@ class TestStorageVolume(FakeAnsibleModule):
redfish_response_mock):
f_module = self.get_module_mock()
msg = "connection error"
- redfish_connection_mock_for_storage_volume.root_uri = "/redfish/v1/"
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
redfish_connection_mock_for_storage_volume.invoke_request.side_effect = URLError(msg)
with pytest.raises(Exception, match=msg) as exc:
self.module.fetch_storage_resource(f_module, redfish_connection_mock_for_storage_volume)
def test_check_mode_validation(self, redfish_connection_mock_for_storage_volume,
- redfish_response_mock, storage_volume_base_uri):
+ redfish_response_mock, storage_volume_base_uri, greater_version):
param = {"drives": ["Disk.Bay.0:Enclosure.Internal.0-0:RAID.Integrated.1-1"],
"capacity_bytes": 214748364800, "block_size_bytes": 512, "encryption_types": "NativeDriveEncryption",
"encrypted": False, "raid_type": "RAID0", "optimum_io_size_bytes": 65536}
@@ -751,13 +758,15 @@ class TestStorageVolume(FakeAnsibleModule):
with pytest.raises(Exception) as exc:
self.module.check_mode_validation(
f_module, redfish_connection_mock_for_storage_volume, "create",
- "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Volumes/")
+ VOLUME_URI,
+ greater_version=True)
assert exc.value.args[0] == "Changes found to be applied."
redfish_response_mock.json_data = {"Members@odata.count": 0}
with pytest.raises(Exception) as exc:
self.module.check_mode_validation(
f_module, redfish_connection_mock_for_storage_volume, "create",
- "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Volumes/")
+ VOLUME_URI,
+ greater_version=True)
assert exc.value.args[0] == "Changes found to be applied."
redfish_response_mock.json_data = {
"Members@odata.count": 1, "Id": "Disk.Virtual.0:RAID.Integrated.1-1",
@@ -772,18 +781,20 @@ class TestStorageVolume(FakeAnsibleModule):
with pytest.raises(Exception) as exc:
self.module.check_mode_validation(
f_module, redfish_connection_mock_for_storage_volume, "create",
- "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Volumes/")
+ VOLUME_URI,
+ greater_version=True)
assert exc.value.args[0] == "No changes found to be applied."
def test_check_mode_validation_01(self, redfish_connection_mock_for_storage_volume,
- redfish_response_mock, storage_volume_base_uri):
+ redfish_response_mock, storage_volume_base_uri, greater_version):
param1 = {"volume_id": None, 'name': None}
f_module = self.get_module_mock(params=param1)
f_module.check_mode = False
result = self.module.check_mode_validation(f_module,
redfish_connection_mock_for_storage_volume,
"",
- "/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Volumes/")
+ VOLUME_URI,
+ greater_version=True)
assert not result
def test_check_raid_type_supported_success_case01(self, mocker, redfish_response_mock, storage_volume_base_uri,
@@ -845,29 +856,31 @@ class TestStorageVolume(FakeAnsibleModule):
def test_get_apply_time_success_case_01(self, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"controller_id": "controller_id", "apply_time": "Immediate"}
f_module = self.get_module_mock(params=param)
redfish_response_mock.success = True
redfish_response_mock.json_data = {"@Redfish.OperationApplyTimeSupport": {"SupportedValues": ["Immediate"]}}
self.module.get_apply_time(f_module,
redfish_connection_mock_for_storage_volume,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
def test_get_apply_time_success_case_02(self, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"controller_id": "controller_id"}
f_module = self.get_module_mock(params=param)
redfish_response_mock.success = True
redfish_response_mock.json_data = {"@Redfish.OperationApplyTimeSupport": {"SupportedValues": ["Immediate"]}}
self.module.get_apply_time(f_module,
redfish_connection_mock_for_storage_volume,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
def test_get_apply_time_supported_failure_case(self, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"controller_id": "controller_id", "apply_time": "Immediate"}
f_module = self.get_module_mock(params=param)
redfish_response_mock.success = True
@@ -875,25 +888,27 @@ class TestStorageVolume(FakeAnsibleModule):
with pytest.raises(Exception) as exc:
self.module.get_apply_time(f_module,
redfish_connection_mock_for_storage_volume,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
assert exc.value.args[0] == "Apply time Immediate \
is not supported. The supported values are ['OnReset']. Enter the valid values and retry the operation."
def test_get_apply_time_supported_exception_case(self, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"controller_id": "controller_id", "apply_time": "Immediate"}
f_module = self.get_module_mock(params=param)
redfish_connection_mock_for_storage_volume.invoke_request.side_effect = HTTPError(HTTPS_ADDRESS, 400,
'', {}, None)
with pytest.raises(HTTPError) as ex:
self.module.get_apply_time(f_module, redfish_connection_mock_for_storage_volume,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
def test_check_apply_time_supported_and_reboot_required_success_case01(self, mocker,
redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"reboot_server": True}
f_module = self.get_module_mock(params=param)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.get_apply_time',
@@ -901,13 +916,14 @@ is not supported. The supported values are ['OnReset']. Enter the valid values a
apply_time = self.module.get_apply_time(f_module, redfish_connection_mock_for_storage_volume)
val = self.module.check_apply_time_supported_and_reboot_required(f_module,
redfish_connection_mock_for_storage_volume,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
assert val
def test_check_apply_time_supported_and_reboot_required_success_case02(self, mocker,
redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"reboot_server": False}
f_module = self.get_module_mock(params=param)
mocker.patch(MODULE_PATH + 'redfish_storage_volume.get_apply_time',
@@ -915,12 +931,13 @@ is not supported. The supported values are ['OnReset']. Enter the valid values a
apply_time = self.module.get_apply_time(f_module, redfish_connection_mock_for_storage_volume)
val = self.module.check_apply_time_supported_and_reboot_required(f_module,
redfish_connection_mock_for_storage_volume,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
assert not val
def test_check_job_tracking_required_success_case01(self, mocker, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"job_wait": True}
mocker.patch(MODULE_PATH + 'redfish_storage_volume.get_apply_time',
return_value="OnReset")
@@ -929,12 +946,13 @@ is not supported. The supported values are ['OnReset']. Enter the valid values a
val = self.module.check_job_tracking_required(f_module,
redfish_connection_mock_for_storage_volume,
reboot_required=False,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
assert not val
def test_check_job_tracking_required_success_case02(self, mocker, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"job_wait": True}
mocker.patch(MODULE_PATH + 'redfish_storage_volume.get_apply_time',
return_value="Immediate")
@@ -942,12 +960,13 @@ is not supported. The supported values are ['OnReset']. Enter the valid values a
val = self.module.check_job_tracking_required(f_module,
redfish_connection_mock_for_storage_volume,
reboot_required=True,
- controller_id="controller_id")
+ controller_id="controller_id",
+ greater_version=True)
assert val
def test_check_job_tracking_required_success_case03(self, mocker, redfish_response_mock,
redfish_connection_mock_for_storage_volume,
- storage_volume_base_uri):
+ storage_volume_base_uri, greater_version):
param = {"job_wait": False}
mocker.patch(MODULE_PATH + 'redfish_storage_volume.get_apply_time',
return_value="Immediate")
@@ -955,7 +974,8 @@ is not supported. The supported values are ['OnReset']. Enter the valid values a
val = self.module.check_job_tracking_required(f_module,
redfish_connection_mock_for_storage_volume,
reboot_required=True,
- controller_id=None)
+ controller_id=None,
+ greater_version=True)
assert not val
def test_perform_reboot_timeout_case(self, mocker, redfish_response_mock,
@@ -1129,3 +1149,32 @@ is not supported. The supported values are ['OnReset']. Enter the valid values a
with pytest.raises(Exception) as ex:
self.module.validate_negative_job_time_out(f_module)
assert ex.value.args[0] == "The parameter job_wait_timeout value cannot be negative or zero."
+
+ def test_is_fw_ver_greater(self, redfish_connection_mock_for_storage_volume, redfish_response_mock):
+ # Scenario 1: FW version is not greater
+ redfish_response_mock.json_data = {
+ '@odata.context': '/redfish/v1/$metadata#Manager.Manager',
+ '@odata.id': '/redfish/v1/Managers/iDRAC.Embedded.1',
+ '@odata.type': '#Manager.v1_3_3.Manager',
+ 'FirmwareVersion': '2.81'
+ }
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
+ ver = self.module.is_fw_ver_greater(redfish_connection_mock_for_storage_volume)
+ if ver is True:
+ assert ver is True
+ else:
+ assert ver is False
+
+ # Scenario 1: FW version is not greater
+ redfish_response_mock.json_data = {
+ '@odata.context': '/redfish/v1/$metadata#Manager.Manager',
+ '@odata.id': '/redfish/v1/Managers/iDRAC.Embedded.1',
+ '@odata.type': '#Manager.v1_18_0.Manager',
+ 'FirmwareVersion': '7.10'
+ }
+ redfish_connection_mock_for_storage_volume.root_uri = REDFISH
+ ver = self.module.is_fw_ver_greater(redfish_connection_mock_for_storage_volume)
+ if ver is True:
+ assert ver is True
+ else:
+ assert ver is False