summaryrefslogtreecommitdiffstats
path: root/ansible_collections/dellemc/powerflex/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/dellemc/powerflex/tests
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/dellemc/powerflex/tests')
-rw-r--r--ansible_collections/dellemc/powerflex/tests/requirements.txt7
-rw-r--r--ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.12.txt11
-rw-r--r--ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.13.txt11
-rw-r--r--ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.14.txt11
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/__init__.py0
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/__init__.py0
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_api_exception.py14
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_info_api.py240
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_mdm_cluster_api.py403
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_protection_domain_api.py68
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_consistency_group_api.py70
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_pair_api.py50
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_sdk_response.py15
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_storagepool_api.py467
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_volume_api.py548
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/__init__.py0
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_info.py151
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_mdm_cluster.py636
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_protection_domain.py236
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_consistency_group.py344
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_pair.py237
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_storagepool.py72
-rw-r--r--ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_volume.py81
23 files changed, 3672 insertions, 0 deletions
diff --git a/ansible_collections/dellemc/powerflex/tests/requirements.txt b/ansible_collections/dellemc/powerflex/tests/requirements.txt
new file mode 100644
index 000000000..3541acd15
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/requirements.txt
@@ -0,0 +1,7 @@
+pytest
+pytest-xdist
+pytest-mock
+pytest-cov
+pytest-forked
+coverage==4.5.4
+mock
diff --git a/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.12.txt b/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.12.txt
new file mode 100644
index 000000000..c78903cdf
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.12.txt
@@ -0,0 +1,11 @@
+plugins/modules/device.py validate-modules:missing-gplv3-license
+plugins/modules/sdc.py validate-modules:missing-gplv3-license
+plugins/modules/sds.py validate-modules:missing-gplv3-license
+plugins/modules/snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/storagepool.py validate-modules:missing-gplv3-license
+plugins/modules/volume.py validate-modules:missing-gplv3-license
+plugins/modules/info.py validate-modules:missing-gplv3-license
+plugins/modules/protection_domain.py validate-modules:missing-gplv3-license
+plugins/modules/mdm_cluster.py validate-modules:missing-gplv3-license
+plugins/modules/replication_consistency_group.py validate-modules:missing-gplv3-license
+plugins/modules/replication_pair.py validate-modules:missing-gplv3-license
diff --git a/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.13.txt b/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.13.txt
new file mode 100644
index 000000000..c78903cdf
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.13.txt
@@ -0,0 +1,11 @@
+plugins/modules/device.py validate-modules:missing-gplv3-license
+plugins/modules/sdc.py validate-modules:missing-gplv3-license
+plugins/modules/sds.py validate-modules:missing-gplv3-license
+plugins/modules/snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/storagepool.py validate-modules:missing-gplv3-license
+plugins/modules/volume.py validate-modules:missing-gplv3-license
+plugins/modules/info.py validate-modules:missing-gplv3-license
+plugins/modules/protection_domain.py validate-modules:missing-gplv3-license
+plugins/modules/mdm_cluster.py validate-modules:missing-gplv3-license
+plugins/modules/replication_consistency_group.py validate-modules:missing-gplv3-license
+plugins/modules/replication_pair.py validate-modules:missing-gplv3-license
diff --git a/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.14.txt b/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.14.txt
new file mode 100644
index 000000000..c78903cdf
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/sanity/ignore-2.14.txt
@@ -0,0 +1,11 @@
+plugins/modules/device.py validate-modules:missing-gplv3-license
+plugins/modules/sdc.py validate-modules:missing-gplv3-license
+plugins/modules/sds.py validate-modules:missing-gplv3-license
+plugins/modules/snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/storagepool.py validate-modules:missing-gplv3-license
+plugins/modules/volume.py validate-modules:missing-gplv3-license
+plugins/modules/info.py validate-modules:missing-gplv3-license
+plugins/modules/protection_domain.py validate-modules:missing-gplv3-license
+plugins/modules/mdm_cluster.py validate-modules:missing-gplv3-license
+plugins/modules/replication_consistency_group.py validate-modules:missing-gplv3-license
+plugins/modules/replication_pair.py validate-modules:missing-gplv3-license
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/__init__.py b/ansible_collections/dellemc/powerflex/tests/unit/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/__init__.py
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/__init__.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/__init__.py
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_api_exception.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_api_exception.py
new file mode 100644
index 000000000..5128e54b3
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_api_exception.py
@@ -0,0 +1,14 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Mock ApiException for Dell Technologies (Dell) PowerFlex Test modules"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockApiException(Exception):
+ body = "PyPowerFlex Error message"
+ status = "500"
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_info_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_info_api.py
new file mode 100644
index 000000000..e2ef01fe7
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_info_api.py
@@ -0,0 +1,240 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of info module on Dell Technologies (Dell) PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_storagepool_api import MockStoragePoolApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_volume_api import MockVolumeApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_replication_consistency_group_api \
+ import MockReplicationConsistencyGroupApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_replication_pair_api \
+ import MockReplicationPairApi
+
+
+__metaclass__ = type
+
+
+class MockInfoApi:
+ INFO_COMMON_ARGS = {
+ "hostname": "**.***.**.***",
+ "gather_subset": [],
+ "filters": None
+ }
+
+ DUMMY_IP = 'xx.xx.xx.xx'
+ INFO_ARRAY_DETAILS = [
+ {
+ 'systemVersionName': 'DellEMC PowerFlex Version',
+ 'perfProfile': 'Compact',
+ 'authenticationMethod': 'Native',
+ 'capacityAlertHighThresholdPercent': 80,
+ 'capacityAlertCriticalThresholdPercent': 90,
+ 'upgradeState': 'NoUpgrade',
+ 'remoteReadOnlyLimitState': False,
+ 'mdmManagementPort': 6611,
+ 'mdmExternalPort': 7611,
+ 'sdcMdmNetworkDisconnectionsCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'sdcSdsNetworkDisconnectionsCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 800,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 4000,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 20000,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'sdcMemoryAllocationFailuresCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'sdcSocketAllocationFailuresCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'sdcLongOperationsCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 10000,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 100000,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 1000000,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'cliPasswordAllowed': True,
+ 'managementClientSecureCommunicationEnabled': True,
+ 'tlsVersion': 'TLSv1.2',
+ 'showGuid': True,
+ 'defragmentationEnabled': True,
+ 'mdmSecurityPolicy': 'None',
+ 'mdmCluster': {
+ 'clusterState': 'ClusteredNormal',
+ 'clusterMode': 'ThreeNodes',
+ 'slaves': [
+ {
+ 'managementIPs': [
+ DUMMY_IP
+ ],
+ 'ips': [
+ DUMMY_IP
+ ],
+ 'versionInfo': '',
+ 'virtualInterfaces': [
+ ''
+ ],
+ 'opensslVersion': 'OpenSSL 26 Jan 2017',
+ 'role': 'Manager',
+ 'status': 'Normal',
+ 'name': 'test_node1_MDM',
+ 'id': 'test_id_1',
+ 'port': 0000
+ }
+ ],
+ 'goodNodesNum': 3,
+ 'master': {
+ 'managementIPs': [
+ DUMMY_IP
+ ],
+ 'ips': [
+ DUMMY_IP
+ ],
+ 'versionInfo': 'R3_6.0.0',
+ 'virtualInterfaces': [
+ 'ens192'
+ ],
+ 'opensslVersion': 'OpenSSL26 Jan 2017',
+ 'role': 'Manager',
+ 'status': 'Normal',
+ 'name': 'test_node_0',
+ 'id': 'test_id_2',
+ 'port': 0000
+ },
+ 'tieBreakers': [
+ {
+ 'managementIPs': [
+ DUMMY_IP
+ ],
+ 'ips': [
+ DUMMY_IP
+ ],
+ 'versionInfo': '',
+ 'opensslVersion': 'N/A',
+ 'role': 'TieBreaker',
+ 'status': 'Normal',
+ 'id': 'test_id_3',
+ 'port': 0000
+ }
+ ],
+ 'goodReplicasNum': 2,
+ 'id': ''
+ },
+ 'sdcSdsConnectivityInfo': {
+ 'clientServerConnectivityStatus': 'AllConnected',
+ 'disconnectedClientId': None,
+ 'disconnectedClientName': None,
+ 'disconnectedServerId': None,
+ 'disconnectedServerName': None,
+ 'disconnectedServerIp': None
+ },
+ 'addressSpaceUsage': 'Normal',
+ 'lastUpgradeTime': 0,
+ 'sdcSdrConnectivityInfo': {
+ 'clientServerConnectivityStatus': 'AllConnected',
+ 'disconnectedClientId': None,
+ 'disconnectedClientName': None,
+ 'disconnectedServerId': None,
+ 'disconnectedServerName': None,
+ 'disconnectedServerIp': None
+ },
+ 'sdrSdsConnectivityInfo': {
+ 'clientServerConnectivityStatus': 'AllConnected',
+ 'disconnectedClientId': None,
+ 'disconnectedClientName': None,
+ 'disconnectedServerId': None,
+ 'disconnectedServerName': None,
+ 'disconnectedServerIp': None
+ },
+ 'isInitialLicense': False,
+ 'capacityTimeLeftInDays': '253',
+ 'swid': 'abcdXXX',
+ 'installId': 'id_111',
+ 'restrictedSdcModeEnabled': False,
+ 'restrictedSdcMode': 'None',
+ 'enterpriseFeaturesEnabled': True,
+ 'daysInstalled': 112,
+ 'maxCapacityInGb': '5120',
+ 'id': 'id_222'
+ }
+ ]
+
+ INFO_VOLUME_GET_LIST = MockVolumeApi.VOLUME_GET_LIST
+
+ INFO_VOLUME_STATISTICS = {
+ 'test_vol_id_1': MockVolumeApi.VOLUME_STATISTICS
+ }
+
+ INFO_STORAGE_POOL_GET_LIST = MockStoragePoolApi.STORAGE_POOL_GET_LIST
+
+ INFO_STORAGE_POOL_STATISTICS = {
+ 'test_pool_id_1': MockStoragePoolApi.STORAGE_POOL_STATISTICS
+ }
+
+ RCG_LIST = MockReplicationConsistencyGroupApi.get_rcg_details()
+ PAIR_LIST = MockReplicationPairApi.get_pair_details()
+
+ @staticmethod
+ def get_exception_response(response_type):
+ if response_type == 'volume_get_details':
+ return "Get volumes list from powerflex array failed with error "
+ elif response_type == 'sp_get_details':
+ return "Get storage pool list from powerflex array failed with error "
+ elif response_type == 'rcg_get_details':
+ return "Get replication consistency group list from powerflex array failed with error "
+ elif response_type == 'replication_pair_get_details':
+ return "Get replication pair list from powerflex array failed with error "
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_mdm_cluster_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_mdm_cluster_api.py
new file mode 100644
index 000000000..e2966fad8
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_mdm_cluster_api.py
@@ -0,0 +1,403 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of MDM cluster module on PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockMdmClusterApi:
+ MODULE_PATH = 'ansible_collections.dellemc.powerflex.plugins.modules.mdm_cluster.PowerFlexMdmCluster'
+ MODULE_UTILS_PATH = 'ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell.utils'
+
+ MDM_CLUSTER_COMMON_ARGS = {
+ "hostname": "**.***.**.***",
+ "mdm_id": None,
+ "mdm_name": None,
+ "mdm_new_name": None,
+ "performance_profile": None,
+ "standby_mdm": None,
+ "is_primary": None,
+ "cluster_mode": None,
+ "mdm": None,
+ "mdm_state": None,
+ "virtual_ip_interfaces": None,
+ "clear_interfaces": None,
+ 'state': None
+ }
+
+ MDM_NAME = "mdm_node1"
+ MDM_NAME_STB_MGR = "mdm_node_mgr"
+ MDM_ID = "5908d328581d1401"
+ STB_TB_MDM_ID = "5908d328581d1403"
+ STB_MGR_MDM_ID = "36279b98215e5a04"
+ IP_1 = "10.x.y.z"
+ IP_2 = "10.x.x.z"
+ IP_3 = "10.x.z.z"
+ IP_4 = "10.x.y.y"
+ SSL_VERSION = "OpenSSL 1.0.2k-fips 26 Jan 2017"
+ SYS_VERSION = "DellEMC PowerFlex Version: R3_6.0.354"
+
+ THREE_MDM_CLUSTER_DETAILS = {
+ "clusterState": "ClusteredNormal",
+ "clusterMode": "ThreeNodes",
+ "goodNodesNum": 3,
+ "master": {
+ "virtualInterfaces": [
+ "ens1"
+ ],
+ "managementIPs": [
+ IP_1
+ ],
+ "ips": [
+ IP_1
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": SSL_VERSION,
+ "role": "Manager",
+ "status": "Normal",
+ "name": "sample_mdm",
+ "id": "5908d328581d1400",
+ "port": 9011
+ },
+ "perfProfile": "HighPerformance",
+ "slaves": [
+ {
+ "virtualInterfaces": [
+ "ens1"
+ ],
+ "managementIPs": [
+ IP_2
+ ],
+ "ips": [
+ IP_2
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": SSL_VERSION,
+ "role": "Manager",
+ "status": "Normal",
+ "name": "sample_mdm1",
+ "id": MDM_ID,
+ "port": 9011
+ }
+ ],
+ "tieBreakers": [
+ {
+ "managementIPs": [],
+ "ips": [
+ IP_4
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "TieBreaker",
+ "status": "Normal",
+ "id": "5908d328581d1402",
+ "port": 9011
+ }
+ ],
+ "standbyMDMs": [
+ {
+ "managementIPs": [
+ IP_3
+ ],
+ "ips": [
+ IP_3
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "TieBreaker",
+ "status": "Normal",
+ "name": MDM_NAME,
+ "id": STB_TB_MDM_ID,
+ "port": 9011
+ },
+ {
+ "virtualInterfaces": [
+ "ens12"
+ ],
+ "managementIPs": [
+ IP_3
+ ],
+ "ips": [
+ IP_3
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "Manager",
+ "status": "Normal",
+ "name": MDM_NAME_STB_MGR,
+ "id": STB_MGR_MDM_ID,
+ "port": 9011
+ }
+ ],
+ "goodReplicasNum": 2,
+ "id": "cdd883cf00000002"
+ }
+
+ THREE_MDM_CLUSTER_DETAILS_2 = {
+ "clusterState": "ClusteredNormal",
+ "clusterMode": "ThreeNodes",
+ "goodNodesNum": 3,
+ "master": {
+ "virtualInterfaces": [
+ "ens1"
+ ],
+ "managementIPs": [
+ IP_1
+ ],
+ "ips": [
+ IP_1
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": SSL_VERSION,
+ "role": "Manager",
+ "status": "Normal",
+ "name": "sample_mdm",
+ "id": "5908d328581d1400",
+ "port": 9011
+ },
+ "perfProfile": "HighPerformance",
+ "slaves": [
+ {
+ "virtualInterfaces": [
+ "ens1"
+ ],
+ "managementIPs": [
+ IP_2
+ ],
+ "ips": [
+ IP_2
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": SSL_VERSION,
+ "role": "Manager",
+ "status": "Normal",
+ "name": "sample_mdm1",
+ "id": MDM_ID,
+ "port": 9011
+ }
+ ],
+ "tieBreakers": [
+ {
+ "managementIPs": [],
+ "ips": [
+ IP_4
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "TieBreaker",
+ "status": "Normal",
+ "id": "5908d328581d1402",
+ "port": 9011
+ }
+ ],
+ "goodReplicasNum": 2,
+ "id": "cdd883cf00000002"
+ }
+
+ FIVE_MDM_CLUSTER_DETAILS = {
+ "clusterState": "ClusteredNormal",
+ "clusterMode": "FiveNodes",
+ "goodNodesNum": 5,
+ "master": {
+ "virtualInterfaces": [
+ "ens1"
+ ],
+ "managementIPs": [
+ IP_1
+ ],
+ "ips": [
+ IP_1
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": SSL_VERSION,
+ "role": "Manager",
+ "status": "Normal",
+ "name": "sample_mdm",
+ "id": "5908d328581d1400",
+ "port": 9011
+ },
+ "perfProfile": "HighPerformance",
+ "slaves": [
+ {
+ "virtualInterfaces": [],
+ "managementIPs": [
+ IP_2
+ ],
+ "ips": [
+ IP_2
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": SSL_VERSION,
+ "role": "Manager",
+ "status": "Normal",
+ "name": "sample_mdm11",
+ "id": MDM_ID,
+ "port": 9011
+ },
+ {
+ "virtualInterfaces": [
+ "ens12"
+ ],
+ "managementIPs": [
+ IP_3
+ ],
+ "ips": [
+ IP_3
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "Manager",
+ "status": "Normal",
+ "name": MDM_NAME_STB_MGR,
+ "id": STB_MGR_MDM_ID,
+ "port": 9011
+ }
+ ],
+ "tieBreakers": [
+ {
+ "managementIPs": [
+ IP_3
+ ],
+ "ips": [
+ IP_3
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "TieBreaker",
+ "status": "Normal",
+ "name": MDM_NAME,
+ "id": STB_TB_MDM_ID,
+ "port": 9011
+ },
+ {
+ "managementIPs": [],
+ "ips": [
+ IP_4
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "TieBreaker",
+ "status": "Normal",
+ "id": "5908d328581d1402",
+ "port": 9011
+ }
+ ],
+ "standbyMDMs": [
+ {
+ "virtualInterfaces": [
+ "ens13"
+ ],
+ "managementIPs": [
+ IP_1
+ ],
+ "ips": [
+ IP_1
+ ],
+ "versionInfo": "R3_6.0.0",
+ "opensslVersion": "N/A",
+ "role": "Manager",
+ "status": "Normal",
+ "name": "mgr_node_2",
+ "id": "5120af354fb17305",
+ "port": 9011
+ }
+ ],
+ "goodReplicasNum": 2,
+ "id": "cdd883cf00000002"
+ }
+ PARTIAL_SYSTEM_DETAILS = [
+ {
+ "systemVersionName": SYS_VERSION,
+ "perfProfile": "Compact",
+ "name": "System:3c567fd2298f020f",
+ "id": "3c567fd2298f020f"
+ },
+ {
+ "systemVersionName": SYS_VERSION,
+ "perfProfile": "Compact",
+ "name": "System:3c567fd2298f0201",
+ "id": "3c567fd2298f0201"
+ }
+ ]
+ PARTIAL_SYSTEM_DETAILS_1 = [
+ {
+ "systemVersionName": SYS_VERSION,
+ "perfProfile": "Compact",
+ "name": "System:3c567fd2298f020f",
+ "id": "3c567fd2298f020f"
+ }
+ ]
+
+ @staticmethod
+ def get_failed_response():
+ return "Failed to get the MDM cluster with error"
+
+ @staticmethod
+ def rename_failed_response():
+ return "Failed to rename the MDM mdm_node1 with error"
+
+ @staticmethod
+ def perf_profile_failed_response():
+ return "Failed to update performance profile to Compact with error"
+
+ @staticmethod
+ def virtual_ip_interface_failed_response():
+ return "Failed to modify the virtual IP interfaces of MDM 5908d328581d1401 with error"
+
+ @staticmethod
+ def remove_mdm_failed_response():
+ return "Failed to remove the standby MDM 5908d328581d1403 from the MDM cluster with error"
+
+ @staticmethod
+ def add_mdm_failed_response():
+ return "Failed to Add a standby MDM with error"
+
+ @staticmethod
+ def owner_failed_response():
+ return "Failed to update the Owner of MDM cluster to MDM sample_mdm1 with error"
+
+ @staticmethod
+ def switch_mode_failed_response():
+ return "Failed to change the MDM cluster mode with error"
+
+ @staticmethod
+ def system_failed_response():
+ return "Failed to get system id with error"
+
+ @staticmethod
+ def multiple_system_failed_response():
+ return "Multiple systems exist on the given host."
+
+ @staticmethod
+ def remove_mdm_no_id_name_failed_response():
+ return "Either mdm_name or mdm_id is required while removing the standby MDM."
+
+ @staticmethod
+ def without_standby_failed_response():
+ return "No Standby MDMs found. To expand cluster size, first add standby MDMs."
+
+ @staticmethod
+ def no_cluster_failed_response():
+ return "MDM cluster not found"
+
+ @staticmethod
+ def id_none_interface_failed_response():
+ return "Please provide mdm_name/mdm_id to modify virtual IP interfaces the MDM"
+
+ @staticmethod
+ def id_none_rename_failed_response():
+ return "Please provide mdm_name/mdm_id to rename the MDM"
+
+ @staticmethod
+ def id_none_change_owner_failed_response():
+ return "Either mdm_name or mdm_id is required while changing ownership of MDM cluster"
+
+ @staticmethod
+ def new_name_add_mdm_failed_response():
+ return "Parameters mdm_id/mdm_new_name are not allowed while adding a standby MDM"
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_protection_domain_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_protection_domain_api.py
new file mode 100644
index 000000000..60452ecda
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_protection_domain_api.py
@@ -0,0 +1,68 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of protection domain module on Dell Technologies (Dell) PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockProtectionDomainApi:
+ MODULE_PATH = 'ansible_collections.dellemc.powerflex.plugins.modules.protection_domain.PowerFlexProtectionDomain'
+ MODULE_UTILS_PATH = 'ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell.utils'
+
+ PROTECTION_DOMAIN = {
+ "protectiondomain": [
+ {
+ "id": "7bd6457000000000",
+ "name": "test_domain",
+ "protectionDomainState": "Active",
+ "overallIoNetworkThrottlingInKbps": 20480,
+ "rebalanceNetworkThrottlingInKbps": 10240,
+ "rebuildNetworkThrottlingInKbps": 10240,
+ "vtreeMigrationNetworkThrottlingInKbps": 10240,
+ "rfcacheEnabled": "false",
+ "rfcacheMaxIoSizeKb": 128,
+ "rfcacheOpertionalMode": "None",
+ "rfcachePageSizeKb": 64,
+ "storagePools": [
+ {
+ "id": "8d1cba1700000000",
+ "name": "pool1"
+ }
+ ]
+ }
+ ]
+ }
+ STORAGE_POOL = {
+ "storagepool": [
+ {
+ "protectionDomainId": "7bd6457000000000",
+ "rebuildEnabled": True,
+ "mediaType": "HDD",
+ "name": "pool1",
+ "id": "8d1cba1700000000"
+ }
+ ]
+ }
+
+ @staticmethod
+ def modify_pd_with_failed_msg(protection_domain_name):
+ return "Failed to update the rf cache limits of protection domain " + protection_domain_name + " with error "
+
+ @staticmethod
+ def delete_pd_failed_msg(protection_domain_id):
+ return "Delete protection domain '" + protection_domain_id + "' operation failed with error ''"
+
+ @staticmethod
+ def rename_pd_failed_msg(protection_domain_name):
+ return "Failed to update the protection domain " + protection_domain_name + " with error "
+
+ @staticmethod
+ def version_pd_failed_msg():
+ return "Getting PyPowerFlex SDK version, failed with Error The 'PyPowerFlex' distribution was " \
+ "not found and is required by the application"
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_consistency_group_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_consistency_group_api.py
new file mode 100644
index 000000000..6671fd875
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_consistency_group_api.py
@@ -0,0 +1,70 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of volume module on Dell Technologies (Dell) PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockReplicationConsistencyGroupApi:
+ RCG_COMMON_ARGS = {
+ "hostname": "**.***.**.***",
+ "rcg_name": None,
+ "rcg_id": None,
+ "create_snapshot": None, "new_rcg_name": None,
+ "rpo": None, "protection_domain_name": None, "protection_domain_id": None,
+ "activity_mode": None, "pause": None, "pause_mode": None, "freeze": None,
+ "remote_peer": {"hostname": None, "username": None, "password": None,
+ "verifycert": None, "port": None, "protection_domain_name": None,
+ "protection_domain_id": None},
+ "target_volume_access_mode": None, "is_consistent": None,
+ "state": None
+ }
+ RCG_ID = "aadc17d500000000"
+ FAIL_MSG = " failed with error"
+
+ @staticmethod
+ def get_rcg_details(pause_mode="None", freeze_state="Unfrozen", activity_mode="Active", consistency="Consistent"):
+ return [{"protectionDomainId": "b969400500000000",
+ "peerMdmId": "6c3d94f600000000",
+ "remoteId": "2130961a00000000",
+ "remoteMdmId": "0e7a082862fedf0f",
+ "currConsistMode": consistency,
+ "freezeState": freeze_state,
+ "lifetimeState": "Normal",
+ "pauseMode": pause_mode,
+ "snapCreationInProgress": False,
+ "lastSnapGroupId": "e58280b300000001",
+ "lastSnapCreationRc": "SUCCESS",
+ "targetVolumeAccessMode": "NoAccess",
+ "remoteProtectionDomainId": "4eeb304600000000",
+ "remoteProtectionDomainName": "domain1",
+ "failoverType": "None",
+ "failoverState": "None",
+ "activeLocal": True,
+ "activeRemote": True,
+ "abstractState": "Ok",
+ "localActivityState": activity_mode,
+ "remoteActivityState": "Active",
+ "inactiveReason": 11,
+ "rpoInSeconds": 30,
+ "replicationDirection": "LocalToRemote",
+ "disasterRecoveryState": "None",
+ "remoteDisasterRecoveryState": "None",
+ "error": 65,
+ "name": "test_rcg",
+ "type": "User",
+ "id": "aadc17d500000000"}]
+
+ @staticmethod
+ def get_exception_response(response_type):
+ return "Failed to get the replication consistency group "
+
+ @staticmethod
+ def create_snapshot_exception_response(response_type, rcg_id):
+ return "Create RCG snapshot for RCG with id " + rcg_id + " operation failed"
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_pair_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_pair_api.py
new file mode 100644
index 000000000..f621db47e
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_replication_pair_api.py
@@ -0,0 +1,50 @@
+# Copyright: (c) 2023, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of replication pair module on Dell Technologies (Dell) PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockReplicationPairApi:
+ REPLICATION_PAIR_COMMON_ARGS = {
+ "hostname": "**.***.**.***",
+ "rcg_name": None, "rcg_id": None,
+ "pair_id": None, "pair_name": None,
+ "pairs": [{"source_volume_name": None, "source_volume_id": None, "target_volume_name": None,
+ "target_volume_id": None}], "pause": None,
+ "remote_peer": {"hostname": None, "username": None, "password": None,
+ "verifycert": None, "port": None}, "state": None
+ }
+ PAIR_ID = "23aa0bc900000001"
+ FAIL_MSG = " failed with error"
+
+ @staticmethod
+ def get_pair_details(copy_state="Done"):
+ return [{"copyType": "OnlineCopy",
+ "id": "23aa0bc900000001",
+ "initialCopyPriority": -1,
+ "initialCopyState": copy_state,
+ "lifetimeState": "Normal",
+ "localActivityState": "RplEnabled",
+ "localVolumeId": "e2bc1fab00000008",
+ "name": None,
+ "peerSystemName": None,
+ "remoteActivityState": "RplEnabled",
+ "remoteCapacityInMB": 8192,
+ "remoteId": "a058446700000001",
+ "remoteVolumeId": "1cda7af20000000d",
+ "remoteVolumeName": "vol",
+ "replicationConsistencyGroupId": "e2ce036b00000002",
+ "userRequestedPauseTransmitInitCopy": False,
+ "links": []}]
+
+ @staticmethod
+ def get_volume_details():
+ return [{"id": "0001",
+ "name": "volume1"}]
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_sdk_response.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_sdk_response.py
new file mode 100644
index 000000000..9e47f4ba5
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_sdk_response.py
@@ -0,0 +1,15 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Mock SDKResponse for Unit tests for Dell Technologies (Dell) PowerFlex modules"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockSDKResponse:
+ def __init__(self, data=None, status_code=200):
+ self.data = data
+ self.status_code = status_code
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_storagepool_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_storagepool_api.py
new file mode 100644
index 000000000..0246b9dd4
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_storagepool_api.py
@@ -0,0 +1,467 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of storage pool module on Dell Technologies (Dell) PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockStoragePoolApi:
+ STORAGE_POOL_COMMON_ARGS = {
+ "hostname": "**.***.**.***",
+ "storage_pool_name": None,
+ "storage_pool_id": None,
+ "storage_pool_new_name": None,
+ "protection_domain_name": None,
+ "protection_domain_id": None,
+ "use_rmcache": None,
+ "use_rfcache": None,
+ "media_type": None,
+ 'state': None
+ }
+
+ STORAGE_POOL_GET_LIST = [
+ {
+ 'protectionDomainId': '4eeb304600000000',
+ 'rebuildEnabled': True,
+ 'dataLayout': 'MediumGranularity',
+ 'persistentChecksumState': 'Protected',
+ 'addressSpaceUsage': 'Normal',
+ 'externalAccelerationType': 'None',
+ 'rebalanceEnabled': True,
+ 'sparePercentage': 10,
+ 'rmcacheWriteHandlingMode': 'Cached',
+ 'checksumEnabled': False,
+ 'useRfcache': False,
+ 'compressionMethod': 'Invalid',
+ 'fragmentationEnabled': True,
+ 'numOfParallelRebuildRebalanceJobsPerDevice': 2,
+ 'capacityAlertHighThreshold': 80,
+ 'capacityAlertCriticalThreshold': 90,
+ 'capacityUsageState': 'Normal',
+ 'capacityUsageType': 'NetCapacity',
+ 'addressSpaceUsageType': 'DeviceCapacityLimit',
+ 'bgScannerCompareErrorAction': 'ReportAndFix',
+ 'bgScannerReadErrorAction': 'ReportAndFix',
+ 'fglExtraCapacity': None,
+ 'fglOverProvisioningFactor': None,
+ 'fglWriteAtomicitySize': None,
+ 'fglMaxCompressionRatio': None,
+ 'fglPerfProfile': None,
+ 'replicationCapacityMaxRatio': 0,
+ 'persistentChecksumEnabled': True,
+ 'persistentChecksumBuilderLimitKb': 3072,
+ 'persistentChecksumValidateOnRead': False,
+ 'useRmcache': False,
+ 'fglAccpId': None,
+ 'rebuildIoPriorityPolicy': 'limitNumOfConcurrentIos',
+ 'rebalanceIoPriorityPolicy': 'favorAppIos',
+ 'vtreeMigrationIoPriorityPolicy': 'favorAppIos',
+ 'protectedMaintenanceModeIoPriorityPolicy': 'limitNumOfConcurrentIos',
+ 'rebuildIoPriorityNumOfConcurrentIosPerDevice': 1,
+ 'rebalanceIoPriorityNumOfConcurrentIosPerDevice': 1,
+ 'vtreeMigrationIoPriorityNumOfConcurrentIosPerDevice': 1,
+ 'protectedMaintenanceModeIoPriorityNumOfConcurrentIosPerDevice': 1,
+ 'rebuildIoPriorityBwLimitPerDeviceInKbps': 10240,
+ 'rebalanceIoPriorityBwLimitPerDeviceInKbps': 10240,
+ 'vtreeMigrationIoPriorityBwLimitPerDeviceInKbps': 10240,
+ 'protectedMaintenanceModeIoPriorityBwLimitPerDeviceInKbps': 10240,
+ 'rebuildIoPriorityAppIopsPerDeviceThreshold': None,
+ 'rebalanceIoPriorityAppIopsPerDeviceThreshold': None,
+ 'vtreeMigrationIoPriorityAppIopsPerDeviceThreshold': None,
+ 'protectedMaintenanceModeIoPriorityAppIopsPerDeviceThreshold': None,
+ 'rebuildIoPriorityAppBwPerDeviceThresholdInKbps': None,
+ 'rebalanceIoPriorityAppBwPerDeviceThresholdInKbps': None,
+ 'vtreeMigrationIoPriorityAppBwPerDeviceThresholdInKbps': None,
+ 'protectedMaintenanceModeIoPriorityAppBwPerDeviceThresholdInKbps': None,
+ 'rebuildIoPriorityQuietPeriodInMsec': None,
+ 'rebalanceIoPriorityQuietPeriodInMsec': None,
+ 'vtreeMigrationIoPriorityQuietPeriodInMsec': None,
+ 'protectedMaintenanceModeIoPriorityQuietPeriodInMsec': None,
+ 'zeroPaddingEnabled': True,
+ 'backgroundScannerMode': 'DataComparison',
+ 'backgroundScannerBWLimitKBps': 3072,
+ 'fglMetadataSizeXx100': None,
+ 'fglNvdimmWriteCacheSizeInMb': None,
+ 'fglNvdimmMetadataAmortizationX100': None,
+ 'mediaType': 'HDD',
+ 'name': 'test_pool',
+ 'id': 'test_pool_id_1'
+ }
+ ]
+
+ STORAGE_POOL_STATISTICS = {
+ 'backgroundScanFixedReadErrorCount': 0,
+ 'pendingMovingOutBckRebuildJobs': 0,
+ 'degradedHealthyCapacityInKb': 0,
+ 'activeMovingOutFwdRebuildJobs': 0,
+ 'bckRebuildWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netFglUncompressedDataSizeInKb': 0,
+ 'primaryReadFromDevBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'BackgroundScannedInMB': 3209584,
+ 'volumeIds': [
+ 'test_vol_id_1'
+ ],
+ 'maxUserDataCapacityInKb': 761204736,
+ 'persistentChecksumBuilderProgress': 100.0,
+ 'rfcacheReadsSkippedAlignedSizeTooLarge': 0,
+ 'pendingMovingInRebalanceJobs': 0,
+ 'rfcacheWritesSkippedHeavyLoad': 0,
+ 'unusedCapacityInKb': 761204736,
+ 'userDataSdcReadLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'totalReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'numOfDeviceAtFaultRebuilds': 0,
+ 'totalWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'persistentChecksumCapacityInKb': 414720,
+ 'rmPendingAllocatedInKb': 0,
+ 'numOfVolumes': 1,
+ 'rfcacheIosOutstanding': 0,
+ 'capacityAvailableForVolumeAllocationInKb': 377487360,
+ 'numOfMappedToAllVolumes': 0,
+ 'netThinUserDataCapacityInKb': 0,
+ 'backgroundScanFixedCompareErrorCount': 0,
+ 'volMigrationWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'thinAndSnapshotRatio': 'Infinity',
+ 'fglUserDataCapacityInKb': 0,
+ 'pendingMovingInEnterProtectedMaintenanceModeJobs': 0,
+ 'activeMovingInNormRebuildJobs': 0,
+ 'aggregateCompressionLevel': 'Uncompressed',
+ 'targetOtherLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netUserDataCapacityInKb': 0,
+ 'pendingMovingOutExitProtectedMaintenanceModeJobs': 0,
+ 'overallUsageRatio': 'Infinity',
+ 'volMigrationReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netCapacityInUseNoOverheadInKb': 0,
+ 'pendingMovingInBckRebuildJobs': 0,
+ 'rfcacheReadsSkippedInternalError': 0,
+ 'activeBckRebuildCapacityInKb': 0,
+ 'rebalanceCapacityInKb': 0,
+ 'pendingMovingInExitProtectedMaintenanceModeJobs': 0,
+ 'rfcacheReadsSkippedLowResources': 0,
+ 'rplJournalCapAllowed': 0,
+ 'thinCapacityInUseInKb': 0,
+ 'userDataSdcTrimLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'activeMovingInEnterProtectedMaintenanceModeJobs': 0,
+ 'rfcacheWritesSkippedInternalError': 0,
+ 'netUserDataCapacityNoTrimInKb': 0,
+ 'rfcacheWritesSkippedCacheMiss': 0,
+ 'degradedFailedCapacityInKb': 0,
+ 'activeNormRebuildCapacityInKb': 0,
+ 'fglSparesInKb': 0,
+ 'snapCapacityInUseInKb': 0,
+ 'numOfMigratingVolumes': 0,
+ 'compressionRatio': 0.0,
+ 'rfcacheWriteMiss': 0,
+ 'primaryReadFromRmcacheBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'migratingVtreeIds': [
+ ],
+ 'numOfVtrees': 1,
+ 'userDataCapacityNoTrimInKb': 0,
+ 'rfacheReadHit': 0,
+ 'compressedDataCompressionRatio': 0.0,
+ 'rplUsedJournalCap': 0,
+ 'pendingMovingCapacityInKb': 0,
+ 'numOfSnapshots': 0,
+ 'pendingFwdRebuildCapacityInKb': 0,
+ 'tempCapacityInKb': 0,
+ 'totalFglMigrationSizeInKb': 0,
+ 'normRebuildCapacityInKb': 0,
+ 'logWrittenBlocksInKb': 0,
+ 'primaryWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'numOfThickBaseVolumes': 0,
+ 'enterProtectedMaintenanceModeReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'activeRebalanceCapacityInKb': 0,
+ 'numOfReplicationJournalVolumes': 0,
+ 'rfcacheReadsSkippedLockIos': 0,
+ 'unreachableUnusedCapacityInKb': 0,
+ 'netProvisionedAddressesInKb': 0,
+ 'trimmedUserDataCapacityInKb': 0,
+ 'provisionedAddressesInKb': 0,
+ 'numOfVolumesInDeletion': 0,
+ 'pendingMovingOutFwdRebuildJobs': 0,
+ 'maxCapacityInKb': 845783040,
+ 'rmPendingThickInKb': 0,
+ 'protectedCapacityInKb': 0,
+ 'secondaryWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'normRebuildReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'thinCapacityAllocatedInKb': 16777216,
+ 'netFglUserDataCapacityInKb': 0,
+ 'metadataOverheadInKb': 0,
+ 'thinCapacityAllocatedInKm': 16777216,
+ 'rebalanceWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'primaryVacInKb': 8388608,
+ 'deviceIds': [
+ 'dv_id_1',
+ 'dv_id_2',
+ 'dv_id_3'
+ ],
+ 'netSnapshotCapacityInKb': 0,
+ 'secondaryVacInKb': 8388608,
+ 'numOfDevices': 3,
+ 'rplTotalJournalCap': 0,
+ 'failedCapacityInKb': 0,
+ 'netMetadataOverheadInKb': 0,
+ 'activeMovingOutBckRebuildJobs': 0,
+ 'rfcacheReadsFromCache': 0,
+ 'activeMovingOutEnterProtectedMaintenanceModeJobs': 0,
+ 'enterProtectedMaintenanceModeCapacityInKb': 0,
+ 'pendingMovingInNormRebuildJobs': 0,
+ 'failedVacInKb': 0,
+ 'primaryReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'fglUncompressedDataSizeInKb': 0,
+ 'fglCompressedDataSizeInKb': 0,
+ 'pendingRebalanceCapacityInKb': 0,
+ 'rfcacheAvgReadTime': 0,
+ 'semiProtectedCapacityInKb': 0,
+ 'pendingMovingOutEnterProtectedMaintenanceModeJobs': 0,
+ 'mgUserDdataCcapacityInKb': 0,
+ 'snapshotCapacityInKb': 0,
+ 'netMgUserDataCapacityInKb': 0,
+ 'fwdRebuildReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheWritesReceived': 0,
+ 'netUnusedCapacityInKb': 380602368,
+ 'thinUserDataCapacityInKb': 0,
+ 'protectedVacInKb': 16777216,
+ 'activeMovingRebalanceJobs': 0,
+ 'bckRebuildCapacityInKb': 0,
+ 'activeMovingInFwdRebuildJobs': 0,
+ 'netTrimmedUserDataCapacityInKb': 0,
+ 'pendingMovingRebalanceJobs': 0,
+ 'numOfMarkedVolumesForReplication': 0,
+ 'degradedHealthyVacInKb': 0,
+ 'semiProtectedVacInKb': 0,
+ 'userDataReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'pendingBckRebuildCapacityInKb': 0,
+ 'capacityLimitInKb': 845783040,
+ 'vtreeIds': [
+ 'vtree_id_1'
+ ],
+ 'activeMovingCapacityInKb': 1,
+ 'targetWriteLatency': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'pendingExitProtectedMaintenanceModeCapacityInKb': 1,
+ 'rfcacheIosSkipped': 1,
+ 'userDataWriteBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'inMaintenanceVacInKb': 1,
+ 'exitProtectedMaintenanceModeReadBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'netFglSparesInKb': 1,
+ 'rfcacheReadsSkipped': 1,
+ 'activeExitProtectedMaintenanceModeCapacityInKb': 1,
+ 'activeMovingOutExitProtectedMaintenanceModeJobs': 1,
+ 'numOfUnmappedVolumes': 2,
+ 'tempCapacityVacInKb': 1,
+ 'volumeAddressSpaceInKb': 80000,
+ 'currentFglMigrationSizeInKb': 1,
+ 'rfcacheWritesSkippedMaxIoSize': 1,
+ 'netMaxUserDataCapacityInKb': 380600000,
+ 'numOfMigratingVtrees': 1,
+ 'atRestCapacityInKb': 1,
+ 'rfacheWriteHit': 1,
+ 'bckRebuildReadBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'rfcacheSourceDeviceWrites': 1,
+ 'spareCapacityInKb': 84578000,
+ 'enterProtectedMaintenanceModeWriteBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'rfcacheIoErrors': 1,
+ 'inaccessibleCapacityInKb': 1,
+ 'normRebuildWriteBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'capacityInUseInKb': 1,
+ 'rebalanceReadBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'rfcacheReadsSkippedMaxIoSize': 1,
+ 'activeMovingInExitProtectedMaintenanceModeJobs': 1,
+ 'secondaryReadFromDevBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'secondaryReadBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'rfcacheWritesSkippedStuckIo': 1,
+ 'secondaryReadFromRmcacheBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'inMaintenanceCapacityInKb': 1,
+ 'exposedCapacityInKb': 1,
+ 'netFglCompressedDataSizeInKb': 1,
+ 'userDataSdcWriteLatency': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'inUseVacInKb': 16777000,
+ 'fwdRebuildCapacityInKb': 1,
+ 'thickCapacityInUseInKb': 1,
+ 'backgroundScanReadErrorCount': 1,
+ 'activeMovingInRebalanceJobs': 1,
+ 'migratingVolumeIds': [
+ '1xxx'
+ ],
+ 'rfcacheWritesSkippedLowResources': 1,
+ 'capacityInUseNoOverheadInKb': 1,
+ 'exitProtectedMaintenanceModeWriteBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'rfcacheSkippedUnlinedWrite': 1,
+ 'netCapacityInUseInKb': 1,
+ 'numOfOutgoingMigrations': 1,
+ 'rfcacheAvgWriteTime': 1,
+ 'pendingNormRebuildCapacityInKb': 1,
+ 'pendingMovingOutNormrebuildJobs': 1,
+ 'rfcacheSourceDeviceReads': 1,
+ 'rfcacheReadsPending': 1,
+ 'volumeAllocationLimitInKb': 3791650000,
+ 'rfcacheReadsSkippedHeavyLoad': 1,
+ 'fwdRebuildWriteBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'rfcacheReadMiss': 1,
+ 'targetReadLatency': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'userDataCapacityInKb': 1,
+ 'activeMovingInBckRebuildJobs': 1,
+ 'movingCapacityInKb': 1,
+ 'activeEnterProtectedMaintenanceModeCapacityInKb': 1,
+ 'backgroundScanCompareErrorCount': 1,
+ 'pendingMovingInFwdRebuildJobs': 1,
+ 'rfcacheReadsReceived': 1,
+ 'spSdsIds': [
+ 'sp_id_1',
+ 'sp_id_2',
+ 'sp_id_3'
+ ],
+ 'pendingEnterProtectedMaintenanceModeCapacityInKb': 1,
+ 'vtreeAddresSpaceInKb': 8388000,
+ 'snapCapacityInUseOccupiedInKb': 1,
+ 'activeFwdRebuildCapacityInKb': 1,
+ 'rfcacheReadsSkippedStuckIo': 1,
+ 'activeMovingOutNormRebuildJobs': 1,
+ 'rfcacheWritePending': 1,
+ 'numOfThinBaseVolumes': 2,
+ 'degradedFailedVacInKb': 1,
+ 'userDataTrimBwc': {
+ 'numSeconds': 1,
+ 'totalWeightInKb': 1,
+ 'numOccured': 1
+ },
+ 'numOfIncomingVtreeMigrations': 1
+ }
+
+ @staticmethod
+ def get_exception_response(response_type):
+ if response_type == 'get_details':
+ return "Failed to get the storage pool test_pool with error "
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_volume_api.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_volume_api.py
new file mode 100644
index 000000000..b05cc84d3
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/module_utils/mock_volume_api.py
@@ -0,0 +1,548 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""
+Mock Api response for Unit tests of volume module on Dell Technologies (Dell) PowerFlex
+"""
+
+from __future__ import (absolute_import, division, print_function)
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_storagepool_api import MockStoragePoolApi
+
+__metaclass__ = type
+
+
+class MockVolumeApi:
+ VOLUME_COMMON_ARGS = {
+ "hostname": "**.***.**.***",
+ "vol_name": None,
+ "vol_id": None,
+ "vol_type": None,
+ "compression_type": None,
+ "storage_pool_name": None,
+ "storage_pool_id": None,
+ "protection_domain_name": None,
+ "protection_domain_id": None,
+ "snapshot_policy_name": None,
+ "snapshot_policy_id": None,
+ "auto_snap_remove_type": None,
+ "use_rmcache": None,
+ "size": None,
+ "cap_unit": None,
+ "vol_new_name": None,
+ "sdc": {},
+ "sdc_state": None,
+ "delete_snapshots": None,
+ "state": None
+ }
+
+ VOLUME_GET_LIST = [
+ {
+ 'storagePoolId': 'test_pool_id_1',
+ 'dataLayout': 'MediumGranularity',
+ 'vtreeId': 'vtree_id_1',
+ 'sizeInKb': 8388608,
+ 'snplIdOfAutoSnapshot': None,
+ 'volumeType': 'ThinProvisioned',
+ 'consistencyGroupId': None,
+ 'ancestorVolumeId': None,
+ 'notGenuineSnapshot': False,
+ 'accessModeLimit': 'ReadWrite',
+ 'secureSnapshotExpTime': 0,
+ 'useRmcache': False,
+ 'managedBy': 'ScaleIO',
+ 'lockedAutoSnapshot': False,
+ 'lockedAutoSnapshotMarkedForRemoval': False,
+ 'autoSnapshotGroupId': None,
+ 'compressionMethod': 'Invalid',
+ 'pairIds': None,
+ 'timeStampIsAccurate': False,
+ 'mappedSdcInfo': None,
+ 'originalExpiryTime': 0,
+ 'retentionLevels': [
+ ],
+ 'snplIdOfSourceVolume': None,
+ 'volumeReplicationState': 'UnmarkedForReplication',
+ 'replicationJournalVolume': False,
+ 'replicationTimeStamp': 0,
+ 'creationTime': 1655878090,
+ 'name': 'testing',
+ 'id': 'test_id_1'
+ }
+ ]
+
+ VOLUME_STORAGEPOOL_DETAILS = MockStoragePoolApi.STORAGE_POOL_GET_LIST[0]
+
+ VOLUME_PD_DETAILS = {
+ 'rebalanceNetworkThrottlingEnabled': False,
+ 'vtreeMigrationNetworkThrottlingEnabled': False,
+ 'overallIoNetworkThrottlingEnabled': False,
+ 'rfcacheEnabled': True,
+ 'rfcacheAccpId': None,
+ 'rebuildNetworkThrottlingEnabled': False,
+ 'sdrSdsConnectivityInfo': {
+ 'clientServerConnStatus': 'CLIENT_SERVER_CONN_STATUS_ALL_CONNECTED',
+ 'disconnectedClientId': None,
+ 'disconnectedClientName': None,
+ 'disconnectedServerId': None,
+ 'disconnectedServerName': None,
+ 'disconnectedServerIp': None
+ },
+ 'protectionDomainState': 'Active',
+ 'rebuildNetworkThrottlingInKbps': None,
+ 'rebalanceNetworkThrottlingInKbps': None,
+ 'overallIoNetworkThrottlingInKbps': None,
+ 'vtreeMigrationNetworkThrottlingInKbps': None,
+ 'sdsDecoupledCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'sdsConfigurationFailureCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'mdmSdsNetworkDisconnectionsCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'sdsSdsNetworkDisconnectionsCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 300,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 500,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 700,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'rfcacheOpertionalMode': 'WriteMiss',
+ 'rfcachePageSizeKb': 64,
+ 'rfcacheMaxIoSizeKb': 128,
+ 'sdsReceiveBufferAllocationFailuresCounterParameters': {
+ 'shortWindow': {
+ 'threshold': 20000,
+ 'windowSizeInSec': 60
+ },
+ 'mediumWindow': {
+ 'threshold': 200000,
+ 'windowSizeInSec': 3600
+ },
+ 'longWindow': {
+ 'threshold': 2000000,
+ 'windowSizeInSec': 86400
+ }
+ },
+ 'fglDefaultNumConcurrentWrites': 1000,
+ 'fglMetadataCacheEnabled': False,
+ 'fglDefaultMetadataCacheSize': 0,
+ 'protectedMaintenanceModeNetworkThrottlingEnabled': False,
+ 'protectedMaintenanceModeNetworkThrottlingInKbps': None,
+ 'rplCapAlertLevel': 'normal',
+ 'systemId': 'syst_id_1',
+ 'name': 'domain1',
+ 'id': '4eeb304600000000',
+ }
+
+ VOLUME_STATISTICS = {
+ 'backgroundScanFixedReadErrorCount': 0,
+ 'pendingMovingOutBckRebuildJobs': 0,
+ 'degradedHealthyCapacityInKb': 0,
+ 'activeMovingOutFwdRebuildJobs': 0,
+ 'bckRebuildWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netFglUncompressedDataSizeInKb': 0,
+ 'primaryReadFromDevBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'BackgroundScannedInMB': 3209584,
+ 'volumeIds': [
+ '456ad22e00000003'
+ ],
+ 'maxUserDataCapacityInKb': 761204736,
+ 'persistentChecksumBuilderProgress': 100.0,
+ 'rfcacheReadsSkippedAlignedSizeTooLarge': 0,
+ 'pendingMovingInRebalanceJobs': 0,
+ 'rfcacheWritesSkippedHeavyLoad': 0,
+ 'unusedCapacityInKb': 761204736,
+ 'userDataSdcReadLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'totalReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'numOfDeviceAtFaultRebuilds': 0,
+ 'totalWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'persistentChecksumCapacityInKb': 414720,
+ 'rmPendingAllocatedInKb': 0,
+ 'numOfVolumes': 1,
+ 'rfcacheIosOutstanding': 0,
+ 'capacityAvailableForVolumeAllocationInKb': 377487360,
+ 'numOfMappedToAllVolumes': 0,
+ 'netThinUserDataCapacityInKb': 0,
+ 'backgroundScanFixedCompareErrorCount': 0,
+ 'volMigrationWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'thinAndSnapshotRatio': 'Infinity',
+ 'fglUserDataCapacityInKb': 0,
+ 'pendingMovingInEnterProtectedMaintenanceModeJobs': 0,
+ 'activeMovingInNormRebuildJobs': 0,
+ 'aggregateCompressionLevel': 'Uncompressed',
+ 'targetOtherLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netUserDataCapacityInKb': 0,
+ 'pendingMovingOutExitProtectedMaintenanceModeJobs': 0,
+ 'overallUsageRatio': 'Infinity',
+ 'volMigrationReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netCapacityInUseNoOverheadInKb': 0,
+ 'pendingMovingInBckRebuildJobs': 0,
+ 'rfcacheReadsSkippedInternalError': 0,
+ 'activeBckRebuildCapacityInKb': 0,
+ 'rebalanceCapacityInKb': 0,
+ 'pendingMovingInExitProtectedMaintenanceModeJobs': 0,
+ 'rfcacheReadsSkippedLowResources': 0,
+ 'rplJournalCapAllowed': 0,
+ 'thinCapacityInUseInKb': 0,
+ 'userDataSdcTrimLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'activeMovingInEnterProtectedMaintenanceModeJobs': 0,
+ 'rfcacheWritesSkippedInternalError': 0,
+ 'netUserDataCapacityNoTrimInKb': 0,
+ 'rfcacheWritesSkippedCacheMiss': 0,
+ 'degradedFailedCapacityInKb': 0,
+ 'activeNormRebuildCapacityInKb': 0,
+ 'fglSparesInKb': 0,
+ 'snapCapacityInUseInKb': 0,
+ 'numOfMigratingVolumes': 0,
+ 'compressionRatio': 0.0,
+ 'rfcacheWriteMiss': 0,
+ 'primaryReadFromRmcacheBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'migratingVtreeIds': [
+ ],
+ 'numOfVtrees': 1,
+ 'userDataCapacityNoTrimInKb': 0,
+ 'rfacheReadHit': 0,
+ 'compressedDataCompressionRatio': 0.0,
+ 'rplUsedJournalCap': 0,
+ 'pendingMovingCapacityInKb': 0,
+ 'numOfSnapshots': 0,
+ 'pendingFwdRebuildCapacityInKb': 0,
+ 'tempCapacityInKb': 0,
+ 'totalFglMigrationSizeInKb': 0,
+ 'normRebuildCapacityInKb': 0,
+ 'logWrittenBlocksInKb': 0,
+ 'primaryWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'numOfThickBaseVolumes': 0,
+ 'enterProtectedMaintenanceModeReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'activeRebalanceCapacityInKb': 0,
+ 'numOfReplicationJournalVolumes': 0,
+ 'rfcacheReadsSkippedLockIos': 0,
+ 'unreachableUnusedCapacityInKb': 0,
+ 'netProvisionedAddressesInKb': 0,
+ 'trimmedUserDataCapacityInKb': 0,
+ 'provisionedAddressesInKb': 0,
+ 'numOfVolumesInDeletion': 0,
+ 'pendingMovingOutFwdRebuildJobs': 0,
+ 'maxCapacityInKb': 845783040,
+ 'rmPendingThickInKb': 0,
+ 'protectedCapacityInKb': 0,
+ 'secondaryWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'normRebuildReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'thinCapacityAllocatedInKb': 16777216,
+ 'netFglUserDataCapacityInKb': 0,
+ 'metadataOverheadInKb': 0,
+ 'thinCapacityAllocatedInKm': 16777216,
+ 'rebalanceWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'primaryVacInKb': 8388608,
+ 'deviceIds': [
+ 'bbd7580800030001',
+ 'bbd4580a00040001',
+ 'bbd5580b00050001'
+ ],
+ 'netSnapshotCapacityInKb': 0,
+ 'secondaryVacInKb': 8388608,
+ 'numOfDevices': 3,
+ 'rplTotalJournalCap': 0,
+ 'failedCapacityInKb': 0,
+ 'netMetadataOverheadInKb': 0,
+ 'activeMovingOutBckRebuildJobs': 0,
+ 'rfcacheReadsFromCache': 0,
+ 'activeMovingOutEnterProtectedMaintenanceModeJobs': 0,
+ 'enterProtectedMaintenanceModeCapacityInKb': 0,
+ 'pendingMovingInNormRebuildJobs': 0,
+ 'failedVacInKb': 0,
+ 'primaryReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'fglUncompressedDataSizeInKb': 0,
+ 'fglCompressedDataSizeInKb': 0,
+ 'pendingRebalanceCapacityInKb': 0,
+ 'rfcacheAvgReadTime': 0,
+ 'semiProtectedCapacityInKb': 0,
+ 'pendingMovingOutEnterProtectedMaintenanceModeJobs': 0,
+ 'mgUserDdataCcapacityInKb': 0,
+ 'snapshotCapacityInKb': 0,
+ 'netMgUserDataCapacityInKb': 0,
+ 'fwdRebuildReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheWritesReceived': 0,
+ 'netUnusedCapacityInKb': 380602368,
+ 'thinUserDataCapacityInKb': 0,
+ 'protectedVacInKb': 16777216,
+ 'activeMovingRebalanceJobs': 0,
+ 'bckRebuildCapacityInKb': 0,
+ 'activeMovingInFwdRebuildJobs': 0,
+ 'netTrimmedUserDataCapacityInKb': 0,
+ 'pendingMovingRebalanceJobs': 0,
+ 'numOfMarkedVolumesForReplication': 0,
+ 'degradedHealthyVacInKb': 0,
+ 'semiProtectedVacInKb': 0,
+ 'userDataReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'pendingBckRebuildCapacityInKb': 0,
+ 'capacityLimitInKb': 845783040,
+ 'vtreeIds': [
+ '32b13de900000003'
+ ],
+ 'activeMovingCapacityInKb': 0,
+ 'targetWriteLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'pendingExitProtectedMaintenanceModeCapacityInKb': 0,
+ 'rfcacheIosSkipped': 0,
+ 'userDataWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'inMaintenanceVacInKb': 0,
+ 'exitProtectedMaintenanceModeReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'netFglSparesInKb': 0,
+ 'rfcacheReadsSkipped': 0,
+ 'activeExitProtectedMaintenanceModeCapacityInKb': 0,
+ 'activeMovingOutExitProtectedMaintenanceModeJobs': 0,
+ 'numOfUnmappedVolumes': 1,
+ 'tempCapacityVacInKb': 0,
+ 'volumeAddressSpaceInKb': 8388608,
+ 'currentFglMigrationSizeInKb': 0,
+ 'rfcacheWritesSkippedMaxIoSize': 0,
+ 'netMaxUserDataCapacityInKb': 380602368,
+ 'numOfMigratingVtrees': 0,
+ 'atRestCapacityInKb': 0,
+ 'rfacheWriteHit': 0,
+ 'bckRebuildReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheSourceDeviceWrites': 0,
+ 'spareCapacityInKb': 84578304,
+ 'enterProtectedMaintenanceModeWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheIoErrors': 0,
+ 'inaccessibleCapacityInKb': 0,
+ 'normRebuildWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'capacityInUseInKb': 0,
+ 'rebalanceReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheReadsSkippedMaxIoSize': 0,
+ 'activeMovingInExitProtectedMaintenanceModeJobs': 0,
+ 'secondaryReadFromDevBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'secondaryReadBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheWritesSkippedStuckIo': 0,
+ 'secondaryReadFromRmcacheBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'inMaintenanceCapacityInKb': 0,
+ 'exposedCapacityInKb': 0,
+ 'netFglCompressedDataSizeInKb': 0,
+ 'userDataSdcWriteLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'inUseVacInKb': 16777216,
+ 'fwdRebuildCapacityInKb': 0,
+ 'thickCapacityInUseInKb': 0,
+ 'backgroundScanReadErrorCount': 0,
+ 'activeMovingInRebalanceJobs': 0,
+ 'migratingVolumeIds': [
+ ],
+ 'rfcacheWritesSkippedLowResources': 0,
+ 'capacityInUseNoOverheadInKb': 0,
+ 'exitProtectedMaintenanceModeWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheSkippedUnlinedWrite': 0,
+ 'netCapacityInUseInKb': 0,
+ 'numOfOutgoingMigrations': 0,
+ 'rfcacheAvgWriteTime': 0,
+ 'pendingNormRebuildCapacityInKb': 0,
+ 'pendingMovingOutNormrebuildJobs': 0,
+ 'rfcacheSourceDeviceReads': 0,
+ 'rfcacheReadsPending': 0,
+ 'volumeAllocationLimitInKb': 3791650816,
+ 'rfcacheReadsSkippedHeavyLoad': 0,
+ 'fwdRebuildWriteBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'rfcacheReadMiss': 0,
+ 'targetReadLatency': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'userDataCapacityInKb': 0,
+ 'activeMovingInBckRebuildJobs': 0,
+ 'movingCapacityInKb': 0,
+ 'activeEnterProtectedMaintenanceModeCapacityInKb': 0,
+ 'backgroundScanCompareErrorCount': 0,
+ 'pendingMovingInFwdRebuildJobs': 0,
+ 'rfcacheReadsReceived': 0,
+ 'spSdsIds': [
+ 'abdfe71b00030001',
+ 'abdce71d00040001',
+ 'abdde71e00050001'
+ ],
+ 'pendingEnterProtectedMaintenanceModeCapacityInKb': 0,
+ 'vtreeAddresSpaceInKb': 8388608,
+ 'snapCapacityInUseOccupiedInKb': 0,
+ 'activeFwdRebuildCapacityInKb': 0,
+ 'rfcacheReadsSkippedStuckIo': 0,
+ 'activeMovingOutNormRebuildJobs': 0,
+ 'rfcacheWritePending': 0,
+ 'numOfThinBaseVolumes': 1,
+ 'degradedFailedVacInKb': 0,
+ 'userDataTrimBwc': {
+ 'numSeconds': 0,
+ 'totalWeightInKb': 0,
+ 'numOccured': 0
+ },
+ 'numOfIncomingVtreeMigrations': 0
+ }
+
+ @staticmethod
+ def get_exception_response(response_type):
+ if response_type == 'get_details':
+ return "Failed to get the volume test_id_1 with error "
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/__init__.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/__init__.py
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_info.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_info.py
new file mode 100644
index 000000000..2bd0ff158
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_info.py
@@ -0,0 +1,151 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for info module on PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_info_api import MockInfoApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKResponse
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.info import PowerFlexInfo
+
+
+class TestPowerflexInfo():
+
+ get_module_args = MockInfoApi.INFO_COMMON_ARGS
+
+ @pytest.fixture
+ def info_module_mock(self, mocker):
+ info_module_mock = PowerFlexInfo()
+ info_module_mock.module.check_mode = False
+ info_module_mock.powerflex_conn.system.api_version = MagicMock(
+ return_value=3.5
+ )
+ info_module_mock.powerflex_conn.system.get = MagicMock(
+ return_value=MockInfoApi.INFO_ARRAY_DETAILS
+ )
+ return info_module_mock
+
+ def test_get_volume_details(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['vol']
+ })
+ info_module_mock.module.params = self.get_module_args
+ volume_resp = MockInfoApi.INFO_VOLUME_GET_LIST
+ info_module_mock.powerflex_conn.volume.get = MagicMock(
+ return_value=volume_resp
+ )
+ volume_stat_resp = MockInfoApi.INFO_VOLUME_STATISTICS
+ info_module_mock.powerflex_conn.utility.get_statistics_for_all_volumes = MagicMock(
+ return_value=volume_stat_resp
+ )
+ info_module_mock.perform_module_operation()
+ info_module_mock.powerflex_conn.volume.get.assert_called()
+ info_module_mock.powerflex_conn.utility.get_statistics_for_all_volumes.assert_called()
+
+ def test_get_volume_details_with_exception(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['vol']
+ })
+ info_module_mock.module.params = self.get_module_args
+ volume_resp = MockInfoApi.INFO_VOLUME_GET_LIST
+ info_module_mock.powerflex_conn.volume.get = MagicMock(
+ return_value=volume_resp
+ )
+ info_module_mock.powerflex_conn.utility.get_statistics_for_all_volumes = MagicMock(
+ side_effect=MockApiException
+ )
+ info_module_mock.perform_module_operation()
+ assert MockInfoApi.get_exception_response('volume_get_details') in info_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_sp_details(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['storage_pool']
+ })
+ info_module_mock.module.params = self.get_module_args
+ sp_resp = MockInfoApi.INFO_STORAGE_POOL_GET_LIST
+ info_module_mock.powerflex_conn.storage_pool.get = MagicMock(
+ return_value=sp_resp
+ )
+ sp_stat_resp = MockInfoApi.INFO_STORAGE_POOL_STATISTICS
+ info_module_mock.powerflex_conn.utility.get_statistics_for_all_storagepools = MagicMock(
+ return_value=sp_stat_resp
+ )
+ info_module_mock.perform_module_operation()
+ info_module_mock.powerflex_conn.storage_pool.get.assert_called()
+ info_module_mock.powerflex_conn.utility.get_statistics_for_all_storagepools.assert_called()
+
+ def test_get_sp_details_with_exception(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['storage_pool']
+ })
+ info_module_mock.module.params = self.get_module_args
+ sp_resp = MockInfoApi.INFO_STORAGE_POOL_GET_LIST
+ info_module_mock.powerflex_conn.storage_pool.get = MagicMock(
+ return_value=sp_resp
+ )
+ info_module_mock.powerflex_conn.utility.get_statistics_for_all_storagepools = MagicMock(
+ side_effect=MockApiException
+ )
+ info_module_mock.perform_module_operation()
+ assert MockInfoApi.get_exception_response('sp_get_details') in info_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_rcg_details(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['rcg']
+ })
+ info_module_mock.module.params = self.get_module_args
+ rcg_resp = MockInfoApi.RCG_LIST
+ info_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=rcg_resp)
+ info_module_mock.perform_module_operation()
+ info_module_mock.powerflex_conn.replication_consistency_group.get.assert_called()
+
+ def test_get_rcg_details_throws_exception(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['rcg']
+ })
+ info_module_mock.module.params = self.get_module_args
+ info_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ side_effect=MockApiException
+ )
+ info_module_mock.perform_module_operation()
+ assert MockInfoApi.get_exception_response('rcg_get_details') in info_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_replication_pair_details(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['replication_pair']
+ })
+ info_module_mock.module.params = self.get_module_args
+ info_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockInfoApi.PAIR_LIST)
+ info_module_mock.perform_module_operation()
+ info_module_mock.powerflex_conn.replication_pair.get.assert_called()
+
+ def test_get_replication_pair_details_throws_exception(self, info_module_mock):
+ self.get_module_args.update({
+ "gather_subset": ['replication_pair']
+ })
+ info_module_mock.module.params = self.get_module_args
+ info_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ side_effect=MockApiException
+ )
+ info_module_mock.perform_module_operation()
+ assert MockInfoApi.get_exception_response('replication_pair_get_details') in info_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_mdm_cluster.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_mdm_cluster.py
new file mode 100644
index 000000000..f8f3cdc2f
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_mdm_cluster.py
@@ -0,0 +1,636 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for MDM cluster module on PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_mdm_cluster_api import MockMdmClusterApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKResponse
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.mdm_cluster import PowerFlexMdmCluster
+
+
+class TestPowerflexMDMCluster():
+
+ get_module_args = MockMdmClusterApi.MDM_CLUSTER_COMMON_ARGS
+ add_mdm_ip = "xx.3x.xx.xx"
+
+ @pytest.fixture
+ def mdm_cluster_module_mock(self, mocker):
+ mocker.patch(MockMdmClusterApi.MODULE_UTILS_PATH + '.PowerFlexClient', new=MockApiException)
+ mdm_cluster_module_mock = PowerFlexMdmCluster()
+ mdm_cluster_module_mock.module.check_mode = False
+ return mdm_cluster_module_mock
+
+ def test_get_mdm_cluster(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details.assert_called()
+
+ def test_get_mdm_cluster_with_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.get_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details.assert_called()
+
+ def test_rename_mdm(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": MockMdmClusterApi.MDM_NAME,
+ "mdm_new_name": "mdm_node_renamed",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.rename_mdm = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.rename_mdm.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_rename_mdm_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": MockMdmClusterApi.MDM_NAME,
+ "mdm_new_name": "mdm_node_renamed",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.rename_mdm = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.rename_mdm.assert_called()
+ assert MockMdmClusterApi.rename_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_set_performance_profile_mdm_cluster(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "performance_profile": "Compact",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.set_cluster_mdm_performance_profile = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.set_cluster_mdm_performance_profile.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_set_performance_profile_mdm_cluster_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "performance_profile": "Compact",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.set_cluster_mdm_performance_profile = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.set_cluster_mdm_performance_profile.assert_called()
+ assert MockMdmClusterApi.perf_profile_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_set_virtual_ip_interface_mdm(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": MockMdmClusterApi.MDM_ID,
+ "virtual_ip_interfaces": ["ens11"],
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.modify_virtual_ip_interface = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.modify_virtual_ip_interface.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_set_virtual_ip_interface_mdm_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": MockMdmClusterApi.MDM_ID,
+ "virtual_ip_interfaces": ["ens11"],
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.modify_virtual_ip_interface = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.modify_virtual_ip_interface.assert_called()
+ assert MockMdmClusterApi.virtual_ip_interface_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_set_virtual_ip_interface_mdm_idempotency(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": MockMdmClusterApi.MDM_ID,
+ "virtual_ip_interfaces": ["ens1"],
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_remove_standby_mdm(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": MockMdmClusterApi.STB_TB_MDM_ID,
+ "state": "absent"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.remove_standby_mdm = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.remove_standby_mdm.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_remove_standby_mdm_idempotency(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "non_existing_node",
+ "state": "absent"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_remove_standby_mdm_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": MockMdmClusterApi.STB_TB_MDM_ID,
+ "state": "absent"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.remove_standby_mdm = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.remove_standby_mdm.assert_called()
+ assert MockMdmClusterApi.remove_mdm_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_add_standby_mdm(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "standby_node",
+ "standby_mdm": {
+ "mdm_ips": [self.add_mdm_ip],
+ "role": "Manager",
+ "port": 9011,
+ "management_ips": [self.add_mdm_ip],
+ "virtual_interfaces": ["ens1"],
+ "allow_multiple_ips": True
+ },
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.add_standby_mdm = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.add_standby_mdm.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_add_standby_mdm_idempotency(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": MockMdmClusterApi.MDM_NAME,
+ "standby_mdm": {
+ "mdm_ips": ["10.x.z.z"],
+ "role": "TieBreaker",
+ "port": 9011
+ },
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_add_standby_mdm_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "standby_node",
+ "standby_mdm": {
+ "mdm_ips": [self.add_mdm_ip],
+ "role": "Manager",
+ "port": 9011,
+ "management_ips": [self.add_mdm_ip],
+ "virtual_interfaces": ["ens1"],
+ "allow_multiple_ips": True
+ },
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.add_standby_mdm = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.add_standby_mdm.assert_called()
+ assert MockMdmClusterApi.add_mdm_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_change_mdm_cluster_owner(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "sample_mdm1",
+ "is_primary": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.change_mdm_ownership = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.change_mdm_ownership.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_change_mdm_cluster_owner_idempotency(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": "5908d328581d1400",
+ "is_primary": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(
+ MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_change_mdm_cluster_owner_execption(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "sample_mdm1",
+ "is_primary": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.change_mdm_ownership = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.change_mdm_ownership.assert_called()
+ assert MockMdmClusterApi.owner_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_expand_mdm_cluster_mode(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "cluster_mode": "FiveNodes",
+ "mdm": [
+ {
+ "mdm_name": MockMdmClusterApi.MDM_NAME_STB_MGR,
+ "mdm_id": None,
+ "mdm_type": "Secondary"
+ },
+ {
+ "mdm_id": MockMdmClusterApi.STB_TB_MDM_ID,
+ "mdm_name": None,
+ "mdm_type": "TieBreaker"
+ }
+ ],
+ "mdm_state": "present-in-cluster",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.switch_cluster_mode = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.switch_cluster_mode.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_reduce_mdm_cluster_mode_idempotency(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "cluster_mode": "ThreeNodes",
+ "mdm": [
+ {
+ "mdm_name": None,
+ "mdm_id": MockMdmClusterApi.STB_MGR_MDM_ID,
+ "mdm_type": "Secondary"
+ },
+ {
+ "mdm_id": None,
+ "mdm_name": MockMdmClusterApi.MDM_NAME,
+ "mdm_type": "TieBreaker"
+ }
+ ],
+ "mdm_state": "absent-in-cluster",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_expand_mdm_cluster_mode_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "cluster_mode": "FiveNodes",
+ "mdm": [
+ {
+ "mdm_name": MockMdmClusterApi.MDM_NAME_STB_MGR,
+ "mdm_id": None,
+ "mdm_type": "Secondary"
+ },
+ {
+ "mdm_id": MockMdmClusterApi.STB_TB_MDM_ID,
+ "mdm_name": None,
+ "mdm_type": "TieBreaker"
+ }
+ ],
+ "mdm_state": "present-in-cluster",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.switch_cluster_mode = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.switch_cluster_mode.assert_called()
+ assert MockMdmClusterApi.switch_mode_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_reduce_mdm_cluster_mode(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "cluster_mode": "ThreeNodes",
+ "mdm": [
+ {
+ "mdm_name": None,
+ "mdm_id": MockMdmClusterApi.STB_MGR_MDM_ID,
+ "mdm_type": "Secondary"
+ },
+ {
+ "mdm_id": None,
+ "mdm_name": MockMdmClusterApi.MDM_NAME,
+ "mdm_type": "TieBreaker"
+ }
+ ],
+ "mdm_state": "absent-in-cluster",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.FIVE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.switch_cluster_mode = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.switch_cluster_mode.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_clear_virtual_ip_interface_mdm(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": MockMdmClusterApi.STB_MGR_MDM_ID,
+ "clear_interfaces": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.modify_virtual_ip_interface = MagicMock()
+ mdm_cluster_module_mock.perform_module_operation()
+ mdm_cluster_module_mock.powerflex_conn.system.modify_virtual_ip_interface.assert_called()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_clear_virtual_ip_interface_mdm_idempotency(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "sample_mdm11",
+ "clear_interfaces": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.FIVE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert mdm_cluster_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_get_system_id_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_module_mock.powerflex_conn.system.get = MagicMock(
+ side_effect=utils.PowerFlexClient
+ )
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.system_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_remove_mdm_cluster_owner_none(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "state": "absent"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.remove_mdm_no_id_name_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_expand_cluster_without_standby(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "cluster_mode": "FiveNodes",
+ "mdm": [
+ {
+ "mdm_name": None,
+ "mdm_id": None,
+ "mdm_type": "Secondary"
+ },
+ {
+ "mdm_id": None,
+ "mdm_name": None,
+ "mdm_type": "TieBreaker"
+ }
+ ],
+ "mdm_state": "present-in-cluster",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS_2)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.without_standby_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_system_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ system_resp = MockSDKResponse(MockMdmClusterApi.PARTIAL_SYSTEM_DETAILS_1)
+ mdm_cluster_module_mock.powerflex_conn.system.get = MagicMock(
+ return_value=system_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value={}
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.no_cluster_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_clear_virtual_ip_interface_mdm_id_none(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": None,
+ "clear_interfaces": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.is_mdm_name_id_exists = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS['master']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.id_none_interface_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_rename_mdm_id_none(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": None,
+ "mdm_new_name": "new_node",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.is_mdm_name_id_exists = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS['master']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.id_none_rename_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_change_owner_id_none(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_id": None,
+ "is_primary": True,
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.is_mdm_name_id_exists = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS['master']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.id_none_change_owner_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_multiple_system_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ system_resp = MockSDKResponse(MockMdmClusterApi.PARTIAL_SYSTEM_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get = MagicMock(
+ return_value=system_resp.__dict__['data']
+ )
+ mdm_cluster_resp = MockSDKResponse(MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS)
+ mdm_cluster_module_mock.powerflex_conn.system.get_mdm_cluster_details = MagicMock(
+ return_value=mdm_cluster_resp.__dict__['data']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.multiple_system_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_add_standby_mdm_new_name_exception(self, mdm_cluster_module_mock):
+ self.get_module_args.update({
+ "mdm_name": "standby_node",
+ "standby_mdm": {
+ "mdm_ips": [self.add_mdm_ip],
+ "role": "Manager",
+ "port": 9011,
+ "management_ips": [self.add_mdm_ip],
+ "virtual_interfaces": ["ens1"],
+ "allow_multiple_ips": True
+ },
+ "mdm_new_name": "new_node",
+ "state": "present"
+ })
+ mdm_cluster_module_mock.module.params = self.get_module_args
+ mdm_cluster_module_mock.get_mdm_cluster_details = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS
+ )
+ mdm_cluster_module_mock.is_mdm_name_id_exists = MagicMock(
+ return_value=MockMdmClusterApi.THREE_MDM_CLUSTER_DETAILS['master']
+ )
+ mdm_cluster_module_mock.perform_module_operation()
+ assert MockMdmClusterApi.new_name_add_mdm_failed_response() in mdm_cluster_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_protection_domain.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_protection_domain.py
new file mode 100644
index 000000000..ced9fc7f7
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_protection_domain.py
@@ -0,0 +1,236 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for Protection Domain module on Dell Technologies (Dell) PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_protection_domain_api import MockProtectionDomainApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKResponse
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.protection_domain import PowerFlexProtectionDomain
+
+
+class TestPowerflexProtectionDomain():
+
+ get_module_args = {
+ 'hostname': '**.***.**.***',
+ 'protection_domain_id': '7bd6457000000000',
+ 'protection_domain_name': None,
+ 'protection_domain_new_name': None,
+ 'is_active': True,
+ 'network_limits': {
+ 'rebuild_limit': 10240,
+ 'rebalance_limit': 10240,
+ 'vtree_migration_limit': 10240,
+ 'overall_limit': 20480,
+ 'bandwidth_unit': 'KBps',
+ },
+ 'rf_cache_limits': {
+ 'is_enabled': None,
+ 'page_size': 4,
+ 'max_io_limit': 16,
+ 'pass_through_mode': 'None'
+ },
+ 'state': 'present'
+ }
+
+ @pytest.fixture
+ def protection_domain_module_mock(self, mocker):
+ mocker.patch(MockProtectionDomainApi.MODULE_UTILS_PATH + '.PowerFlexClient', new=MockApiException)
+ protection_domain_module_mock = PowerFlexProtectionDomain()
+ return protection_domain_module_mock
+
+ def test_get_protection_domain_response(self, protection_domain_module_mock):
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.perform_module_operation()
+ protection_domain_module_mock.powerflex_conn.protection_domain.get.assert_called()
+
+ def test_create_protection_domain(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ "protection_domain_name": "test_domain",
+ "state": "present"
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.get_protection_domain = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain'][0]
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.create = MagicMock(return_values=None)
+ protection_domain_module_mock.perform_module_operation()
+ assert (self.get_module_args['protection_domain_name'] ==
+ protection_domain_module_mock.module.exit_json.call_args[1]["protection_domain_details"]['name'])
+ assert protection_domain_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_modify_protection_domain(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ 'network_limits': {
+ 'rebuild_limit': 10,
+ 'rebalance_limit': 10,
+ 'vtree_migration_limit': 11,
+ 'overall_limit': 21,
+ 'bandwidth_unit': 'GBps',
+ }
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ sp_resp = MockSDKResponse(MockProtectionDomainApi.STORAGE_POOL)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.get_storage_pools = MagicMock(
+ return_value=sp_resp.__dict__['data']['storagepool']
+ )
+ protection_domain_module_mock.perform_module_operation()
+ protection_domain_module_mock.powerflex_conn.protection_domain.network_limits.assert_called()
+
+ def test_rename_protection_domain(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ 'protection_domain_new_name': 'new_test_domain'
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.perform_module_operation()
+ protection_domain_module_mock.powerflex_conn.protection_domain.rename.assert_called()
+
+ def test_inactivate_protection_domain(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ 'is_active': False
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.perform_module_operation()
+ protection_domain_module_mock.powerflex_conn.protection_domain. \
+ inactivate.assert_called()
+
+ def test_activate_protection_domain(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ 'is_active': True
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.activate = MagicMock(return_value=None)
+ protection_domain_module_mock.perform_module_operation()
+ assert protection_domain_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_delete_protection_domain(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ 'protection_domain_name': 'new_test_domain',
+ 'state': 'absent'
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ protection_domain_module_mock.get_protection_domain = MagicMock(return_values=None)
+ protection_domain_module_mock.perform_module_operation()
+ assert protection_domain_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_delete_protection_domain_throws_exception(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ 'protection_domain_id': '7bd6457000000000',
+ 'state': 'absent'
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.delete = MagicMock(
+ side_effect=utils.PowerFlexClient)
+ protection_domain_module_mock.perform_module_operation()
+ assert MockProtectionDomainApi.delete_pd_failed_msg(self.get_module_args['protection_domain_id']) in \
+ protection_domain_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_with_404_exception(self, protection_domain_module_mock):
+ MockProtectionDomainApi.status = 404
+ self.get_module_args.update({
+ "protection_domain_name": "test_domain1"
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.create = MagicMock(
+ side_effect=utils.PowerFlexClient)
+ protection_domain_module_mock.perform_module_operation()
+ assert protection_domain_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_modify_protection_domain_throws_exception(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ "protection_domain_id": "7bd6457000000000",
+ 'rf_cache_limits': {
+ 'is_enabled': True,
+ 'page_size': 64,
+ 'max_io_limit': 128,
+ 'pass_through_mode': 'invalid_Read'
+ }
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.set_rfcache_enabled = MagicMock(
+ side_effect=utils.PowerFlexClient)
+ protection_domain_module_mock.perform_module_operation()
+ assert MockProtectionDomainApi.modify_pd_with_failed_msg(self.get_module_args['protection_domain_id']) in \
+ protection_domain_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_rename_protection_domain_invalid_value(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ "protection_domain_name": "test_domain",
+ "protection_domain_new_name": " test domain",
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.rename = MagicMock(
+ side_effect=utils.PowerFlexClient)
+ protection_domain_module_mock.perform_module_operation()
+ assert MockProtectionDomainApi.rename_pd_failed_msg(self.get_module_args['protection_domain_id']) in \
+ protection_domain_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_protection_domain_invalid_param(self, protection_domain_module_mock):
+ self.get_module_args.update({
+ "protection_domain_name": "test_domain1",
+ "protection_domain_new_name": "new_domain",
+ "state": "present"
+ })
+ protection_domain_module_mock.module.params = self.get_module_args
+ pd_resp = MockSDKResponse(MockProtectionDomainApi.PROTECTION_DOMAIN)
+ protection_domain_module_mock.powerflex_conn.protection_domain.get = MagicMock(
+ return_value=pd_resp.__dict__['data']['protectiondomain']
+ )
+ protection_domain_module_mock.powerflex_conn.protection_domain.create = MagicMock(
+ side_effect=utils.PowerFlexClient)
+ protection_domain_module_mock.perform_module_operation()
+ assert MockProtectionDomainApi.version_pd_failed_msg() in \
+ protection_domain_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_consistency_group.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_consistency_group.py
new file mode 100644
index 000000000..334de8942
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_consistency_group.py
@@ -0,0 +1,344 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for replication consistency group module on PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+from unittest.mock import Mock
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_replication_consistency_group_api import MockReplicationConsistencyGroupApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.replication_consistency_group import PowerFlexReplicationConsistencyGroup
+
+
+class TestPowerflexReplicationConsistencyGroup():
+
+ get_module_args = MockReplicationConsistencyGroupApi.RCG_COMMON_ARGS
+
+ @pytest.fixture
+ def replication_consistency_group_module_mock(self):
+ replication_consistency_group_module_mock = PowerFlexReplicationConsistencyGroup()
+ replication_consistency_group_module_mock.module.check_mode = False
+ return replication_consistency_group_module_mock
+
+ def test_get_rcg_details(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "state": "present"
+ })
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_resp = MockReplicationConsistencyGroupApi.get_rcg_details()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=replication_consistency_group_resp
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get.assert_called()
+
+ def test_get_rcg_details_with_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "state": "present"
+ })
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ side_effect=MockApiException)
+ replication_consistency_group_module_mock.validate_create = MagicMock()
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert MockReplicationConsistencyGroupApi.get_exception_response('get_details') in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_rcg_snapshot_response(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "create_snapshot": True,
+ "state": "present"
+ })
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_resp = MockReplicationConsistencyGroupApi.get_rcg_details()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=replication_consistency_group_resp
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.create_snapshot.assert_called()
+
+ def test_create_rcg_snapshot_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({
+ "rcg_id": "aadc17d500000000",
+ "create_snapshot": True,
+ "state": "present"
+ })
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_resp = MockReplicationConsistencyGroupApi.get_rcg_details()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=replication_consistency_group_resp
+ )
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.create_snapshot = MagicMock(
+ side_effect=MockApiException
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert MockReplicationConsistencyGroupApi.create_snapshot_exception_response('create_snapshot', self.get_module_args['rcg_id']) \
+ in replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg", "rpo": 60, "protection_domain_name": "domain1",
+ "protection_domain_id": None, "activity_mode": "active", "state": "present",
+ "remote_peer": {"hostname": "1.1.1.1", "username": "username", "password": "password",
+ "verifycert": "verifycert", "port": "port", "protection_domain_name": "None",
+ "protection_domain_id": "123"}})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=None
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.create.assert_called()
+
+ def test_modify_rpo(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "rpo": 60, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details()
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.modify_rpo.assert_called()
+
+ def test_modify_rpo_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "rpo": 60, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.modify_rpo = MagicMock(
+ side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Modify rpo for replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_modify_target_volume_access_mode(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "target_volume_access_mode": "Readonly", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details()
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.modify_target_volume_access_mode.assert_called()
+
+ def test_modify_target_volume_access_mode_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "target_volume_access_mode": "Readonly", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.modify_target_volume_access_mode = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Modify target volume access mode for replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID \
+ + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_modify_activity_mode(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "activity_mode": "Inactive", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.inactivate.assert_called()
+
+ def test_modify_activity_mode_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "activity_mode": "Active", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details(activity_mode="Inactive"))
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.activate = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Modify activity_mode for replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID \
+ + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_pause_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "pause": True,
+ "pause_mode": "StopDataTransfer", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details()
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.pause.assert_called()
+
+ def test_pause_rcg_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "pause": True,
+ "pause_mode": "StopDataTransfer", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.pause = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Pause replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID \
+ + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_resume_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "pause": False, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details(pause_mode="StopDataTransfer"))
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.resume.assert_called()
+
+ def test_resume_rcg_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "pause": False, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details(pause_mode="StopDataTransfer"))
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.resume = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Resume replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID \
+ + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_freeze_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "freeze": True, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.freeze.assert_called()
+
+ def test_freeze_rcg_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "freeze": True, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.freeze = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Freeze replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID \
+ + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_unfreeze_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "freeze": False, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details(freeze_state="Frozen")
+ )
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.unfreeze.assert_called()
+
+ def test_unfreeze_rcg_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "freeze": False, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details(freeze_state="Frozen"))
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.unfreeze = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Unfreeze replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID \
+ + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_rename_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "new_rcg_name": "test_rcg_rename", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.rename_rcg.assert_called()
+
+ def test_rename_rcg_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "new_rcg_name": "test_rcg_rename", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.rename_rcg = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Renaming replication consistency group to test_rcg_rename failed with error" in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_delete_rcg(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "state": "absent"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.delete.assert_called()
+
+ def test_delete_rcg_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "state": "absent"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.delete = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Delete replication consistency group " + MockReplicationConsistencyGroupApi.RCG_ID + MockReplicationConsistencyGroupApi.FAIL_MSG in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_modify_rcg_as_inconsistent(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "is_consistent": False, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.perform_module_operation()
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.set_as_inconsistent.assert_called()
+
+ def test_modify_rcg_as_consistent_throws_exception(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "is_consistent": True, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details(consistency="InConsistent"))
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.set_as_consistent = \
+ MagicMock(side_effect=MockApiException)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Modifying consistency of replication consistency group failed with error" in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_pause_rcg_without_pause_mode(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "pause": True, "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.protection_domain.get = MagicMock(return_value=[{"name": "pd_id"}])
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Specify pause_mode to perform pause on replication consistency group." in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_rcg_with_invalid_params(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg", "activity_mode": "active", "state": "present",
+ "remote_peer": {"hostname": "1.1.1.1", "username": "username", "password": "password",
+ "verifycert": "verifycert", "port": "port", "protection_domain_name": None,
+ "protection_domain_id": None}})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=None)
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Enter remote protection_domain_name or protection_domain_id to create replication consistency group" in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_pause_rcg_without_pause(self, replication_consistency_group_module_mock):
+ self.get_module_args.update({"rcg_name": "test_rcg", "pause_mode": "StopDataTransfer", "state": "present"})
+ replication_consistency_group_module_mock.module.params = self.get_module_args
+ replication_consistency_group_module_mock.powerflex_conn.replication_consistency_group.get = MagicMock(
+ return_value=MockReplicationConsistencyGroupApi.get_rcg_details())
+ replication_consistency_group_module_mock.powerflex_conn.protection_domain.get = MagicMock(return_value=[{"name": "pd_id"}])
+ replication_consistency_group_module_mock.perform_module_operation()
+ assert "Specify pause as True to pause replication consistency group" in \
+ replication_consistency_group_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_pair.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_pair.py
new file mode 100644
index 000000000..81787de8f
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_replication_pair.py
@@ -0,0 +1,237 @@
+# Copyright: (c) 2023, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for replication pair module on PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+from unittest.mock import Mock
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_replication_pair_api import MockReplicationPairApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.replication_pair import PowerFlexReplicationPair
+
+
+class TestPowerflexReplicationPair():
+
+ get_module_args = MockReplicationPairApi.REPLICATION_PAIR_COMMON_ARGS
+
+ @pytest.fixture
+ def replication_pair_module_mock(self):
+ replication_pair_module_mock = PowerFlexReplicationPair()
+ replication_pair_module_mock.get_rcg = MagicMock(return_value={"id": 123})
+ replication_pair_module_mock.module.check_mode = False
+ return replication_pair_module_mock
+
+ def test_get_pair_details(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "pair_name": "test_pair",
+ "pairs": None,
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_resp = MockReplicationPairApi.get_pair_details()
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=replication_pair_resp
+ )
+ replication_pair_module_mock.perform_module_operation()
+ replication_pair_module_mock.powerflex_conn.replication_pair.get.assert_called()
+
+ def test_get_pair_details_with_exception(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "pair_name": "test_pair",
+ "pairs": None,
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ side_effect=MockApiException)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Failed to get the replication pair" in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_pairs(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": [{"source_volume_id": "123", "target_volume_id": "345", "source_volume_name": None,
+ "target_volume_name": None, "copy_type": "OnlineCopy", "name": "test_pair"}],
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_resp = MockReplicationPairApi.get_pair_details()
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=replication_pair_resp
+ )
+ replication_pair_module_mock.perform_module_operation()
+ replication_pair_module_mock.powerflex_conn.replication_pair.add.assert_called()
+
+ def test_create_pairs_with_volume_name(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": [{"source_volume_name": "src_vol", "target_volume_name": "dest_vol", "source_volume_id": None,
+ "target_volume_id": None, "copy_type": "OnlineCopy", "name": "test_pair"}],
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.volume.get = MagicMock(
+ return_value=MockReplicationPairApi.get_volume_details()
+ )
+ replication_pair_module_mock.perform_module_operation()
+ replication_pair_module_mock.powerflex_conn.replication_pair.add.assert_called()
+
+ def test_create_pairs_exception(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": [{"source_volume_id": "123", "target_volume_id": "345", "source_volume_name": None,
+ "target_volume_name": None, "copy_type": "OnlineCopy", "name": "test_pair"}],
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_resp = MockReplicationPairApi.get_pair_details()
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=replication_pair_resp
+ )
+ replication_pair_module_mock.powerflex_conn.replication_pair.add = MagicMock(
+ side_effect=MockApiException
+ )
+ replication_pair_module_mock.perform_module_operation()
+ assert "Create replication pairs failed with error" \
+ in replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_pause_replication_pair(self, replication_pair_module_mock):
+ self.get_module_args.update({"pair_name": "test_pair", "pause": True, "state": "present"})
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details("Uninitialized")
+ )
+ replication_pair_module_mock.perform_module_operation()
+ replication_pair_module_mock.powerflex_conn.replication_pair.pause.assert_called()
+
+ def test_pause_rcg_throws_exception(self, replication_pair_module_mock):
+ self.get_module_args.update({"pair_id": MockReplicationPairApi.PAIR_ID, "pause": True, "state": "present"})
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details("Uninitialized"))
+ replication_pair_module_mock.powerflex_conn.replication_pair.pause = \
+ MagicMock(side_effect=MockApiException)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Pause replication pair " + MockReplicationPairApi.PAIR_ID \
+ + MockReplicationPairApi.FAIL_MSG in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_resume_replication_pair(self, replication_pair_module_mock):
+ self.get_module_args.update({"pair_name": "test_pair", "pause": False, "state": "present"})
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details("Paused")
+ )
+ replication_pair_module_mock.perform_module_operation()
+ replication_pair_module_mock.powerflex_conn.replication_pair.resume.assert_called()
+
+ def test_resume_rcg_throws_exception(self, replication_pair_module_mock):
+ self.get_module_args.update({"pair_id": MockReplicationPairApi.PAIR_ID, "pause": False, "state": "present"})
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details("Paused"))
+ replication_pair_module_mock.powerflex_conn.replication_pair.resume = \
+ MagicMock(side_effect=MockApiException)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Resume replication pair " + MockReplicationPairApi.PAIR_ID \
+ + MockReplicationPairApi.FAIL_MSG in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_delete_replication_pair(self, replication_pair_module_mock):
+ self.get_module_args.update({"pair_name": "test_pair", "pairs": None, "state": "absent"})
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details()
+ )
+ replication_pair_module_mock.perform_module_operation()
+ replication_pair_module_mock.powerflex_conn.replication_pair.remove.assert_called()
+
+ def test_delete_replication_pair_throws_exception(self, replication_pair_module_mock):
+ self.get_module_args.update({"pair_id": MockReplicationPairApi.PAIR_ID, "pairs": None, "state": "absent"})
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details())
+ replication_pair_module_mock.powerflex_conn.replication_pair.remove = \
+ MagicMock(side_effect=MockApiException)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Delete replication pair " + MockReplicationPairApi.PAIR_ID \
+ + MockReplicationPairApi.FAIL_MSG in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_replication_pair_src_validation(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": [{"source_volume_id": "123", "target_volume_id": "345", "source_volume_name": "abc",
+ "target_volume_name": None, "copy_type": "OnlineCopy", "name": "test_pair"}],
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details())
+ replication_pair_module_mock.create_replication_pairs = MagicMock(return_value=None)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Specify either source_volume_id or source_volume_name" in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_replication_pair_target_validation(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": [{"source_volume_id": "123", "target_volume_id": "345", "source_volume_name": None,
+ "target_volume_name": "abc", "copy_type": "OnlineCopy", "name": "test_pair"}],
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details())
+ replication_pair_module_mock.create_replication_pairs = MagicMock(return_value=None)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Specify either target_volume_id or target_volume_name" in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_replication_pair_pause_validation(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": None, "pause": True,
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details())
+ replication_pair_module_mock.perform_pause_or_resume = MagicMock()
+ replication_pair_module_mock.perform_module_operation()
+ assert "Specify a valid pair_name or pair_id to perform pause or resume" in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_rcg_replication_pairs_throws_exception(self, replication_pair_module_mock):
+ self.get_module_args.update({
+ "rcg_name": "test_rcg",
+ "pairs": [{"source_volume_id": "123", "target_volume_id": "345", "source_volume_name": None,
+ "target_volume_name": None, "copy_type": "OnlineCopy", "name": "test_pair"}],
+ "state": "present"
+ })
+ replication_pair_module_mock.module.params = self.get_module_args
+ replication_pair_module_mock.powerflex_conn.replication_pair.get = MagicMock(
+ return_value=MockReplicationPairApi.get_pair_details())
+ replication_pair_module_mock.powerflex_conn.replication_consistency_group.get_replication_pairs = MagicMock(
+ side_effect=MockApiException)
+ replication_pair_module_mock.create_replication_pairs = MagicMock(return_value=None)
+ replication_pair_module_mock.perform_module_operation()
+ assert "Failed to get the replication pairs for replication consistency group" in \
+ replication_pair_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_storagepool.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_storagepool.py
new file mode 100644
index 000000000..a2c463f66
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_storagepool.py
@@ -0,0 +1,72 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for storage pool module on PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_storagepool_api import MockStoragePoolApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKResponse
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.storagepool import PowerFlexStoragePool
+
+
+class TestPowerflexStoragePool():
+
+ get_module_args = MockStoragePoolApi.STORAGE_POOL_COMMON_ARGS
+
+ @pytest.fixture
+ def storagepool_module_mock(self, mocker):
+ storagepool_module_mock = PowerFlexStoragePool()
+ storagepool_module_mock.module.check_mode = False
+ return storagepool_module_mock
+
+ def test_get_storagepool_details(self, storagepool_module_mock):
+ self.get_module_args.update({
+ "storage_pool_name": "test_pool",
+ "state": "present"
+ })
+ storagepool_module_mock.module.params = self.get_module_args
+ storagepool_resp = MockStoragePoolApi.STORAGE_POOL_GET_LIST
+ storagepool_module_mock.powerflex_conn.storage_pool.get = MagicMock(
+ return_value=storagepool_resp
+ )
+ storagepool_statistics_resp = MockStoragePoolApi.STORAGE_POOL_STATISTICS
+ storagepool_module_mock.powerflex_conn.storage_pool.get_statistics = MagicMock(
+ return_value=storagepool_statistics_resp
+ )
+ storagepool_module_mock.perform_module_operation()
+ storagepool_module_mock.powerflex_conn.storage_pool.get.assert_called()
+ storagepool_module_mock.powerflex_conn.storage_pool.get_statistics.assert_called()
+
+ def test_get_storagepool_details_with_exception(self, storagepool_module_mock):
+ self.get_module_args.update({
+ "storage_pool_name": "test_pool"
+ })
+ storagepool_module_mock.module.params = self.get_module_args
+ storagepool_resp = MockStoragePoolApi.STORAGE_POOL_GET_LIST
+ storagepool_module_mock.powerflex_conn.storage_pool.get = MagicMock(
+ return_value=storagepool_resp
+ )
+ storagepool_module_mock.powerflex_conn.storage_pool.get_statistics = MagicMock(
+ side_effect=MockApiException
+ )
+ storagepool_module_mock.create_storage_pool = MagicMock(return_value=None)
+ storagepool_module_mock.perform_module_operation()
+ assert MockStoragePoolApi.get_exception_response('get_details') in storagepool_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_volume.py b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_volume.py
new file mode 100644
index 000000000..53cdcfc0d
--- /dev/null
+++ b/ansible_collections/dellemc/powerflex/tests/unit/plugins/modules/test_volume.py
@@ -0,0 +1,81 @@
+# Copyright: (c) 2022, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+"""Unit Tests for volume module on PowerFlex"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_volume_api import MockVolumeApi
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKResponse
+from ansible_collections.dellemc.powerflex.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_powerflex_gateway_host_connection = MagicMock()
+utils.PowerFlexClient = MagicMock()
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.powerflex.plugins.modules.volume import PowerFlexVolume
+
+
+class TestPowerflexVolume():
+
+ get_module_args = MockVolumeApi.VOLUME_COMMON_ARGS
+
+ @pytest.fixture
+ def volume_module_mock(self, mocker):
+ volume_module_mock = PowerFlexVolume()
+ volume_module_mock.module.check_mode = False
+ return volume_module_mock
+
+ def test_get_volume_details(self, volume_module_mock):
+ self.get_module_args.update({
+ "vol_name": "testing",
+ "state": "present"
+ })
+ volume_module_mock.module.params = self.get_module_args
+ volume_resp = MockVolumeApi.VOLUME_GET_LIST
+ volume_module_mock.powerflex_conn.volume.get = MagicMock(
+ return_value=volume_resp
+ )
+ volume_sp_resp = MockVolumeApi.VOLUME_STORAGEPOOL_DETAILS
+ volume_module_mock.get_storage_pool = MagicMock(
+ return_value=volume_sp_resp
+ )
+ volume_pd_resp = MockVolumeApi.VOLUME_PD_DETAILS
+ volume_module_mock.get_protection_domain = MagicMock(
+ return_value=volume_pd_resp
+ )
+ volume_statistics_resp = MockVolumeApi.VOLUME_STATISTICS
+ volume_module_mock.powerflex_conn.volume.get_statistics = MagicMock(
+ return_value=volume_statistics_resp
+ )
+ volume_module_mock.perform_module_operation()
+ volume_module_mock.powerflex_conn.volume.get.assert_called()
+ volume_module_mock.powerflex_conn.volume.get_statistics.assert_called()
+
+ def test_get_volume_details_with_exception(self, volume_module_mock):
+ self.get_module_args.update({
+ "vol_name": "testing",
+ "state": "present"
+ })
+ volume_module_mock.module.params = self.get_module_args
+ volume_resp = MockVolumeApi.VOLUME_GET_LIST
+ volume_module_mock.powerflex_conn.volume.get = MagicMock(
+ return_value=volume_resp
+ )
+ volume_module_mock.powerflex_conn.volume.get_statistics = MagicMock(
+ side_effect=MockApiException
+ )
+ volume_module_mock.create_volume = MagicMock(return_value=None)
+ volume_module_mock.perform_module_operation()
+ assert MockVolumeApi.get_exception_response('get_details') in volume_module_mock.module.fail_json.call_args[1]['msg']