summaryrefslogtreecommitdiffstats
path: root/ansible_collections/dellemc/unity/tests
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/dellemc/unity/tests')
-rw-r--r--ansible_collections/dellemc/unity/tests/requirements.txt7
-rw-r--r--ansible_collections/dellemc/unity/tests/sanity/ignore-2.12.txt33
-rw-r--r--ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt27
-rw-r--r--ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt27
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py19
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py200
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py122
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_api.py68
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py154
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py122
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py64
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py187
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py259
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py32
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py168
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py174
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py169
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py193
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py94
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py143
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py350
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py112
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py183
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py225
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py132
-rw-r--r--ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py128
26 files changed, 3392 insertions, 0 deletions
diff --git a/ansible_collections/dellemc/unity/tests/requirements.txt b/ansible_collections/dellemc/unity/tests/requirements.txt
new file mode 100644
index 000000000..3541acd15
--- /dev/null
+++ b/ansible_collections/dellemc/unity/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/unity/tests/sanity/ignore-2.12.txt b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.12.txt
new file mode 100644
index 000000000..f78c82922
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.12.txt
@@ -0,0 +1,33 @@
+plugins/modules/nfs.py compile-2.6
+plugins/modules/nfs.py import-2.6
+plugins/modules/consistencygroup.py validate-modules:missing-gplv3-license
+plugins/modules/filesystem.py validate-modules:missing-gplv3-license
+plugins/modules/filesystem_snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/info.py validate-modules:missing-gplv3-license
+plugins/modules/host.py validate-modules:missing-gplv3-license
+plugins/modules/nasserver.py validate-modules:missing-gplv3-license
+plugins/modules/nfs.py validate-modules:missing-gplv3-license
+plugins/modules/smbshare.py validate-modules:missing-gplv3-license
+plugins/modules/snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/snapshotschedule.py validate-modules:missing-gplv3-license
+plugins/modules/storagepool.py validate-modules:missing-gplv3-license
+plugins/modules/tree_quota.py validate-modules:missing-gplv3-license
+plugins/modules/user_quota.py validate-modules:missing-gplv3-license
+plugins/modules/volume.py validate-modules:missing-gplv3-license
+plugins/modules/cifsserver.py validate-modules:missing-gplv3-license
+plugins/modules/nfsserver.py validate-modules:missing-gplv3-license
+plugins/modules/host.py import-2.6
+plugins/modules/host.py import-2.7
+plugins/modules/interface.py import-2.6
+plugins/modules/interface.py import-2.7
+plugins/modules/nfs.py import-2.7
+plugins/modules/nfs.py import-3.5
+plugins/modules/nfs.py compile-2.7
+plugins/modules/nfs.py compile-3.5
+plugins/modules/filesystem.py import-2.6
+plugins/modules/filesystem.py compile-2.6
+plugins/modules/filesystem.py compile-2.7
+plugins/modules/filesystem.py compile-3.5
+plugins/modules/filesystem.py import-2.7
+plugins/modules/filesystem.py import-3.5
+plugins/modules/interface.py validate-modules:missing-gplv3-license \ No newline at end of file
diff --git a/ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt
new file mode 100644
index 000000000..a175e9976
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt
@@ -0,0 +1,27 @@
+plugins/modules/consistencygroup.py validate-modules:missing-gplv3-license
+plugins/modules/filesystem.py validate-modules:missing-gplv3-license
+plugins/modules/filesystem_snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/info.py validate-modules:missing-gplv3-license
+plugins/modules/host.py validate-modules:missing-gplv3-license
+plugins/modules/nasserver.py validate-modules:missing-gplv3-license
+plugins/modules/nfs.py validate-modules:missing-gplv3-license
+plugins/modules/smbshare.py validate-modules:missing-gplv3-license
+plugins/modules/snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/snapshotschedule.py validate-modules:missing-gplv3-license
+plugins/modules/storagepool.py validate-modules:missing-gplv3-license
+plugins/modules/tree_quota.py validate-modules:missing-gplv3-license
+plugins/modules/user_quota.py validate-modules:missing-gplv3-license
+plugins/modules/volume.py validate-modules:missing-gplv3-license
+plugins/modules/cifsserver.py validate-modules:missing-gplv3-license
+plugins/modules/nfsserver.py validate-modules:missing-gplv3-license
+plugins/modules/host.py import-2.7
+plugins/modules/interface.py import-2.7
+plugins/modules/nfs.py import-2.7
+plugins/modules/nfs.py import-3.5
+plugins/modules/nfs.py compile-2.7
+plugins/modules/nfs.py compile-3.5
+plugins/modules/filesystem.py compile-2.7
+plugins/modules/filesystem.py compile-3.5
+plugins/modules/filesystem.py import-2.7
+plugins/modules/filesystem.py import-3.5
+plugins/modules/interface.py validate-modules:missing-gplv3-license
diff --git a/ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt
new file mode 100644
index 000000000..a175e9976
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt
@@ -0,0 +1,27 @@
+plugins/modules/consistencygroup.py validate-modules:missing-gplv3-license
+plugins/modules/filesystem.py validate-modules:missing-gplv3-license
+plugins/modules/filesystem_snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/info.py validate-modules:missing-gplv3-license
+plugins/modules/host.py validate-modules:missing-gplv3-license
+plugins/modules/nasserver.py validate-modules:missing-gplv3-license
+plugins/modules/nfs.py validate-modules:missing-gplv3-license
+plugins/modules/smbshare.py validate-modules:missing-gplv3-license
+plugins/modules/snapshot.py validate-modules:missing-gplv3-license
+plugins/modules/snapshotschedule.py validate-modules:missing-gplv3-license
+plugins/modules/storagepool.py validate-modules:missing-gplv3-license
+plugins/modules/tree_quota.py validate-modules:missing-gplv3-license
+plugins/modules/user_quota.py validate-modules:missing-gplv3-license
+plugins/modules/volume.py validate-modules:missing-gplv3-license
+plugins/modules/cifsserver.py validate-modules:missing-gplv3-license
+plugins/modules/nfsserver.py validate-modules:missing-gplv3-license
+plugins/modules/host.py import-2.7
+plugins/modules/interface.py import-2.7
+plugins/modules/nfs.py import-2.7
+plugins/modules/nfs.py import-3.5
+plugins/modules/nfs.py compile-2.7
+plugins/modules/nfs.py compile-3.5
+plugins/modules/filesystem.py compile-2.7
+plugins/modules/filesystem.py compile-3.5
+plugins/modules/filesystem.py import-2.7
+plugins/modules/filesystem.py import-3.5
+plugins/modules/interface.py validate-modules:missing-gplv3-license
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py
new file mode 100644
index 000000000..4ddee9661
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py
@@ -0,0 +1,19 @@
+# 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 Unity Test modules"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockApiException(Exception):
+ body = "SDK Error message"
+ status = "500"
+
+
+class HttpError(Exception):
+ body = "Http Error message"
+ http_status = 401
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py
new file mode 100644
index 000000000..427d530fa
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py
@@ -0,0 +1,200 @@
+# 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 CIFS server module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+from unittest.mock import MagicMock
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+
+
+class MockCIFSServerApi:
+ CIFS_SERVER_MODULE_ARGS = {
+ 'nas_server_id': None,
+ 'nas_server_name': None,
+ 'netbios_name': None,
+ 'workgroup': None,
+ 'local_password': None,
+ 'domain': None,
+ 'domain_username': None,
+ 'domain_password': None,
+ 'cifs_server_id': None,
+ 'cifs_server_name': None,
+ 'interfaces': None,
+ 'unjoin_cifs_server_account': None,
+ 'state': None
+ }
+
+ @staticmethod
+ def get_cifs_server_details_method_response():
+ return {
+ "description": None,
+ "domain": "xxx.xxx.xxx.xxx",
+ "existed": True,
+ "file_interfaces": {
+ "UnityFileInterfaceList": [
+ {
+ "UnityFileInterface": {
+ "hash": 8791477905949,
+ "id": "if_43"
+ }
+ }
+ ]
+ },
+ "hash": 8791478461637,
+ "health": {
+ "UnityHealth": {
+ "hash": 8791478461623
+ }
+ },
+ "id": "cifs_59",
+ "is_standalone": False,
+ "last_used_organizational_unit": "ou=Computers,ou=EMC NAS servers",
+ "name": "test_cifs_server",
+ "nas_server": {
+ "UnityNasServer": {
+ "hash": 8791478461595,
+ "id": "nas_18"
+ }
+ },
+ "netbios_name": "TEST_CIFS_SERVER",
+ "smb_multi_channel_supported": True,
+ "smb_protocol_versions": [
+ "1.0",
+ "2.0",
+ "2.1",
+ "3.0"
+ ],
+ "smbca_supported": True,
+ "workgroup": None
+ }
+
+ @staticmethod
+ def get_cifs_server_details_method_netbios_response():
+ return {
+ "UnityCifsServerList": [{
+ "UnityCifsServer": {
+ "existed": True,
+ "file_interfaces": {
+ "UnityFileInterfaceList": [{
+ "UnityFileInterface": {
+ "hash": -9223363293222387298,
+ "id": "if_43"
+ }
+ }]
+ },
+ "hash": 8743632213638,
+ "health": {
+ "UnityHealth": {
+ "hash": -9223363293222562209
+ }
+ },
+ "id": "cifs_60",
+ "is_standalone": True,
+ "nas_server": {
+ "UnityNasServer": {
+ "hash": -9223363293221242245,
+ "id": "nas_18"
+ }
+ },
+ "netbios_name": "ANSIBLE_CIFS",
+ "smb_multi_channel_supported": True,
+ "smb_protocol_versions": ["1.0", "2.0", "2.1", "3.0"],
+ "smbca_supported": True,
+ "workgroup": "ANSIBLE"
+ }
+ }]
+ }
+
+ @staticmethod
+ def create_cifs_server_without_nas():
+ return "Please provide nas server id/name to create CIFS server."
+
+ @staticmethod
+ def invalid_credentials():
+ return "Incorrect username or password provided."
+
+ @staticmethod
+ def modify_error_msg():
+ return "Modification is not supported through Ansible module"
+
+ @staticmethod
+ def get_nas_server_details():
+ return {
+ "UnityNasServer": {
+ "cifs_server": {
+ "UnityCifsServerList": [{
+ "UnityCifsServer": {
+ "hash": 8734183189936,
+ "id": "cifs_60"
+ }
+ }]
+ },
+ "current_sp": {
+ "UnityStorageProcessor": {
+ "hash": 8734188780762,
+ "id": "spa"
+ }
+ },
+ "current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NONE",
+ "existed": True,
+ "file_dns_server": {
+ "UnityFileDnsServer": {
+ "hash": 8734183189782,
+ "id": "dns_11"
+ }
+ },
+ "file_interface": {
+ "UnityFileInterfaceList": [{
+ "UnityFileInterface": {
+ "hash": -9223363302671584431,
+ "id": "if_43"
+ }
+ }]
+ },
+ "hash": -9223363302671053452,
+ "health": {
+ "UnityHealth": {
+ "hash": 8734182402245
+ }
+ },
+ "home_sp": {
+ "UnityStorageProcessor": {
+ "hash": -9223363302671594510,
+ "id": "spa"
+ }
+ },
+ "id": "nas_18",
+ "is_backup_only": False,
+ "is_multi_protocol_enabled": False,
+ "is_packet_reflect_enabled": False,
+ "is_replication_destination": False,
+ "is_replication_enabled": False,
+ "name": "test_nas1",
+ "pool": {
+ "UnityPool": {
+ "hash": -9223363302672128291,
+ "id": "pool_7"
+ }
+ },
+ "preferred_interface_settings": {
+ "UnityPreferredInterfaceSettings": {
+ "hash": -9223363302671585904,
+ "id": "preferred_if_16"
+ }
+ },
+ "replication_type": "ReplicationTypeEnum.NONE",
+ "size_allocated": 2952790016,
+ "virus_checker": {
+ "UnityVirusChecker": {
+ "hash": 8734183191465,
+ "id": "cava_18"
+ }
+ }
+ }
+ }
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py
new file mode 100644
index 000000000..07fe6b5d7
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py
@@ -0,0 +1,122 @@
+# 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 consistency group module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+from unittest.mock import MagicMock
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+
+
+class MockConsistenyGroupApi:
+ CONSISTENCY_GROUP_MODULE_ARGS = {
+ 'unispherehost': '**.***.**.***',
+ 'port': '123',
+ 'cg_id': None,
+ 'cg_name': None,
+ 'new_cg_name': None,
+ 'pool_id': None,
+ 'description': None,
+ 'snap_schedule': None,
+ 'tiering_policy': None,
+ 'volumes': [],
+ 'vol_state': None,
+ 'hosts': [],
+ 'mapping_state': None,
+ 'replication_params': {},
+ 'replication_state': None,
+ 'state': None
+ }
+ IP_ADDRESS_MOCK_VALUE = '***.***.***.**'
+
+ @staticmethod
+ def cg_get_details_method_response():
+ return {'advanced_dedup_status': 'DedupStatusEnum.DISABLED', 'block_host_access': None, 'data_reduction_percent': 0,
+ 'data_reduction_ratio': 1.0, 'data_reduction_size_saved': 0, 'data_reduction_status': 'DataReductionStatusEnum.DISABLED',
+ 'datastores': None, 'dedup_status': None, 'description': '', 'esx_filesystem_block_size': None,
+ 'esx_filesystem_major_version': None, 'filesystem': None, 'health': {}, 'host_v_vol_datastore': None,
+ 'id': 'cg_id_1', 'is_replication_destination': False, 'is_snap_schedule_paused': None,
+ 'luns': [{'id': 'lun_id_1', 'name': 'test_lun_cg_issue', 'is_thin_enabled': False,
+ 'size_total': 1, 'is_data_reduction_enabled': False}],
+ 'name': 'lun_test_cg_source_12', 'per_tier_size_used': [1, 0, 0],
+ 'pools': [{'id': 'pool_id_1'}],
+ 'relocation_policy': 'TieringPolicyEnum.AUTOTIER_HIGH', 'replication_type': 'ReplicationTypeEnum.NONE',
+ 'size_allocated': 0, 'size_total': 1, 'size_used': None, 'snap_count': 0, 'snap_schedule': None,
+ 'snaps_size_allocated': 0, 'snaps_size_total': 0, 'thin_status': 'ThinStatusEnum.TRUE',
+ 'type': 'StorageResourceTypeEnum.CONSISTENCY_GROUP', 'virtual_volumes': None, 'vmware_uuid': None,
+ 'existed': True, 'snapshots': [], 'cg_replication_enabled': False}
+
+ @staticmethod
+ def get_cg_object():
+ return MockSDKObject({'advanced_dedup_status': 'DedupStatusEnum.DISABLED', 'block_host_access': None,
+ 'data_reduction_percent': 0, 'data_reduction_ratio': 1.0, 'data_reduction_size_saved': 0,
+ 'data_reduction_status': 'DataReductionStatusEnum.DISABLED',
+ 'datastores': None, 'dedup_status': None, 'description': '', 'esx_filesystem_block_size': None,
+ 'esx_filesystem_major_version': None, 'filesystem': None, 'health': {}, 'host_v_vol_datastore': None,
+ 'id': 'cg_id_1', 'is_replication_destination': False, 'is_snap_schedule_paused': None,
+ 'luns': [MockSDKObject({'id': 'lun_id_1', 'name': 'test_lun_cg_issue',
+ 'is_thin_enabled': False, 'size_total': 1, 'is_data_reduction_enabled': False})],
+ 'name': 'lun_test_cg_source_12', 'per_tier_size_used': [1, 0, 0],
+ 'pools': [MockSDKObject({'id': 'pool_id_1'})],
+ 'relocation_policy': 'TieringPolicyEnum.AUTOTIER_HIGH', 'replication_type': 'ReplicationTypeEnum.NONE',
+ 'size_allocated': 0, 'size_total': 1, 'size_used': None, 'snap_count': 0, 'snap_schedule': None,
+ 'snaps_size_allocated': 0, 'snaps_size_total': 0, 'thin_status': 'ThinStatusEnum.TRUE',
+ 'type': 'StorageResourceTypeEnum.CONSISTENCY_GROUP', 'virtual_volumes': None, 'vmware_uuid': None,
+ 'existed': True, 'snapshots': [], 'cg_replication_enabled': False})
+
+ @staticmethod
+ def get_cg_replication_dependent_response(response_type):
+ if response_type == 'cg_replication_enabled_details':
+ cg_replication_enabled_details = MockConsistenyGroupApi.cg_get_details_method_response()
+ cg_replication_enabled_details['cg_replication_enabled'] = True
+ return cg_replication_enabled_details
+ elif response_type == 'remote_system':
+ return [MockSDKObject({"connection_type": "ReplicationCapabilityEnum.ASYNC", "existed": True,
+ "health": {"UnityHealth": {}}, "id": "system_id_1", "local_spa_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE],
+ "local_spb_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE],
+ "management_address": "**.***.**.**", "model": "U XXX",
+ "name": "ABXXXXXX", "remote_spa_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE],
+ "remote_spb_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE],
+ "serial_number": "ABXXXXXX", "sync_fc_ports": ["abc_def", "ghi_jkl"], "username": "username"})]
+ elif response_type == 'remote_system_pool_object':
+ return MockSDKObject({"alert_threshold": 60, "creation_time": "2021-10-18 12:51:27+00:00", "description": "",
+ "existed": True, "harvest_state": "UsageHarvestStateEnum.IDLE", "health": {"UnityHealth": {}},
+ "id": "pool_3", "is_all_flash": True, "is_empty": False, "is_fast_cache_enabled": False,
+ "is_harvest_enabled": True, "is_snap_harvest_enabled": True, "name": "Extreme_Perf_tier",
+ "object_id": 1, "pool_fast_vp": {"UnityPoolFastVp": {}}, "pool_space_harvest_high_threshold": 95.0,
+ "pool_space_harvest_low_threshold": 70.5, "pool_type": "StoragePoolTypeEnum.DYNAMIC",
+ "raid_type": "RaidTypeEnum.RAID5", "size_free": 1, "size_subscribed": 1, "size_total": 1,
+ "size_used": 1, "snap_size_subscribed": 1, "snap_size_used": 1, "snap_space_harvest_high_threshold": 20.5,
+ "snap_space_harvest_low_threshold": 1.0,
+ "tiers": {"UnityPoolTierList": [{"UnityPoolTier": {}}, {"UnityPoolTier": {}}, {"UnityPoolTier": {}}]}})
+ elif response_type == 'replication_session':
+ return MockSDKObject({"current_transfer_est_remain_time": 0, "daily_snap_replication_policy": {},
+ "dst_resource_id": "dest_id_1", "dst_status": "ReplicationSessionStatusEnum.OK", "existed": True,
+ "health": {}, "hourly_snap_replication_policy": {},
+ "id": "111111_XXX1111111_0000_1111111_XXX111111111_0000",
+ "last_sync_time": "2022-02-17 09: 50: 54+00: 00",
+ "local_role": "ReplicationSessionReplicationRoleEnum.LOOPBACK",
+ "max_time_out_of_sync": 60, "members": {}, "name": "rep_session_1",
+ "network_status": "ReplicationSessionNetworkStatusEnum.OK", "remote_system": {},
+ "replication_resource_type": "ReplicationEndpointResourceTypeEnum.CONSISTENCYGROUP",
+ "src_resource_id": "src_id_1",
+ "src_status": "ReplicationSessionStatusEnum.OK",
+ "status": "ReplicationOpStatusEnum.AUTO_SYNC_CONFIGURED",
+ "sync_progress": 0, "sync_state": "ReplicationSessionSyncStateEnum.IDLE"})
+ elif response_type == 'destination_cg_name_validation':
+ return 'destination_cg_name value should be in range of 1 to 95'
+ elif response_type == 'enable_cg_exception':
+ return 'Enabling replication to the consistency group lun_test_cg_source_12 failed with error '
+ elif response_type == 'disable_cg_exception':
+ return 'Disabling replication to the consistency group lun_test_cg_source_12 failed with error '
+
+ @staticmethod
+ def get_remote_system_conn_response():
+ conn = MockConsistenyGroupApi.get_cg_replication_dependent_response("remote_system")[0]
+ conn.get_pool = MagicMock(return_value=MockConsistenyGroupApi.get_cg_replication_dependent_response('remote_system_pool_object'))
+ return conn
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_api.py
new file mode 100644
index 000000000..d855815a2
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_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 FileSystem module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+
+
+class MockFileSystemApi:
+ @staticmethod
+ def get_file_system_response():
+ filesystem_response = {"UnityFileSystem": {
+ "access_policy": "AccessPolicyEnum.NATIVE",
+ "cifs_notify_on_change_dir_depth": 512,
+ "data_reduction_percent": 0,
+ "data_reduction_ratio": 1.0,
+ "data_reduction_size_saved": 0,
+ "description": "",
+ "existed": True,
+ "size_total": 5,
+ "folder_rename_policy": "FSRenamePolicyEnum.SMB_RENAME_FORBIDDEN",
+ "id": "fs_208",
+ "replication_type": "Remote"}}
+ filesystem_response['storage_resource'] = MockSDKObject({'replication_type': None})
+ return filesystem_response
+
+ @staticmethod
+ def get_replication_params(is_valid=True):
+ rpo = 60
+ if not is_valid:
+ rpo = 2
+ return {'replication_params': {
+ 'replication_name': None,
+ 'new_replication_name': None,
+ 'replication_mode': 'asynchronous',
+ 'replication_type': 'local',
+ 'rpo': rpo,
+ 'remote_system': None,
+ 'destination_pool_name': 'pool_test_name_1',
+ 'destination_pool_id': None},
+ 'replication_state': 'enable',
+ 'state': 'present'
+ }
+ else:
+ return {'replication_params': {
+ 'replication_name': None,
+ 'replication_mode': 'asynchronous',
+ 'new_replication_name': None,
+ 'replication_type': 'remote',
+ 'rpo': rpo,
+ 'remote_system': {
+ 'remote_system_host': '1.1.1.1',
+ 'remote_system_verifycert': False,
+ 'remote_system_username': 'username',
+ 'remote_system_password': 'password',
+ 'remote_system_port': 1
+ },
+ 'destination_pool_name': 'pool_test_name_1',
+ 'destination_pool_id': None},
+ 'replication_state': 'enable',
+ 'state': 'present'
+ }
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py
new file mode 100644
index 000000000..4e93b6285
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py
@@ -0,0 +1,154 @@
+# 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 host module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+
+
+class MockHostApi:
+ HOST_MODULE_ARGS = {
+ 'unispherehost': '**.***.**.***',
+ 'port': '123',
+ 'host_id': None,
+ 'host_name': None,
+ 'host_os': None,
+ 'description': None,
+ 'initiators': None,
+ 'initiator_state': None,
+ 'new_host_name': None,
+ 'network_address': None,
+ 'network_address_state': None,
+ 'state': None
+ }
+
+ IP_ADDRESS_MOCK_VALUE = '***.***.*.*'
+ IQN_INITIATOR_MOCK_VALUE = 'iqn.1111-11.com.vmware: host_name_1-111111f'
+
+ @staticmethod
+ def get_host_count_response():
+ return [{"auto_manage_type": "HostManageEnum.OTHERS", "description": "", "existed": True,
+ "fc_host_initiators": {"UnityHostInitiatorList": [{"UnityHostInitiator": {}}]}, "health":
+ {"UnityHealth": {}}, "host_ip_ports": {"UnityHostIpPortList": [{"UnityHostIpPort": {}},
+ {"UnityHostIpPort": {}}]}, "host_pushed_uuid": "1-1-1-1-1",
+ "id": "Host_id_1", "iscsi_host_initiators": {"UnityHostInitiatorList": [{"UnityHostInitiator": {}}]},
+ "name": "host_name_1", "os_type": "XXXXXXXX", "type": "HostTypeEnum.HOST_AUTO"}]
+
+ @staticmethod
+ def get_host_initiators_list():
+ return ['1:1:1:1:1:1:1:1:1', MockHostApi.IQN_INITIATOR_MOCK_VALUE]
+
+ @staticmethod
+ def get_host_details_response(response_type):
+ if response_type == 'api':
+ return {'auto_manage_type': 'HostManageEnum.OTHERS', 'datastores': None, 'description': '',
+ 'fc_host_initiators': [MockSDKObject({'chap_user_name': None,
+ 'health': {'UnityHealth': {}}, 'id': 'HostInitiator_fc_1',
+ 'initiator_id': '1:1:1:1:1:1:1:1:1',
+ 'initiator_source_type': 'HostInitiatorSourceTypeEnum.OPEN_NATIVE', 'is_bound': None,
+ 'is_chap_secret_enabled': False,
+ 'is_ignored': False, 'iscsi_type': None,
+ 'node_wwn': '11:12:13:14:**:**:**:**',
+ 'parent_host': {'UnityHost': {'id': 'Host_id_1'}},
+ 'paths': [MockSDKObject({'id': 'HostInitiator_mock_6', 'is_logged_in': True}),
+ MockSDKObject({'id': 'HostInitiator_mock_5', 'is_logged_in': True}),
+ MockSDKObject({'id': 'HostInitiator_mock_4', 'is_logged_in': True}),
+ MockSDKObject({'id': 'HostInitiator_mock_3', 'is_logged_in': True})],
+ 'port_wwn': '10:10:10:10:10:10:10:10:10', 'source_type': None,
+ 'type': 'HostInitiatorTypeEnum.FC', 'existed': True})],
+ 'host_container': None, 'host_ip_ports': [MockSDKObject({'address': MockHostApi.IP_ADDRESS_MOCK_VALUE,
+ 'host': None, 'id': 'HostNetworkAddress_1',
+ 'is_ignored': None, 'name': None, 'netmask': None, 'type': None,
+ 'v6_prefix_length': None, 'existed': True}),
+ MockSDKObject({'address': 'host_name_1', 'host': None, 'id': 'HostNetworkAddress_2',
+ 'is_ignored': None, 'name': None, 'netmask': None, 'type': None,
+ 'v6_prefix_length': None, 'existed': True})],
+ 'host_luns': MockSDKObject({'lun':
+ [MockSDKObject({'hlu': 1, 'host': None, 'id': 'host_a', 'name': 'host_name_a', 'is_read_only': None,
+ 'lun': {'UnityLun': {}}, 'snap': None, 'type': None, 'existed': True}),
+ MockSDKObject({'hlu': 0, 'host': None, 'id': 'host_b', 'name': 'host_name_b', 'is_read_only': None,
+ 'lun': {'UnityLun': {}}, 'snap': None, 'type': None, 'existed': True})]}),
+ 'host_polled_uuid': None, 'host_pushed_uuid': '1-1-1-1-1',
+ 'host_uuid': None, 'host_v_vol_datastore': None, 'id': 'Host_id_1',
+ 'iscsi_host_initiators': [MockSDKObject({'chap_user_name': None, 'health': {'UnityHealth': {}}, 'id': 'HostInitiator_iscsi_1',
+ 'initiator_id': MockHostApi.IQN_INITIATOR_MOCK_VALUE,
+ 'initiator_source_type': 'HostInitiatorSourceTypeEnum.OPEN_NATIVE', 'is_bound': True,
+ 'is_chap_secret_enabled': False, 'is_ignored': False,
+ 'iscsi_type': 'HostInitiatorIscsiTypeEnum.SOFTWARE', 'node_wwn': None,
+ 'parent_host': {'UnityHost': {'id': 'Host_id_1'}},
+ 'paths': [MockSDKObject({'id': 'HostInitiator_mock_1', 'is_logged_in': True}),
+ MockSDKObject({'id': 'HostInitiator_mock_2', 'is_logged_in': True})],
+ 'port_wwn': None, 'source_type': None, 'type': 'HostInitiatorTypeEnum.ISCSI',
+ 'existed': True})],
+ 'last_poll_time': None, 'name': 'host_name_1',
+ 'os_type': 'XXXXXXXX', 'registration_type': None, 'storage_resources': None, 'tenant': None,
+ 'type': 'HostTypeEnum.HOST_AUTO',
+ 'vms': None, 'existed': True, 'health': {'UnityHealth': {}}}
+ elif response_type == 'module':
+ return {'changed': False,
+ 'host_details': {'auto_manage_type': 'HostManageEnum.OTHERS', 'datastores': None, 'description': '',
+ 'fc_host_initiators': [{'id': 'HostInitiator_fc_1',
+ 'name': '1:1:1:1:1:1:1:1:1',
+ 'paths': [{'id': 'HostInitiator_mock_6',
+ 'is_logged_in': True},
+ {'id': 'HostInitiator_mock_5',
+ 'is_logged_in': True},
+ {'id': 'HostInitiator_mock_4',
+ 'is_logged_in': True},
+ {'id': 'HostInitiator_mock_3',
+ 'is_logged_in': True}]}],
+ 'health': {'UnityHealth': {}},
+ 'host_container': None,
+ 'host_luns': [{'id': "host_a", 'name': 'host_name_a'}, {'id': 'host_b', 'name': 'host_name_b'}],
+ 'host_polled_uuid': None, 'host_pushed_uuid': '1-1-1-1-1',
+ 'host_uuid': None, 'host_v_vol_datastore': None, 'id': 'Host_id_1',
+ 'iscsi_host_initiators': [{'id': 'HostInitiator_iscsi_1',
+ 'name': MockHostApi.IQN_INITIATOR_MOCK_VALUE,
+ 'paths': [{'id': 'HostInitiator_mock_1',
+ 'is_logged_in': True},
+ {'id': 'HostInitiator_mock_2',
+ 'is_logged_in': True}]}],
+ 'last_poll_time': None, 'name': 'host_name_1', 'os_type': 'XXXXXXXX',
+ 'registration_type': None, 'storage_resources': None, 'tenant': None,
+ 'type': 'HostTypeEnum.HOST_AUTO', 'vms': None, 'existed': True,
+ 'network_addresses': [MockHostApi.IP_ADDRESS_MOCK_VALUE, 'host_name_1']}}
+ elif response_type == 'error':
+ return "Incorrect username or password provided."
+
+ @staticmethod
+ def get_host_details_after_network_address_addition(response_type):
+ if response_type == 'api':
+ host_object = MockHostApi.get_host_details_response('api')
+ host_object['host_ip_ports'].append(MockSDKObject({'address': 'net_add_1', 'host': None, 'id': 'HostNetworkAddress_3',
+ 'is_ignored': None, 'name': None, 'netmask': None, 'type': None,
+ 'v6_prefix_length': None, 'existed': True}))
+ return host_object
+ elif response_type == 'module':
+ host_module_response = MockHostApi.get_host_details_response('module')
+ host_module_response['host_details']['network_addresses'].append('net_add_1')
+ host_module_response['changed'] = True
+ return host_module_response
+ elif response_type == 'invalid_address':
+ return 'Please enter valid IPV4 address or host name for network address'
+
+ @staticmethod
+ def get_host_details_after_network_address_removal(response_type):
+ if response_type == 'api':
+ host_object = MockHostApi.get_host_details_response('api')
+ host_object['host_ip_ports'] = [MockSDKObject({'address': MockHostApi.IP_ADDRESS_MOCK_VALUE, 'host': None, 'id': 'HostNetworkAddress_1',
+ 'is_ignored': None, 'name': None, 'netmask': None, 'type': None,
+ 'v6_prefix_length': None, 'existed': True})]
+ return host_object
+ elif response_type == 'module':
+ host_module_response = MockHostApi.get_host_details_response('module')
+ host_module_response['host_details']['network_addresses'].remove('host_name_1')
+ host_module_response['changed'] = True
+ return host_module_response
+ elif response_type == 'invalid_IPV4':
+ return 'Please enter valid IPV4 address for network address'
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py
new file mode 100644
index 000000000..6bd53ea9b
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py
@@ -0,0 +1,122 @@
+# 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 interface on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+from unittest.mock import MagicMock
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from copy import deepcopy
+
+
+class MockInterfaceApi:
+ INTERFACE_MODULE_ARGS = {
+ 'unispherehost': '**.***.**.***',
+ 'port': '123',
+ 'nas_server_id': None,
+ 'nas_server_name': None,
+ 'ethernet_port_name': None,
+ 'ethernet_port_id': None,
+ 'role': None,
+ 'interface_ip': None,
+ 'netmask': None,
+ 'prefix_length': None,
+ 'gateway': None,
+ 'vlan_id': None,
+ 'state': None
+ }
+ ETHERNET_PORT_NAME = "Card Ethernet Port"
+ NETMASK_DUMMY = "255.xx.xx.xx"
+ GATEWAY_DUMMY = "10.***.**.1"
+ INTERFACE_DUMMY = "10.***.**.**"
+
+ NAS_SERVER_OBJECT = \
+ MockSDKObject({'allow_unmapped_user': None, 'cifs_server': {'UnityCifsServerList': [{'UnityCifsServer': {'id': 'cifs_id_0'}}]},
+ 'current_sp': {'UnityStorageProcessor': {'id': 'abc'}},
+ 'current_unix_directory_service': 'NasServerUnixDirectoryServiceEnum.NIS', 'default_unix_user': None,
+ 'default_windows_user': None, 'file_dns_server': {'UnityFileDnsServer': {'id': 'dns_id_0'}},
+ 'file_interface': {'UnityFileInterfaceList': [{'UnityFileInterface': {'id': 'file_interface_id_0'}}]},
+ 'filesystems': {'UnityFileSystemList': [{'UnityFileSystem': {'id': 'fs_id_0'}}]},
+ 'home_sp': {'UnityStorageProcessor': {'id': 'abd'}},
+ 'id': 'nas_id_00', 'is_backup_only': False, 'is_multi_protocol_enabled': False,
+ 'is_packet_reflect_enabled': False, 'is_replication_destination': False,
+ 'is_replication_enabled': True, 'is_windows_to_unix_username_mapping_enabled': None,
+ 'name': 'dummy_nas', 'pool': {'UnityPool': {'id': 'pool_id_0'}},
+ 'preferred_interface_settings': {'UnityPreferredInterfaceSettings': {'id': 'preferred_interface_0'}},
+ 'replication_type': 'ReplicationTypeEnum.MIXED',
+ 'tenant': None, 'virus_checker': {'UnityVirusChecker': {'id': 'cava_id_0'}},
+ 'existed': True})
+
+ INTERFACE_OBJECT = \
+ MockSDKObject({"existed": True,
+ "gateway": GATEWAY_DUMMY,
+ "id": "file_interface_id_0",
+ "ip_address": INTERFACE_DUMMY,
+ "ip_port": {"UnityIpPort": {"id": "ethernet_port_id_0"}},
+ "ip_protocol_version": "IpProtocolVersionEnum.IPv4",
+ "is_disabled": False, "is_preferred": True,
+ "mac_address": "AA:AA:AA:**:**:**",
+ "name": "dummy_if_name",
+ "nas_server": {"UnityNasServer": {"id": "nas_id_00"}},
+ "netmask": NETMASK_DUMMY,
+ "role": "FileInterfaceRoleEnum.BACKUP",
+ "vlan_id": 324})
+
+ FILE_INTERFACE_ROLE_ENUM_DUMMY = {
+ 'PRODUCTION': (0, 'Production'),
+ 'BACKUP': (1, 'Backup')
+ }
+
+ @staticmethod
+ def get_nas_without_interface():
+ nas_object = deepcopy(MockInterfaceApi.NAS_SERVER_OBJECT)
+ nas_object.file_interface['UnityFileInterfaceList'] = []
+ return nas_object
+
+ @staticmethod
+ def get_nas_server_obj_existed_false():
+ nas_object = deepcopy(MockInterfaceApi.NAS_SERVER_OBJECT)
+ nas_object.existed = False
+ return nas_object
+
+ @staticmethod
+ def get_interface_exception_response(response_type):
+ if response_type == 'nas_server_id_exception':
+ return "Failed to get details of NAS server: dummy_nas with error: "
+ elif response_type == 'interface_exception':
+ return "Getting Interface details failed with error "
+ elif response_type == 'add_interface_exception':
+ return "Failed to add interface to NAS Server with error: "
+ elif response_type == 'delete_interface_exception':
+ return "Failed to delete interface with error: "
+
+ @staticmethod
+ def get_interface_error_response(response_type):
+ if response_type == 'invalid_ethernet_port_name':
+ return "Please provide valid value for: ethernet_port_name"
+ elif response_type == 'invalid_vlan_id':
+ return "vlan_id should be in the range of 3 to 4094"
+ elif response_type == 'invalid_interface_ip':
+ return 'The value for interface ip is invalid'
+ elif response_type == 'invalid_gateway':
+ return "The value for gateway is invalid"
+ elif response_type == 'invalid_netmask':
+ return 'Invalid IPV4 address specified for netmask'
+ elif response_type == 'modify_failure':
+ return "Modification of Interfaces for NAS server is not supported through Ansible module"
+ elif response_type == 'no_role':
+ return "Role is a mandatory parameter for adding interface to NAS Server."
+ elif response_type == 'no_ethernet':
+ return "ethernet_port_name/ethernet_port_id is mandatory parameter for adding interface to NAS Server."
+
+ @staticmethod
+ def get_nas_server_obj_errors(response_type):
+ if response_type == 'existed_false':
+ return "NAS server with id nas_id_00 does not exist"
+ elif response_type == 'exception':
+ return "Failed to get details of NAS server with error: "
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py
new file mode 100644
index 000000000..cb11e6d8e
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py
@@ -0,0 +1,64 @@
+# 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 NASServer module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockNASServerApi:
+ @staticmethod
+ def get_nas_server_response():
+ return ({"access_policy": "AccessPolicyEnum.NATIVE",
+ "cifs_notify_on_change_dir_depth": 512,
+ "data_reduction_percent": 0,
+ "data_reduction_ratio": 1.0,
+ "data_reduction_size_saved": 0,
+ "description": "",
+ "existed": True,
+ "size_total": 5,
+ "id": "nas0",
+ "name": "nas0",
+ "replication_type": "Remote"})
+
+ @staticmethod
+ def get_replication_params(is_valid=True):
+ rpo = 60
+ if not is_valid:
+ rpo = 2
+ return {'replication_params': {
+ 'replication_name': None,
+ 'new_replication_name': None,
+ 'replication_type': 'local',
+ 'replication_mode': 'asynchronous',
+ 'rpo': rpo,
+ 'remote_system': None,
+ 'destination_nas_server_name': None,
+ 'destination_pool_name': 'pool_test_name_1',
+ 'destination_pool_id': None},
+ 'replication_state': 'enable',
+ 'state': 'present'
+ }
+ else:
+ return {'replication_params': {
+ 'replication_name': None,
+ 'replication_mode': 'asynchronous',
+ 'new_replication_name': None,
+ 'replication_type': 'remote',
+ 'rpo': rpo,
+ 'remote_system': {
+ 'remote_system_host': '1.1.1.1',
+ 'remote_system_verifycert': False,
+ 'remote_system_username': 'username',
+ 'remote_system_password': 'password',
+ 'remote_system_port': 1
+ },
+ 'destination_nas_server_name': None,
+ 'destination_pool_name': 'pool_test_name_1',
+ 'destination_pool_id': None},
+ 'replication_state': 'enable',
+ 'state': 'present'
+ }
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py
new file mode 100644
index 000000000..bd933f7ce
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py
@@ -0,0 +1,187 @@
+# 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 nfs module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from mock.mock import MagicMock
+
+
+class MockNfsApi:
+ NFS_MODULE_ARGS = {
+ 'unispherehost': '**.***.**.***',
+ 'port': '123',
+ 'description': None,
+ 'anonymous_uid': None,
+ 'anonymous_gid': None,
+ 'min_security': None,
+ 'default_access': None,
+ 'nas_server_id': None,
+ 'nas_server_name': None,
+ 'nfs_export_id': None,
+ 'nfs_export_name': None,
+ 'snapshot_name': None,
+ 'snapshot_id': None,
+ 'filesystem_name': None,
+ 'filesystem_id': None,
+ 'host_state': None,
+ 'adv_host_mgmt_enabled': None,
+ 'no_access_hosts': None,
+ 'read_only_hosts': None,
+ 'read_only_root_hosts': None,
+ 'read_write_hosts': None,
+ 'read_write_root_hosts': None,
+ 'path': None,
+ 'state': None
+ }
+
+ DUMMY_DOMAIN_VALUE = "google.com"
+ DUMMY_SUBNET_VALUE = "**.***.2.2/10"
+
+ FILESYSTEM_OBJECT = MockSDKObject({"access_policy": "AccessPolicyEnum.UNIX", "cifs_notify_on_change_dir_depth": 512,
+ "data_reduction_percent": 0, "data_reduction_ratio": 1.0, "data_reduction_size_saved": 0,
+ "description": "", "existed": True,
+ "folder_rename_policy": "FSRenamePolicyEnum.SMB_RENAME_FORBIDDEN",
+ "format": "FSFormatEnum.UFS64", "host_io_size": "HostIOSizeEnum.GENERAL_16K",
+ "id": "fs_id_1", "is_advanced_dedup_enabled": False, "is_cifs_notify_on_access_enabled": False,
+ "is_cifs_notify_on_write_enabled": False, "is_cifs_op_locks_enabled": True,
+ "is_cifs_sync_writes_enabled": False, "is_data_reduction_enabled": False, "is_read_only": False,
+ "is_smbca": False, "is_thin_enabled": True, "locking_policy": "FSLockingPolicyEnum.MANDATORY",
+ "min_size_allocated": 0, "name": "fs_dummy_name", "nas_server": {"id": "nas_id_1"},
+ "nfs_share": [{"id": "NFSShare_id_1"}], "pool": {"id": "pool_id_1"},
+ "pool_full_policy": "ResourcePoolFullPolicyEnum.FAIL_WRITES", "snap_count": 0, "snaps_size": 0,
+ "snaps_size_allocated": 0, "storage_resource": {"id": "stg_id_1"},
+ "supported_protocols": "FSSupportedProtocolEnum.NFS",
+ "tiering_policy": "TieringPolicyEnum.AUTOTIER_HIGH",
+ "type": "FilesystemTypeEnum.FILESYSTEM"})
+
+ NFS_SHARE_OBJECT = MockSDKObject({"anonymous_gid": 4294967294, "anonymous_uid": 4294967294,
+ "default_access": "NFSShareDefaultAccessEnum.NO_ACCESS", "description": "", "existed": True,
+ "export_option": 1, "export_paths": ["**.***.**.**:/nfsshare_dummy_name"],
+ "filesystem": MockSDKObject({"id": "fs_id_1", "name": "fs_name1", "nas_server": "not_none"}),
+ "id": "NFSShare_id_1",
+ "min_security": "NFSShareSecurityEnum.SYS",
+ "modification_time": "2022-04-24 17:07:57.749000+00:00",
+ "name": "nfsshare_dummy_name",
+ "no_access_hosts": None,
+ "no_access_hosts_string": None,
+ "read_only_hosts": None,
+ "read_only_hosts_string": None,
+ "read_only_root_access_hosts": None,
+ "read_only_root_hosts_string": None,
+ "read_write_hosts": None,
+ "read_write_hosts_string": None,
+ "read_write_root_hosts_string": None,
+ "root_access_hosts": None,
+ "path": "/",
+ "role": "NFSShareRoleEnum.PRODUCTION",
+ "type": "NFSTypeEnum.NFS_SHARE"})
+
+ NFS_SHARE_DISPLAY_ATTR = {'anonymous_gid': 4294967294, 'anonymous_uid': 4294967294, 'creation_time': '2022-03-09 15:05:34.720000+00:00',
+ 'default_access': 'NFSShareDefaultAccessEnum.NO_ACCESS', 'description': '', 'export_option': 1,
+ 'export_paths': ['**.***.**.**:/nfsshare_dummy_name'],
+ 'filesystem': {'UnityFileSystem': {'id': 'fs_id_1', 'name': 'fs_name1'}}, 'host_accesses': None,
+ 'id': 'NFSShare_id_1', 'is_read_only': None, 'min_security': 'NFSShareSecurityEnum.SYS',
+ 'modification_time': '2022-04-24 17:07:57.749000+00:00', 'name': 'nfsshare_dummy_name',
+ 'nfs_owner_username': None, 'no_access_hosts': None,
+ 'no_access_hosts_string': None,
+ 'path': '/', 'read_only_hosts': None, 'read_only_hosts_string': '', 'read_only_root_access_hosts': None,
+ 'read_only_root_hosts_string': '', 'read_write_hosts': None, 'read_write_hosts_string': '',
+ 'read_write_root_hosts_string': '', 'role': 'NFSShareRoleEnum.PRODUCTION', 'root_access_hosts': None,
+ 'snap': None, 'type': 'NFSTypeEnum.NFS_SHARE', 'existed': True,
+ 'nas_server': {'UnityNasServer': {'id': 'nas_id_1', 'name': 'lglad068'}}}
+
+ @staticmethod
+ def get_nfs_share_object_on_host_access(action, advhostmgmt):
+ if advhostmgmt:
+ if action == 'add':
+ nfs_share_object = MockNfsApi.NFS_SHARE_OBJECT
+ return nfs_share_object
+ elif action == 'remove':
+ nfs_share_object = MockNfsApi.NFS_SHARE_OBJECT
+ nfs_share_object.no_access_hosts = {
+ 'UnityHostList': [
+ {
+ 'UnityHost': {
+ 'id': 'Host_1389'
+ }
+ },
+ {
+ 'UnityHost': {
+ 'id': 'Host_1330'
+ }
+ }
+ ]
+ }
+ return nfs_share_object
+ else:
+ if action == 'add':
+ nfs_share_display_attr = MockNfsApi.NFS_SHARE_OBJECT
+ nfs_share_display_attr.read_only_root_hosts_string = ''
+ return nfs_share_display_attr
+ elif action == 'remove':
+ nfs_share_display_attr = MockNfsApi.NFS_SHARE_OBJECT
+ nfs_share_display_attr.read_only_root_hosts_string = '*.google.com,**.***.0.0/255.***.*.*'
+ return nfs_share_display_attr
+
+ @staticmethod
+ def get_nfs_share_display_attr_on_host_access(action, advhostmgmt):
+ if advhostmgmt:
+ if action == 'add':
+ nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR
+ nfs_share_display_attr['no_access_hosts'] = {
+ 'UnityHostList': [
+ {
+ 'UnityHost': {
+ 'id': 'Host_1389'
+ }
+ },
+ {
+ 'UnityHost': {
+ 'id': 'Host_1330'
+ }
+ }
+ ]
+ }
+ return nfs_share_display_attr
+ elif action == 'remove':
+ nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR
+ nfs_share_display_attr['no_access_hosts'] = None
+ return nfs_share_display_attr
+ else:
+ if action == 'add':
+ nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR
+ nfs_share_display_attr['read_only_root_hosts_string'] = '*.google.com,**.***.0.0/255.***.*.*'
+ return nfs_share_display_attr
+ elif action == 'remove':
+ nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR
+ nfs_share_display_attr['read_only_root_hosts_string'] = ''
+ return nfs_share_display_attr
+
+ @staticmethod
+ def get_host_obj(id):
+ if id == 1:
+ host_1 = MagicMock()
+ host_1.id = 'Host_1389'
+ host_1.name = 'host_1'
+ return host_1
+ elif id == 2:
+ host_2 = MagicMock()
+ host_2.id = 'Host_1330'
+ host_2.name = 'host_2'
+ return host_2
+
+ @staticmethod
+ def host_access_negative_response(response_type):
+ if response_type == 'subnet_validation':
+ return "Subnet should be in format 'IP address/netmask' or 'IP address/prefix length'"
+ elif response_type == 'advhostmngmnt_field_validation':
+ return "'host_state' and 'adv_host_mgmt_enabled' is required along with: read_only_root_hosts"
+ elif response_type == 'modify_exception':
+ return 'Failed to modify nfs error: '
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py
new file mode 100644
index 000000000..1254f0035
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py
@@ -0,0 +1,259 @@
+# 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 NFS server module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+from unittest.mock import MagicMock
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+
+
+class MockNFSServerApi:
+ NFS_SERVER_MODULE_ARGS = {
+ 'nas_server_id': None,
+ 'nas_server_name': None,
+ 'host_name': None,
+ 'is_secure_enabled': None,
+ 'kerberos_domain_controller_type': None,
+ 'kerberos_domain_controller_username': None,
+ 'kerberos_domain_controller_password': None,
+ 'is_extended_credentials_enabled': None,
+ 'nfs_v4_enabled': None,
+ 'nfs_server_id': None,
+ 'interfaces': None,
+ 'remove_spn_from_kerberos': None,
+ 'state': None
+ }
+
+ NAS_SERVER_OBJ = MockSDKObject({"id": "nas_10"})
+
+ @staticmethod
+ def get_nfs_server_details_method_response():
+ return {
+ "credentials_cache_ttl": "0:15:00",
+ "existed": True,
+ "file_interfaces": {
+ "UnityFileInterfaceList": [{
+ "UnityFileInterface": {
+ "hash": 1111111111111,
+ "id": "if_3"
+ }
+ }]
+ },
+ "hash": 1111111111111,
+ "id": "nfs_95",
+ "is_extended_credentials_enabled": False,
+ "is_secure_enabled": False,
+ "nas_server": MockNFSServerApi.NAS_SERVER_OBJ,
+ "nfs_v4_enabled": True,
+ 'servicee_principal_name': None
+ }
+
+ @staticmethod
+ def get_nfs_server_details():
+ return [MockSDKObject({
+ "credentials_cache_ttl": "0:15:00",
+ "existed": True,
+ "file_interfaces": {
+ "UnityFileInterfaceList": [{
+ "UnityFileInterface": {
+ "hash": 1111111111111,
+ "id": "if_3"
+ }
+ }]
+ },
+ "hash": 1111111111111,
+ "id": "nfs_95",
+ "is_extended_credentials_enabled": False,
+ "is_secure_enabled": False,
+ "nas_server": MockNFSServerApi.NAS_SERVER_OBJ,
+ "nfs_v4_enabled": True,
+ 'servicee_principal_name': None})]
+
+ @staticmethod
+ def validate_params_exception():
+ return "Please provide valid value for:"
+
+ @staticmethod
+ def create_nfs_server_without_nas_server_id():
+ return "Please provide nas server id/name to create NFS server."
+
+ @staticmethod
+ def get_nas_server_id_api_exception():
+ return "Failed to get details of NAS server:"
+
+ @staticmethod
+ def create_nfs_server_without_is_secure_enabled():
+ return "For create NFS Server nfs_v4_enabled and is_secure_enabled should be true."
+
+ @staticmethod
+ def create_nfs_server_with_api_exception():
+ return "Failed to create NFS server with on NAS Server"
+
+ @staticmethod
+ def get_nfs_server_api_exception():
+ return "Incorrect username or password provided."
+
+ @staticmethod
+ def get_nfs_server_api_exception_1():
+ return "Failed to get details of NFS Server with error"
+
+ @staticmethod
+ def delete_exception():
+ return "Failed to delete NFS server:"
+
+ @staticmethod
+ def modify_error_msg():
+ return "Modification of NFS Server parameters is not supported through Ansible module"
+
+ @staticmethod
+ def get_nas_server_details():
+ return {
+ "UnityNasServer": {
+ "cifs_server": {
+ "UnityCifsServerList": [{
+ "UnityCifsServer": {
+ "hash": 1111111111111,
+ "id": "cifs_60"
+ }
+ }]
+ },
+ "current_sp": {
+ "UnityStorageProcessor": {
+ "hash": 1111111111111,
+ "id": "spa"
+ }
+ },
+ "current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NONE",
+ "existed": True,
+ "file_dns_server": {
+ "UnityFileDnsServer": {
+ "hash": 1111111111111,
+ "id": "dns_11"
+ }
+ },
+ "file_interface": {
+ "UnityFileInterfaceList": [{
+ "UnityFileInterface": {
+ "hash": -1111111111111,
+ "id": "if_43"
+ }
+ }]
+ },
+ "hash": -1111111111111,
+ "health": {
+ "UnityHealth": {
+ "hash": 1111111111111
+ }
+ },
+ "home_sp": {
+ "UnityStorageProcessor": {
+ "hash": -1111111111111,
+ "id": "spa"
+ }
+ },
+ "id": "nas_18",
+ "is_backup_only": False,
+ "is_multi_protocol_enabled": False,
+ "is_packet_reflect_enabled": False,
+ "is_replication_destination": False,
+ "is_replication_enabled": False,
+ "name": "test_nas1",
+ "pool": {
+ "UnityPool": {
+ "hash": -1111111111111,
+ "id": "pool_7"
+ }
+ },
+ "preferred_interface_settings": {
+ "UnityPreferredInterfaceSettings": {
+ "hash": -1111111111111,
+ "id": "preferred_if_16"
+ }
+ },
+ "replication_type": "ReplicationTypeEnum.NONE",
+ "size_allocated": 1111111111111,
+ "virus_checker": {
+ "UnityVirusChecker": {
+ "hash": 1111111111111,
+ "id": "cava_18"
+ }
+ }
+ }
+ }
+
+ @staticmethod
+ def get_nas_server_id():
+ return MockSDKObject({
+ "cifs_server": {
+ "UnityCifsServerList": [{
+ "UnityCifsServer": {
+ "hash": 1111111111111,
+ "id": "cifs_34"
+ }
+ }]
+ },
+ "current_sp": {
+ "UnityStorageProcessor": {
+ "hash": 1111111111111,
+ "id": "spb"
+ }
+ },
+ "current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NIS",
+ "existed": True,
+ "file_dns_server": {
+ "UnityFileDnsServer": {
+ "hash": 1111111111111,
+ "id": "dns_12"
+ }
+ },
+ "file_interface": {
+ "UnityFileInterfaceList": [{
+ "UnityFileInterface": {
+ "hash": 1111111111111,
+ "id": "if_37"
+ }
+ }]
+ },
+ "hash": 1111111111111,
+ "health": {
+ "UnityHealth": {
+ "hash": 1111111111111
+ }
+ },
+ "home_sp": {
+ "UnityStorageProcessor": {
+ "hash": 1111111111111,
+ "id": "spb"
+ }
+ },
+ "id": "nas_10",
+ "is_backup_only": False,
+ "is_multi_protocol_enabled": False,
+ "is_packet_reflect_enabled": False,
+ "is_replication_destination": False,
+ "is_replication_enabled": True,
+ "name": "dummy_nas",
+ "pool": {
+ "UnityPool": {
+ "hash": 1111111111111,
+ "id": "pool_7"
+ }
+ },
+ "preferred_interface_settings": {
+ "UnityPreferredInterfaceSettings": {
+ "hash": 1111111111111,
+ "id": "preferred_if_10"
+ }
+ },
+ "replication_type": "ReplicationTypeEnum.REMOTE",
+ "size_allocated": 1111111111111,
+ "virus_checker": {
+ "UnityVirusChecker": {
+ "hash": 1111111111111,
+ "id": "cava_10"}}})
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py
new file mode 100644
index 000000000..2556870ba
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py
@@ -0,0 +1,32 @@
+# 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 Unity modules"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+
+class MockSDKObject:
+ def __init__(self, data):
+ self.skip_list = ['skip_list']
+ for key, value in data.items():
+ setattr(self, key, value)
+
+ def add_to_skip_list(self, key):
+ self.skip_list.append(key)
+
+ def _get_properties(self):
+ data = {}
+ for attr, value in self.__dict__.items():
+ if attr not in self.skip_list:
+ data[attr] = value
+ return data
+
+ def get_id(self):
+ return "res_0"
+
+ def name(self):
+ return "res_0"
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py
new file mode 100644
index 000000000..1ec9fcadd
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py
@@ -0,0 +1,168 @@
+# 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 storagepool module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+
+
+class MockStoragePoolApi:
+ STORAGE_POOL_MODULE_ARGS = {
+ 'unispherehost': '**.***.**.***',
+ 'port': '123',
+ 'pool_name': None,
+ 'pool_id': None,
+ 'new_pool_name': None,
+ 'pool_description': None,
+ 'fast_cache': None,
+ 'fast_vp': None,
+ 'raid_groups': {},
+ 'state': None
+ }
+ RAID_TYPE_5 = 'RaidTypeEnum.RAID5'
+
+ @staticmethod
+ def get_pool_details_response(response_type):
+ if response_type == 'get_pool':
+ return {'alert_threshold': 84, 'creation_time': '2021-11-11 11:11:11+00:00',
+ 'description': '', 'harvest_state': 'UsageHarvestStateEnum.IDLE',
+ 'health': {'UnityHealth': {}}, 'id': 'pool_mock_1',
+ 'is_all_flash': True, 'is_empty': False, 'is_fast_cache_enabled': False,
+ 'is_harvest_enabled': True, 'is_snap_harvest_enabled': False,
+ 'metadata_size_subscribed': 1, 'metadata_size_used': 1,
+ 'name': 'Ansible_Unity_TEST_1', 'object_id': 1, 'pool_fast_vp': {'UnityPoolFastVp': {}},
+ 'pool_space_harvest_high_threshold': 95.0, 'pool_space_harvest_low_threshold': 85.0, 'pool_type':
+ 'StoragePoolTypeEnum.DYNAMIC', 'raid_type': MockStoragePoolApi.RAID_TYPE_5, 'rebalance_progress': None, 'size_free': 1,
+ 'size_subscribed': 1, 'size_total': 1, 'size_used': 1, 'snap_size_subscribed':
+ 1, 'snap_size_used': 1, 'snap_space_harvest_high_threshold': 25.0, 'snap_space_harvest_low_threshold':
+ 20.0, 'tiers': {'UnityPoolTierList': [{'UnityPoolTier': {}}, {'UnityPoolTier': {}}, {'UnityPoolTier': {}}]}, 'existed': True}
+ elif response_type == 'pool_object':
+ return {'alert_threshold': 84, 'creation_time': '2021-11-11 11:11:11+00:00',
+ 'description': '', 'harvest_state': 'UsageHarvestStateEnum.IDLE',
+ 'health': {'UnityHealth': {}}, 'id': 'pool_mock_1',
+ 'is_all_flash': True, 'is_empty': False, 'is_fast_cache_enabled': False,
+ 'is_harvest_enabled': True, 'is_snap_harvest_enabled': False,
+ 'metadata_size_subscribed': 1, 'metadata_size_used': 1,
+ 'name': 'Ansible_Unity_TEST_1', 'object_id': 1,
+ 'pool_fast_vp': {'UnityPoolFastVp': {}},
+ 'pool_space_harvest_high_threshold': 95.0,
+ 'pool_space_harvest_low_threshold': 85.0, 'pool_type': 'StoragePoolTypeEnum.DYNAMIC',
+ 'raid_type': MockStoragePoolApi.RAID_TYPE_5, 'rebalance_progress': None, 'size_free': 1,
+ 'size_subscribed': 1, 'size_total': 1, 'size_used': 1,
+ 'snap_size_subscribed': 1, 'snap_size_used': 1,
+ 'snap_space_harvest_high_threshold': 25.0, 'snap_space_harvest_low_threshold': 20.0,
+ 'tiers': MockSDKObject({'disk_count': [5, 0, 0], 'name': ['Extreme Performance', 'Performance', 'Capacity'],
+ 'pool_units': [{'UnityPoolUnitList': [{'UnityPoolUnit': {'id': 'pool_unit_mock_1'}}]}, None, None],
+ 'raid_type': [MockStoragePoolApi.RAID_TYPE_5, 'RaidTypeEnum.NONE', 'RaidTypeEnum.NONE'],
+ 'size_free': [1, 0, 0],
+ 'size_moving_down': [0, 0, 0], 'size_moving_up': [0, 0, 0],
+ 'size_moving_within': [0, 0, 0], 'size_total': [1, 0, 0],
+ 'size_used': [1, 0, 0], 'stripe_width': ['RaidStripeWidthEnum._5', None, None],
+ 'tier_type': ['TierTypeEnum.EXTREME_PERFORMANCE', 'TierTypeEnum.PERFORMANCE', 'TierTypeEnum.CAPACITY'],
+ 'existed': True}),
+ 'existed': True}
+ elif response_type == 'disk_list':
+ return [MockSDKObject({"bus_id": 99, "current_speed": 1, "disk_group": {"UnityDiskGroup": {"id": "disk_mock_1"}},
+ "disk_technology": MockSDKObject({"name": "mock_disk_tech"}), "emc_part_number": "XXXXXXXX",
+ "emc_serial_number": "XXXXXXXX", "existed": True, "health": {"UnityHealth": {}},
+ "id": "disk_mock_2", "is_fast_cache_in_use": False, "is_in_use": True,
+ "is_sed": False, "manufacturer": "mock_disk_manufacturer",
+ "max_speed": 1, "model": "mock_disk_model", "name": "Drive 12",
+ "needs_replacement": False, "pool": MockSDKObject({"id": "pool_5", "name": "Pool_Mock_TEST_2", "UnityPool": {}}),
+ "raw_size": 1, "rpm": 0, "size": 1, "slot_number": 12,
+ "tier_type": MockSDKObject({"name": "EXTREME_PERFORMANCE"}), "vendor_size": 1,
+ "version": "S109", "wwn": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"}),
+ MockSDKObject({"bus_id": 99, "current_speed": 1,
+ "disk_group": {"UnityDiskGroup": {"id": "disk_mock_1"}},
+ "disk_technology": MockSDKObject({"name": "mock_disk_tech"}), "emc_part_number": "XXXXXXXX",
+ "emc_serial_number": "XXXXXXXX", "existed": True, "health": {"UnityHealth": {}},
+ "id": "mock_disk_id", "is_fast_cache_in_use": False, "is_in_use": True, "is_sed": False,
+ "manufacturer": "mock_disk_manufacturer", "max_speed": 1, "model": "mock_disk_model",
+ "name": "disk_disk_name", "needs_replacement": False,
+ "pool": MockSDKObject({"id": "pool_mock_1", "name": "Ansible_Unity_TEST_1"}),
+ "raw_size": 1, "rpm": 0, "size": 1,
+ "slot_number": 13, "tier_type": MockSDKObject({"name": "EXTREME_PERFORMANCE"}),
+ "vendor_size": 1, "version": "S109",
+ "wwn": "01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"})]
+ elif response_type == 'module':
+ return {"storage_pool_details":
+ {"alert_threshold": 84, "creation_time": "2021-11-11 11:11:11+00:00", "description": "",
+ "drives": [{"disk_technology": "mock_disk_tech", "id": "mock_disk_id", "name": "disk_disk_name",
+ "size": 1, "tier_type": "EXTREME_PERFORMANCE"}],
+ "existed": True, "harvest_state": "UsageHarvestStateEnum.IDLE",
+ "health": {"UnityHealth": {}},
+ "id": "pool_mock_1", "is_all_flash": True, "is_empty": False,
+ "is_fast_cache_enabled": False, "is_fast_vp_enabled": True,
+ "is_harvest_enabled": True, "is_snap_harvest_enabled": False,
+ "metadata_size_subscribed": 1, "metadata_size_used":
+ 1, "name": "Ansible_Unity_TEST_1", "object_id": 1,
+ "pool_fast_vp": {"UnityPoolFastVp": {}},
+ "pool_space_harvest_high_threshold": 95.0,
+ "pool_space_harvest_low_threshold": 85.0, "pool_type": "StoragePoolTypeEnum.DYNAMIC",
+ "raid_type": "RaidTypeEnum.RAID5", "rebalance_progress": None, "size_free": 1,
+ "size_free_with_unit": "1.0 B", "size_subscribed": 1, "size_subscribed_with_unit": "1.0 B",
+ "size_total": 1, "size_total_with_unit": "1.0 B", "size_used": 1, "size_used_with_unit": "1.0 B",
+ "snap_size_subscribed": 1, "snap_size_subscribed_with_unit": "1.0 B", "snap_size_used": 1,
+ "snap_size_used_with_unit": "1.0 B", "snap_space_harvest_high_threshold": 25.0, "snap_space_harvest_low_threshold": 20.0,
+ "tiers": {"UnityPoolTierList": [{"disk_count": [5, 0, 0], "existed": True,
+ "name": ["Extreme Performance", "Performance", "Capacity"],
+ "pool_units": [{"UnityPoolUnitList": [{"UnityPoolUnit": {"id": "pool_unit_mock_1"}}]}, None, None],
+ "raid_type": ["RaidTypeEnum.RAID5", "RaidTypeEnum.NONE", "RaidTypeEnum.NONE"],
+ "size_free": [1, 0, 0], "size_moving_down": [0, 0, 0],
+ "size_moving_up": [0, 0, 0],
+ "size_moving_within": [0, 0, 0],
+ "size_total": [1, 0, 0],
+ "size_used": [1, 0, 0],
+ "stripe_width": ["RaidStripeWidthEnum._5", None, None],
+ "tier_type": ["TierTypeEnum.EXTREME_PERFORMANCE", "TierTypeEnum.PERFORMANCE",
+ "TierTypeEnum.CAPACITY"]}]}}}
+ elif response_type == 'error':
+ return 'Get details of storage pool failed with error: '
+
+ @staticmethod
+ def create_pool_response(response_type):
+ if response_type == 'api':
+ return {"storage_pool_details":
+ {"alert_threshold": 50, "creation_time": "2022-03-08 10:51:08+00:00", "description": "Unity test pool.",
+ "drives": [{"disk_technology": "SAS", "id": "disk_id_1", "name": "DPE Drive 1",
+ "size": 1, "tier_type": "PERFORMANCE"},
+ {"disk_technology": "SAS", "id": "disk_id_2", "name": "DPE Drive 2",
+ "size": 1, "tier_type": "PERFORMANCE"},
+ {"disk_technology": "SAS", "id": "disk_id_3", "name": "DPE Drive 3",
+ "size": 1, "tier_type": "PERFORMANCE"}],
+ "existed": True, "harvest_state": "UsageHarvestStateEnum.IDLE",
+ "health": {"UnityHealth": {}},
+ "id": "pool_id_1", "is_all_flash": False, "is_empty": True,
+ "is_fast_cache_enabled": False, "is_fast_vp_enabled": True,
+ "is_harvest_enabled": True, "is_snap_harvest_enabled": True,
+ "metadata_size_subscribed": 0, "metadata_size_used":
+ 0, "name": "Mock_Test", "object_id": 123,
+ "pool_fast_vp": {"UnityPoolFastVp": {}},
+ "pool_space_harvest_high_threshold": 59.0,
+ "pool_space_harvest_low_threshold": 40.0, "pool_type": "StoragePoolTypeEnum.DYNAMIC",
+ "raid_type": "RaidTypeEnum.RAID10", "rebalance_progress": None, "size_free": 1,
+ "size_free_with_unit": "1 GB", "size_subscribed": 0, "size_subscribed_with_unit": "0B",
+ "size_total": 1, "size_total_with_unit": "1 GB", "size_used": 0, "size_used_with_unit": "0B",
+ "snap_size_subscribed": 0, "snap_size_subscribed_with_unit": "0B", "snap_size_used": 0,
+ "snap_size_used_with_unit": "0B", "snap_space_harvest_high_threshold": 80.0, "snap_space_harvest_low_threshold": 60.0,
+ "tiers": {"UnityPoolTierList": [{"disk_count": [0, 3, 0], "existed": True,
+ "name": ["Extreme Performance", "Performance", "Capacity"],
+ "pool_units": [{"UnityPoolUnitList": [{"UnityPoolUnit": {"id": "rg_id_1"}},
+ {"UnityPoolUnit": {"id": "rg_id_2"}}]}, None],
+ "raid_type": ["RaidTypeEnum.NONE", "RaidTypeEnum.RAID10", "RaidTypeEnum.NONE"],
+ "size_free": [0, 1, 0], "size_moving_down": [0, 0, 0],
+ "size_moving_up": [0, 0, 0],
+ "size_moving_within": [0, 0, 0],
+ "size_total": [0, 1, 0],
+ "size_used": [0, 0, 0],
+ "stripe_width": [None, "RaidStripeWidthEnum._2", None],
+ "tier_type": ["TierTypeEnum.EXTREME_PERFORMANCE", "TierTypeEnum.PERFORMANCE",
+ "TierTypeEnum.CAPACITY"]}]}}}
+ elif response_type == 'error':
+ return 'Failed to create storage pool with error: '
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py
new file mode 100644
index 000000000..82097a338
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py
@@ -0,0 +1,174 @@
+# 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 volume module on Unity"""
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response import MockSDKObject
+
+
+class MockVolumeApi:
+
+ VOLUME_MODULE_ARGS = {
+ 'unispherehost': '**.***.**.***',
+ 'port': '123',
+ 'vol_name': None,
+ 'vol_id': None,
+ 'description': None,
+ 'pool_name': None,
+ 'pool_id': None,
+ 'size': None,
+ 'cap_unit': None,
+ 'is_thin': None,
+ 'compression': None,
+ 'advanced_dedup': None,
+ 'sp': None,
+ 'io_limit_policy': None,
+ 'snap_schedule': None,
+ 'host_name': None,
+ 'host_id': None,
+ 'hosts': {},
+ 'hlu': None,
+ 'mapping_state': None,
+ 'new_vol_name': None,
+ 'tiering_policy': None,
+ 'state': None,
+ }
+
+ pool = {
+ 'alert_threshold': 60,
+ 'creation_time': '2021-10-18 12:51:27+00:00',
+ 'description': 'A2Z',
+ 'existed': True,
+ 'harvest_state': 'UsageHarvestStateEnum.IDLE',
+ 'hash': 8778647453970,
+ 'health': {'UnityHealth': {'hash': 8778647453730}},
+ 'id': 'pool_3',
+ 'is_all_flash': True,
+ 'is_empty': False,
+ 'is_fast_cache_enabled': False,
+ 'is_harvest_enabled': True,
+ 'is_snap_harvest_enabled': True,
+ 'metadata_size_subscribed': 646124142592,
+ 'metadata_size_used': 357287591936,
+ 'name': 'Extreme_Perf_tier',
+ 'object_id': 12884901892,
+ 'pool_fast_vp': {'UnityPoolFastVp': {'hash': 8778647539688}},
+ 'pool_space_harvest_high_threshold': 95.0,
+ 'pool_space_harvest_low_threshold': 70.5,
+ 'pool_type': 'StoragePoolTypeEnum.TRADITIONAL',
+ 'raid_type': 'RaidTypeEnum.RAID5',
+ 'size_free': 1174673555456,
+ 'size_subscribed': 8703230820352,
+ 'size_total': 3141768577024,
+ 'size_used': 1802576257024,
+ 'snap_size_subscribed': 290195193856,
+ 'snap_size_used': 43098112,
+ 'snap_space_harvest_high_threshold': 20.5,
+ 'snap_space_harvest_low_threshold': 1.0,
+ 'tiers': {'UnityPoolTierList': [{'UnityPoolTier': {'hash': 8778647538737}},
+ {'UnityPoolTier': {'hash': 8778647538749}},
+ {'UnityPoolTier': {'hash': 8778647526797}}]},
+ }
+
+ @staticmethod
+ def create_volume_response(response_type):
+ if response_type == 'api':
+ return {'volume_details': {
+ 'current_node': 'NodeEnum.SPB',
+ 'data_reduction_percent': 0,
+ 'data_reduction_ratio': 1.0,
+ 'data_reduction_size_saved': 0,
+ 'default_node': 'NodeEnum.SPB',
+ 'description': None,
+ 'effective_io_limit_max_iops': None,
+ 'effective_io_limit_max_kbps': None,
+ 'existed': True,
+ 'family_base_lun': {'UnityLun': {}},
+ 'family_clone_count': 0,
+ 'hash': 8769317548849,
+ 'health': {'UnityHealth': {}},
+ 'host_access': [],
+ 'id': 'sv_214551',
+ 'io_limit_policy': True,
+ 'is_advanced_dedup_enabled': True,
+ 'is_compression_enabled': True,
+ 'is_data_reduction_enabled': True,
+ 'is_replication_destination': False,
+ 'is_snap_schedule_paused': False,
+ 'is_thin_clone': False,
+ 'is_thin_enabled': True,
+ 'metadata_size': 3758096384,
+ 'metadata_size_allocated': 3221225472,
+ 'name': 'Atest',
+ 'per_tier_size_used': [3489660928, 0, 0],
+ 'pool': {'id': 'pool_3', 'name': 'Extreme_Perf_tier'},
+ 'size_allocated': 0,
+ 'size_total': 2147483648,
+ 'size_total_with_unit': '2.0 GB',
+ 'size_used': None,
+ 'snap_count': 0,
+ 'snap_schedule': None,
+ 'snap_wwn': '60:06:01:60:5C:F0:50:00:F6:42:70:38:7A:90:40:FF',
+ 'snaps_size': 0,
+ 'snaps_size_allocated': 0,
+ 'storage_resource': {'UnityStorageResource': {}},
+ 'tiering_policy': 'TieringPolicyEnum.AUTOTIER_HIGH',
+ 'type': 'LUNTypeEnum.STANDALONE',
+ 'wwn': '60:06:01:60:5C:F0:50:00:41:25:EA:63:94:92:92:AE',
+ }}
+ else:
+ return 'Create volume operation Atest failed with error'
+
+ @staticmethod
+ def modify_volume_response(response_type):
+ if response_type == 'api':
+ return {'volume_details': {
+ 'current_node': 'NodeEnum.SPB',
+ 'data_reduction_percent': 0,
+ 'data_reduction_ratio': 1.0,
+ 'data_reduction_size_saved': 0,
+ 'default_node': 'NodeEnum.SPB',
+ 'description': None,
+ 'effective_io_limit_max_iops': None,
+ 'effective_io_limit_max_kbps': None,
+ 'existed': True,
+ 'family_base_lun': {'UnityLun': {}},
+ 'family_clone_count': 0,
+ 'hash': 8769317548849,
+ 'health': {'UnityHealth': {}},
+ 'host_access': [],
+ 'id': 'sv_214551',
+ 'io_limit_policy': None,
+ 'is_advanced_dedup_enabled': False,
+ 'is_compression_enabled': True,
+ 'is_data_reduction_enabled': True,
+ 'is_replication_destination': False,
+ 'is_snap_schedule_paused': False,
+ 'is_thin_clone': False,
+ 'is_thin_enabled': True,
+ 'metadata_size': 3758096384,
+ 'metadata_size_allocated': 3221225472,
+ 'name': 'Atest',
+ 'per_tier_size_used': [3489660928, 0, 0],
+ 'pool': {'id': 'pool_3', 'name': 'Extreme_Perf_tier'},
+ 'size_allocated': 0,
+ 'size_total': 2147483648,
+ 'size_total_with_unit': '2.0 GB',
+ 'size_used': None,
+ 'snap_count': 0,
+ 'snap_schedule': None,
+ 'snap_wwn': '60:06:01:60:5C:F0:50:00:F6:42:70:38:7A:90:40:FF',
+ 'snaps_size': 0,
+ 'snaps_size_allocated': 0,
+ 'storage_resource': {'UnityStorageResource': {}},
+ 'tiering_policy': 'TieringPolicyEnum.AUTOTIER_HIGH',
+ 'type': 'LUNTypeEnum.STANDALONE',
+ 'wwn': '60:06:01:60:5C:F0:50:00:41:25:EA:63:94:92:92:AE',
+ }}
+ else:
+ return 'Failed to modify the volume Atest with error'
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py
new file mode 100644
index 000000000..e28c2e935
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py
@@ -0,0 +1,169 @@
+# 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 CIFS server module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_cifsserver_api \
+ import MockCIFSServerApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import HttpError as http_error, MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+utils.UnityCifsServer = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.unity.plugins.modules.cifsserver import CIFSServer
+
+
+class TestCIFSServer():
+
+ get_module_args = MockCIFSServerApi.CIFS_SERVER_MODULE_ARGS
+
+ @pytest.fixture
+ def cifsserver_module_mock(self):
+ cifsserver_module_mock = CIFSServer()
+ cifsserver_module_mock.unity_conn = MagicMock()
+ utils.cifsserver = MagicMock()
+ return cifsserver_module_mock
+
+ def test_get_cifs_server_details(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.unity_conn.get_cifs_server = MagicMock(return_value=MockSDKObject(cifs_server_details))
+ cifsserver_module_mock.perform_module_operation()
+ assert MockCIFSServerApi.get_cifs_server_details_method_response() == \
+ cifsserver_module_mock.module.exit_json.call_args[1]['cifs_server_details']
+
+ def test_get_cifs_server_details_using_id(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_id': 'cifs_59',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.unity_conn.get_cifs_server = MagicMock(return_value=MockSDKObject(cifs_server_details))
+ cifsserver_module_mock.perform_module_operation()
+ assert MockCIFSServerApi.get_cifs_server_details_method_response() == \
+ cifsserver_module_mock.module.exit_json.call_args[1]['cifs_server_details']
+
+ def test_get_get_nas_server_id(self, cifsserver_module_mock):
+ nas_server_details = MockCIFSServerApi.get_nas_server_details()
+ self.get_module_args.update({
+ 'cifs_server_id': 'cifs_59',
+ 'nas_server_name': 'test_nas1',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.unity_conn.get_nas_server = MagicMock(return_value=MockSDKObject(nas_server_details))
+ cifsserver_module_mock.perform_module_operation()
+ cifsserver_module_mock.unity_conn.get_nas_server.assert_called()
+
+ def test_create_cifs_server(self, cifsserver_module_mock):
+ self.get_module_args.update({
+ 'nas_server_id': 'nas_18',
+ 'cifs_server_name': 'test_cifs_server',
+ 'domain': 'xxx.xxx.xxx.xxx',
+ 'domain_username': 'xxxxxxxx',
+ 'domain_password': 'xxxxxxxx',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=None)
+ cifsserver_module_mock.unity_conn.create_cifs_server = MagicMock(return_value=True)
+ cifsserver_module_mock.perform_module_operation()
+ assert cifsserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_create_cifs_server_throws_exception(self, cifsserver_module_mock):
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'domain': 'xxx.xxx.xxx.xxx',
+ 'domain_username': 'xxxxxxxx',
+ 'domain_password': 'xxxxxxxx',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=None)
+ cifsserver_module_mock.perform_module_operation()
+ assert MockCIFSServerApi.create_cifs_server_without_nas() == cifsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_delete_cifs_server(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'unjoin_cifs_server_account': False,
+ 'domain_username': 'xxxxxxxx',
+ 'domain_password': 'xxxxxxxx',
+ 'state': 'absent'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details)
+ cifsserver_module_mock.get_cifs_server_instance = MagicMock(return_value=MockSDKObject(cifs_server_details))
+ cifsserver_module_mock.perform_module_operation()
+ assert cifsserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_is_modification_required(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'netbios_name': 'ansible_netbios',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details)
+ cifsserver_module_mock.perform_module_operation()
+ assert MockCIFSServerApi.modify_error_msg() == cifsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_is_domain_modification_required(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'domain': 'yyy.yyy.yyy.yyy',
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details)
+ cifsserver_module_mock.perform_module_operation()
+ print(cifsserver_module_mock.module.fail_json.call_args[1])
+ assert MockCIFSServerApi.modify_error_msg() == cifsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_is_modify_interfaces(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'interfaces': ['if_39'],
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details)
+ cifsserver_module_mock.perform_module_operation()
+ print(cifsserver_module_mock.module.fail_json.call_args[1])
+ assert MockCIFSServerApi.modify_error_msg() == cifsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_is_modify_interfaces_idempotency(self, cifsserver_module_mock):
+ cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response()
+ self.get_module_args.update({
+ 'cifs_server_name': 'test_cifs_server',
+ 'interfaces': ['if_43'],
+ 'state': 'present'
+ })
+ cifsserver_module_mock.module.params = self.get_module_args
+ cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details)
+ cifsserver_module_mock.perform_module_operation()
+ assert cifsserver_module_mock.module.exit_json.call_args[1]['changed'] is False
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py
new file mode 100644
index 000000000..dd2cdd81a
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py
@@ -0,0 +1,193 @@
+# 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 consistency group module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_consistencygroup_api \
+ import MockConsistenyGroupApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock(side_effect=[MagicMock(),
+ MockConsistenyGroupApi.get_remote_system_conn_response()])
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.consistencygroup import ConsistencyGroup
+
+
+class TestConsistencyGroup():
+
+ get_module_args = MockConsistenyGroupApi.CONSISTENCY_GROUP_MODULE_ARGS
+
+ @pytest.fixture
+ def consistencygroup_module_mock(self):
+ consistencygroup_module_mock = ConsistencyGroup()
+ consistencygroup_module_mock.unity_conn = MagicMock()
+ utils.cg = MagicMock()
+ return consistencygroup_module_mock
+
+ def test_enable_cg_replication(self, consistencygroup_module_mock):
+ self.get_module_args.update({
+ 'cg_name': 'lun_test_cg_source_12',
+ 'replication_params': {
+ 'destination_cg_name': 'destination_cg_1',
+ 'replication_mode': 'asynchronous',
+ 'rpo': 60,
+ 'replication_type': 'remote',
+ 'remote_system': {
+ 'remote_system_host': '11.111.11.11',
+ 'remote_system_verifycert': False,
+ 'remote_system_username': 'username',
+ 'remote_system_password': 'password',
+ 'remote_system_port': 1111
+ },
+ 'destination_pool_name': 'pool_test_name_1',
+ 'destination_pool_id': None
+ },
+ 'replication_state': 'enable',
+ 'state': 'present'
+ })
+ consistencygroup_module_mock.module.params = self.get_module_args
+ cg_details = MockConsistenyGroupApi.cg_get_details_method_response()
+ cg_object = MockConsistenyGroupApi.get_cg_object()
+ consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object)
+ consistencygroup_module_mock.get_details = MagicMock(side_effect=[
+ cg_details,
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details')])
+ cg_object.get_id = MagicMock(return_value=cg_details['id'])
+ utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object)
+ cg_object.check_cg_is_replicated = MagicMock(return_value=False)
+ consistencygroup_module_mock.unity_conn.get_remote_system = \
+ MagicMock(return_value=MockConsistenyGroupApi.get_cg_replication_dependent_response('remote_system'))
+ utils.UnityStorageResource = MagicMock(return_value=MockSDKObject({}))
+ cg_object.replicate_cg_with_dst_resource_provisioning = MagicMock(return_value=None)
+ consistencygroup_module_mock.perform_module_operation()
+ assert consistencygroup_module_mock.module.exit_json.call_args[1]['consistency_group_details']['cg_replication_enabled'] is True
+ assert consistencygroup_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_enable_cg_replication_negative_1(self, consistencygroup_module_mock):
+ self.get_module_args.update({
+ 'cg_name': 'lun_test_cg_source_12',
+ 'replication_params': {
+ 'destination_cg_name': '',
+ 'replication_mode': 'asynchronous',
+ 'rpo': 60,
+ 'replication_type': 'local',
+ 'destination_pool_name': None,
+ 'destination_pool_id': 'pool_test_1'
+ },
+ 'replication_state': 'enable',
+ 'state': 'present'
+ })
+ consistencygroup_module_mock.module.params = self.get_module_args
+ cg_details = MockConsistenyGroupApi.cg_get_details_method_response()
+ cg_object = MockConsistenyGroupApi.get_cg_object()
+ consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object)
+ consistencygroup_module_mock.get_details = MagicMock(side_effect=[
+ cg_details,
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details')])
+ cg_object.get_id = MagicMock(return_value=cg_details['id'])
+ utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object)
+ cg_object.check_cg_is_replicated = MagicMock(return_value=False)
+ consistencygroup_module_mock.unity_conn.get_remote_system = \
+ MagicMock(return_value=MockConsistenyGroupApi.get_cg_replication_dependent_response('remote_system'))
+ utils.UnityStorageResource = MagicMock(return_value=MockSDKObject({}))
+ cg_object.replicate_cg_with_dst_resource_provisioning = MagicMock(return_value=None)
+ consistencygroup_module_mock.perform_module_operation()
+ assert consistencygroup_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('destination_cg_name_validation')
+
+ def test_enable_cg_replication_negative_2(self, consistencygroup_module_mock):
+ self.get_module_args.update({
+ 'cg_name': 'lun_test_cg_source_12',
+ 'replication_params': {
+ 'destination_cg_name': 'destination_cg_1',
+ 'replication_mode': 'asynchronous',
+ 'rpo': 60,
+ 'replication_type': 'remote',
+ 'remote_system': {
+ 'remote_system_host': '11.111.11.11',
+ 'remote_system_verifycert': False,
+ 'remote_system_username': 'username',
+ 'remote_system_password': 'password',
+ 'remote_system_port': 1111
+ },
+ 'destination_pool_name': None,
+ 'destination_pool_id': 'pool_test_1'
+ },
+ 'replication_state': 'enable',
+ 'state': 'present'
+ })
+ consistencygroup_module_mock.module.params = self.get_module_args
+ cg_details = MockConsistenyGroupApi.cg_get_details_method_response()
+ cg_object = MockConsistenyGroupApi.get_cg_object()
+ consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object)
+ consistencygroup_module_mock.get_details = MagicMock(side_effect=[
+ cg_details,
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details')])
+ cg_object.get_id = MagicMock(return_value=cg_details['id'])
+ utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object)
+ cg_object.check_cg_is_replicated = MagicMock(return_value=False)
+ consistencygroup_module_mock.unity_conn.get_remote_system = MagicMock(side_effect=MockApiException)
+ consistencygroup_module_mock.perform_module_operation()
+ assert consistencygroup_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('enable_cg_exception')
+
+ def test_disable_cg_replication(self, consistencygroup_module_mock):
+ self.get_module_args.update({
+ 'cg_name': 'lun_test_cg_source_12',
+ 'replication_state': 'disable',
+ 'state': 'present'
+ })
+ consistencygroup_module_mock.module.params = self.get_module_args
+ cg_details = MockConsistenyGroupApi.cg_get_details_method_response()
+ cg_object = MockConsistenyGroupApi.get_cg_object()
+ consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object)
+ consistencygroup_module_mock.get_details = MagicMock(side_effect=[
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details'),
+ cg_details])
+ cg_object.get_id = MagicMock(return_value=cg_details['id'])
+ utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object)
+ cg_object.check_cg_is_replicated = MagicMock(return_value=True)
+ repl_session = MockConsistenyGroupApi.get_cg_replication_dependent_response('replication_session')
+ repl_session.delete = MagicMock(return_value=None)
+ consistencygroup_module_mock.unity_conn.get_replication_session = \
+ MagicMock(return_value=[repl_session])
+ consistencygroup_module_mock.perform_module_operation()
+ assert consistencygroup_module_mock.module.exit_json.call_args[1]['consistency_group_details']['cg_replication_enabled'] is False
+ assert consistencygroup_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_disable_cg_replication_throws_exception(self, consistencygroup_module_mock):
+ self.get_module_args.update({
+ 'cg_name': 'lun_test_cg_source_12',
+ 'replication_state': 'disable',
+ 'state': 'present'
+ })
+ consistencygroup_module_mock.module.params = self.get_module_args
+ cg_details = MockConsistenyGroupApi.cg_get_details_method_response()
+ cg_object = MockConsistenyGroupApi.get_cg_object()
+ consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object)
+ consistencygroup_module_mock.get_details = MagicMock(side_effect=[
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details'),
+ cg_details])
+ cg_object.get_id = MagicMock(return_value=cg_details['id'])
+ utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object)
+ cg_object.check_cg_is_replicated = MagicMock(side_effect=MockApiException)
+ consistencygroup_module_mock.perform_module_operation()
+ assert consistencygroup_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockConsistenyGroupApi.get_cg_replication_dependent_response('disable_cg_exception')
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py
new file mode 100644
index 000000000..c8551d08b
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py
@@ -0,0 +1,94 @@
+# 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 FileSystem module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+import re
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_filesystem_api \
+ import MockFileSystemApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.UnityReplicationSession = object
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.filesystem import Filesystem
+
+
+class TestFileSystem():
+
+ FILE_SYSTEM_MODULE_ARGS = {'filesystem_id': '123', 'filesystem_name': None, 'nas_server_name': None,
+ 'nas_server_id': None, 'pool_name': None, 'pool_id': None, 'size': None,
+ 'cap_unit': None, 'quota_config': None, 'snap_schedule_name': None,
+ 'snap_schedule_id': None, 'replication_params': {}, 'replication_state': None, 'state': None}
+
+ @pytest.fixture
+ def filesystem_module_mock(self):
+ filesystem_module_mock = Filesystem()
+ filesystem_module_mock.unity_conn = MagicMock()
+ return filesystem_module_mock
+
+ def test_enable_fs_replication(self, filesystem_module_mock):
+ self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params())
+ filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS
+ filesystem_response = MockFileSystemApi.get_file_system_response()
+ filesystem_response['replicate_with_dst_resource_provisioning'] = MagicMock(return_value=True)
+ filesystem_module_mock.perform_module_operation()
+ assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_enable_fs_replication_invalid_params(self, filesystem_module_mock):
+ self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params(False))
+ filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS
+ filesystem_module_mock.is_modify_required = MagicMock(return_value=False)
+ filesystem_module_mock.perform_module_operation()
+ assert "Invalid rpo value" in \
+ filesystem_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_enable_fs_replication_throws_ex(self, filesystem_module_mock):
+ self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params())
+ filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS
+ filesystem_module_mock.is_modify_required = MagicMock(return_value=False)
+ filesystem_response = MockFileSystemApi.get_file_system_response()
+ filesystem_response['replicate_with_dst_resource_provisioning'] = MagicMock(side_effect=Exception)
+ filesystem_module_mock.get_filesystem = MagicMock(side_effect=[
+ MockSDKObject(filesystem_response)])
+ filesystem_module_mock.get_filesystem_display_attributes = MagicMock(side_effect=[
+ MockSDKObject(filesystem_response)])
+ filesystem_module_mock.perform_module_operation()
+ assert "Enabling replication to the filesystem failed with error" in \
+ re.sub(' <.*?>>', '', filesystem_module_mock.module.fail_json.call_args[1]['msg'])
+
+ def test_modify_fs_replication(self, filesystem_module_mock):
+ self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params())
+ filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS
+ filesystem_module_mock.perform_module_operation()
+ filesystem_module_mock.get_replication_session_on_filter = MagicMock()
+ assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_disable_replication(self, filesystem_module_mock):
+ self.FILE_SYSTEM_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'})
+ filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS
+ filesystem_module_mock.get_filesystem_display_attributes = MagicMock()
+ filesystem_module_mock.perform_module_operation()
+ assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_disable_replication_throws_ex(self, filesystem_module_mock):
+ self.FILE_SYSTEM_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'})
+ filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS
+ filesystem_module_mock.get_replication_session = MagicMock(side_effect=Exception)
+ filesystem_module_mock.get_filesystem_display_attributes = MagicMock()
+ filesystem_module_mock.perform_module_operation()
+ assert "Disabling replication on the filesystem failed with error" in \
+ re.sub(' <.*?>', '', filesystem_module_mock.module.fail_json.call_args[1]['msg'])
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py
new file mode 100644
index 000000000..de94c38d3
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py
@@ -0,0 +1,143 @@
+# 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 host module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_host_api \
+ import MockHostApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import HttpError as http_error, MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.host import Host
+
+
+class TestHost():
+
+ get_module_args = MockHostApi.HOST_MODULE_ARGS
+
+ @pytest.fixture
+ def host_module_mock(self):
+ host_module_mock = Host()
+ host_module_mock.unity = MagicMock()
+ utils.host = MagicMock()
+ return host_module_mock
+
+ def test_get_host_details(self, host_module_mock):
+ host_details = MockHostApi.get_host_details_response('api')
+ self.get_module_args.update({
+ 'host_name': 'host_name_1',
+ })
+ host_module_mock.module.params = self.get_module_args
+ host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list())
+ utils.host.UnityHostList.get = MagicMock(return_value=MockHostApi.get_host_count_response())
+ host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]])
+ host_module_mock.unity.get_host = MagicMock(return_value=MockSDKObject(host_details))
+ host_module_mock.perform_module_operation()
+ assert MockHostApi.get_host_details_response('module')['host_details'] == host_module_mock.module.exit_json.call_args[1]['host_details']
+
+ def test_get_host_details_throws_exception(self, host_module_mock):
+ self.get_module_args.update({
+ 'host_name': 'name1'
+ })
+ host_module_mock.module.params = self.get_module_args
+ utils.HttpError = http_error
+ utils.host.UnityHostList.get = MagicMock(side_effect=http_error)
+ host_module_mock.create_host = MagicMock(return_value=(False, MagicMock()))
+ host_module_mock.perform_module_operation()
+ assert MockHostApi.get_host_details_response('error') == host_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_add_network_address_to_host(self, host_module_mock):
+ self.get_module_args.update({
+ 'host_name': 'host_name_1',
+ 'network_address': 'net_add_1',
+ 'network_address_state': 'present-in-host',
+ 'state': 'present'
+ })
+ host_module_mock.module.params = self.get_module_args
+ host_details = MockHostApi.get_host_details_response('api')
+ host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]])
+ host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list())
+ host_module_mock.unity.get_host = MagicMock(return_value=MockSDKObject(MockHostApi.get_host_details_after_network_address_addition('api')))
+ host_details = MockSDKObject(host_details)
+ host_details.add_ip_port = MagicMock(return_value=None)
+ host_details.add_to_skip_list('add_ip_port')
+ host_module_mock.get_host_details = MagicMock(return_value=host_details)
+ host_module_mock.perform_module_operation()
+ assert MockHostApi.get_host_details_after_network_address_addition('module')['host_details'] == \
+ host_module_mock.module.exit_json.call_args[1]['host_details']
+ assert MockHostApi.get_host_details_after_network_address_addition('module')['changed'] == host_module_mock.module.exit_json.call_args[1]['changed']
+
+ def test_add_network_address_to_host_negative(self, host_module_mock):
+ self.get_module_args.update({
+ 'host_name': 'host_name_1',
+ 'network_address': 'net_ad$$$$$d_12',
+ 'network_address_state': 'present-in-host',
+ 'state': 'present'
+ })
+ host_module_mock.module.params = self.get_module_args
+ host_details = MockHostApi.get_host_details_response('api')
+ host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]])
+ host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list())
+ host_module_mock.manage_network_address = MagicMock(return_value=(None, False))
+ host_module_mock.get_host_details = MagicMock(return_value=MockSDKObject(host_details))
+ host_module_mock.perform_module_operation()
+ assert MockHostApi.get_host_details_after_network_address_addition('invalid_address') == \
+ host_module_mock.module.fail_json.call_args[1]['msg']
+ assert host_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_remove_network_address_from_host(self, host_module_mock):
+ self.get_module_args.update({
+ 'host_name': 'host_name_1',
+ 'network_address': 'host_name_1',
+ 'network_address_state': 'absent-in-host',
+ 'state': 'present'
+ })
+ host_module_mock.module.params = self.get_module_args
+ host_details = MockHostApi.get_host_details_response('api')
+ host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]])
+ host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list())
+ host_module_mock.unity.get_host = MagicMock(return_value=MockSDKObject(MockHostApi.get_host_details_after_network_address_removal('api')))
+ host_details = MockSDKObject(host_details)
+ host_details.delete_ip_port = MagicMock(return_value=None)
+ host_details.add_to_skip_list('delete_ip_port')
+ host_module_mock.get_host_details = MagicMock(return_value=host_details)
+ host_module_mock.perform_module_operation()
+ assert MockHostApi.get_host_details_after_network_address_removal('module')['host_details'] == \
+ host_module_mock.module.exit_json.call_args[1]['host_details']
+ assert MockHostApi.get_host_details_after_network_address_removal('module')['changed'] == host_module_mock.module.exit_json.call_args[1]['changed']
+
+ def test_remove_network_address_from_host_negative(self, host_module_mock):
+ self.get_module_args.update({
+ 'host_name': 'host_name_1',
+ 'network_address': '1.1.1',
+ 'network_address_state': 'absent-in-host',
+ 'state': 'present'
+ })
+ host_module_mock.module.params = self.get_module_args
+ host_details = MockHostApi.get_host_details_response('api')
+ host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]])
+ host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list())
+ host_module_mock.manage_network_address = MagicMock(return_value=(None, False))
+ host_module_mock.get_host_details = MagicMock(return_value=MockSDKObject(host_details))
+ host_module_mock.perform_module_operation()
+ assert MockHostApi.get_host_details_after_network_address_removal('invalid_IPV4') == \
+ host_module_mock.module.fail_json.call_args[1]['msg']
+ assert host_module_mock.module.exit_json.call_args[1]['changed'] is False
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py
new file mode 100644
index 000000000..88151bcba
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py
@@ -0,0 +1,350 @@
+# 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 interface module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_interface_api \
+ import MockInterfaceApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.interface import Interface
+
+
+class TestInterface():
+
+ interface_module_args = MockInterfaceApi.INTERFACE_MODULE_ARGS
+
+ @pytest.fixture
+ def interface_module_mock(self):
+ interface_module_mock = Interface()
+ interface_module_mock.module.check_mode = False
+ interface_module_mock.unity_conn = MagicMock()
+ return interface_module_mock
+
+ def test_validate_param_ethernet_port_name_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'ethernet_port_name': " ",
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.get_nas_server_obj = mock_none_response
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_interface_error_response('invalid_ethernet_port_name') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_validate_param_vlan_id_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'vlan_id': 2,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.get_nas_server_obj = mock_none_response
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_interface_error_response('invalid_vlan_id') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_validate_param_interface_ip_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': "10.2.2",
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.get_nas_server_obj = mock_none_response
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_interface_error_response('invalid_interface_ip') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_validate_param_gateway_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'gateway': "10.2.1",
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.get_nas_server_obj = mock_none_response
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_interface_error_response('invalid_gateway') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_validate_param_netmask_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'netmask': "10.2.0/2",
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.get_nas_server_obj = mock_none_response
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_interface_error_response('invalid_netmask') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_nas_server_obj_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_id': "nas_id_00",
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=MockInterfaceApi.get_nas_server_obj_existed_false())
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_nas_server_obj_errors('existed_false') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_nas_server_obj_exception(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_id': "nas_id_00",
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ mock_none_response = MagicMock(return_value=None)
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=MockApiException)
+ interface_module_mock.validate_create_params = mock_none_response
+ interface_module_mock.add_interface = mock_none_response
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_nas_server_obj_errors('exception') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_modify_operation_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'vlan_id': 4,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object)
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT)
+ interface_module_mock.perform_module_operation()
+ assert MockInterfaceApi.get_interface_error_response('modify_failure') == \
+ interface_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_interface_details(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object)
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT)
+ interface_module_mock.perform_module_operation()
+ interface_details = MockInterfaceApi.INTERFACE_OBJECT._get_properties()
+ assert interface_module_mock.module.exit_json.call_args[1]['interface_details'] == interface_details
+
+ def test_get_interface_details_exception(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object)
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(side_effect=[MockApiException, MockInterfaceApi.INTERFACE_OBJECT])
+ interface_module_mock.validate_create_params = MagicMock(return_value=None)
+ interface_module_mock.add_interface = MagicMock(return_value=None)
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockInterfaceApi.get_interface_exception_response('interface_exception')
+
+ def test_add_interface_without_role_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME,
+ 'netmask': MockInterfaceApi.NETMASK_DUMMY,
+ 'gateway': MockInterfaceApi.GATEWAY_DUMMY,
+ 'vlan_id': 324,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_existing = MockInterfaceApi.get_nas_without_interface()
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_Value=nas_server_existing)
+ interface_module_mock.add_interface = MagicMock(return_value=None)
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockInterfaceApi.get_interface_error_response('no_role')
+
+ def test_add_interface_without_ethernet_negative(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'role': "PRODUCTION",
+ 'netmask': MockInterfaceApi.NETMASK_DUMMY,
+ 'gateway': MockInterfaceApi.GATEWAY_DUMMY,
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'vlan_id': 324,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_existing = MockInterfaceApi.get_nas_without_interface()
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_Value=nas_server_existing)
+ interface_module_mock.add_interface = MagicMock(return_value=None)
+ interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})])
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockInterfaceApi.get_interface_error_response('no_ethernet')
+
+ def test_add_interface(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME,
+ 'role': "PRODUCTION",
+ 'netmask': MockInterfaceApi.NETMASK_DUMMY,
+ 'gateway': MockInterfaceApi.GATEWAY_DUMMY,
+ 'vlan_id': 324,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ nas_server_existing = MockInterfaceApi.get_nas_without_interface()
+ nas_server_existing.get_id = MagicMock(return_value='nas_id_00')
+ nas_server_existing.add_to_skip_list('get_id')
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=[nas_server_existing,
+ nas_server_object])
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT)
+ utils.FileInterfaceRoleEnum = MockInterfaceApi.FILE_INTERFACE_ROLE_ENUM_DUMMY
+ ethernet_port_info = MagicMock()
+ ethernet_port_info.id = 'ethernet_port_id_0'
+ interface_module_mock.unity_conn.get_ethernet_port = MagicMock(return_value=ethernet_port_info)
+ utils.UnityFileInterface = MagicMock()
+ utils.UnityFileInterface.create = MagicMock(return_value=None)
+ interface_module_mock.perform_module_operation()
+ interface_details = MockInterfaceApi.INTERFACE_OBJECT._get_properties()
+ assert interface_module_mock.module.exit_json.call_args[1]['interface_details'] == interface_details
+
+ def test_add_interface_no_change(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME,
+ 'role': "PRODUCTION",
+ 'netmask': MockInterfaceApi.NETMASK_DUMMY,
+ 'gateway': MockInterfaceApi.GATEWAY_DUMMY,
+ 'vlan_id': 324,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=[nas_server_object,
+ nas_server_object])
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT)
+ utils.FileInterfaceRoleEnum = MockInterfaceApi.FILE_INTERFACE_ROLE_ENUM_DUMMY
+ ethernet_port_info = MagicMock()
+ ethernet_port_info.id = 'ethernet_port_id_0'
+ interface_module_mock.unity_conn.get_ethernet_port = MagicMock(return_value=ethernet_port_info)
+ utils.UnityFileInterface = MagicMock()
+ utils.UnityFileInterface.create = MagicMock(return_value=None)
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.exit_json.call_args[1]['changed'] is False
+
+ def test_add_interface_exception(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME,
+ 'role': "PRODUCTION",
+ 'netmask': MockInterfaceApi.NETMASK_DUMMY,
+ 'gateway': MockInterfaceApi.GATEWAY_DUMMY,
+ 'vlan_id': 324,
+ 'state': "present"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ nas_server_existing = MockInterfaceApi.get_nas_without_interface()
+ nas_server_existing.get_id = MagicMock(return_value='nas_id_00')
+ nas_server_existing.add_to_skip_list('get_id')
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=[nas_server_existing,
+ nas_server_object])
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT)
+ utils.FileInterfaceRoleEnum = MockInterfaceApi.FILE_INTERFACE_ROLE_ENUM_DUMMY
+ ethernet_port_info = MagicMock()
+ ethernet_port_info.id = 'ethernet_port_id_0'
+ interface_module_mock.unity_conn.get_ethernet_port = MagicMock(return_value=ethernet_port_info)
+ utils.UnityFileInterface = MagicMock()
+ utils.UnityFileInterface.create = MagicMock(side_effect=MockApiException)
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockInterfaceApi.get_interface_exception_response('add_interface_exception')
+
+ def test_delete_interface(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'state': "absent"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object)
+ interface_object = MockInterfaceApi.INTERFACE_OBJECT
+ interface_object.delete = MagicMock(return_value=None)
+ interface_object.add_to_skip_list('delete')
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=interface_object)
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_delete_interface_exception(self, interface_module_mock):
+ self.interface_module_args.update({
+ 'nas_server_name': "dummy_nas",
+ 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY,
+ 'state': "absent"
+ })
+ interface_module_mock.module.params = self.interface_module_args
+ nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT
+ interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object)
+ interface_object = MockInterfaceApi.INTERFACE_OBJECT
+ interface_object.delete = MagicMock(side_effect=MockApiException)
+ interface_object.add_to_skip_list('delete')
+ interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=interface_object)
+ interface_module_mock.perform_module_operation()
+ assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \
+ MockInterfaceApi.get_interface_exception_response('delete_interface_exception')
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py
new file mode 100644
index 000000000..a929ba497
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py
@@ -0,0 +1,112 @@
+# 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 NAS Server module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_nasserver_api \
+ import MockNASServerApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.nas_server = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.nasserver import NASServer
+
+
+class TestNASServer():
+
+ NAS_SERVER_MODULE_ARGS = {'nas_server_name': 'nas0', 'nas_server_id': None, 'nas_server_new_name': None, 'default_unix_user': None,
+ 'default_windows_user': None, 'is_replication_destination': None, 'is_multiprotocol_enabled': None,
+ 'allow_unmapped_user': None, 'enable_windows_to_unix_username_mapping': None,
+ 'is_backup_only': None, 'is_packet_reflect_enabled': None, 'current_unix_directory_service': None,
+ 'replication_reuse_resource': None, 'replication_params': {}, 'replication_state': None, 'state': None}
+
+ @pytest.fixture
+ def nasserver_module_mock(self):
+ nasserver_module_mock = NASServer()
+ nasserver_module_mock.unity_conn = MagicMock()
+ return nasserver_module_mock
+
+ def get_nas_response(self):
+ nasserver_response = MockNASServerApi.get_nas_server_response()
+ nasserver_response['replicate_with_dst_resource_provisioning'] = MagicMock(return_value=True)
+ return nasserver_response
+
+ def test_enable_nas_replication(self, nasserver_module_mock):
+ self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params())
+ nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS
+ nasserver_module_mock.to_update = MagicMock(return_value=False)
+ nasserver_module_mock.get_nas_server = \
+ MagicMock(return_value=MockSDKObject(self.get_nas_response()))
+ nasserver_module_mock.perform_module_operation()
+ assert nasserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_enable_nas_replication_invalid_params(self, nasserver_module_mock):
+ self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params(False))
+ nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS
+ nasserver_module_mock.get_nas_server = \
+ MagicMock(return_value=MockSDKObject(self.get_nas_response()))
+ nasserver_module_mock.to_update = MagicMock(return_value=False)
+ nasserver_module_mock.perform_module_operation()
+ assert "rpo value should be in range of 5 to 1440" in \
+ nasserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_enable_nas_replication_throws_ex(self, nasserver_module_mock):
+ self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params())
+ nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS
+ nasserver_module_mock.to_update = MagicMock(return_value=False)
+ nasserver_module_mock.get_nas_server = \
+ MagicMock(return_value=MockSDKObject(self.get_nas_response()))
+ nasserver_module_mock.get_remote_system = MagicMock(side_effect=Exception)
+ nasserver_module_mock.perform_module_operation()
+ assert "Enabling replication to the nas server %s failed with error" \
+ % self.NAS_SERVER_MODULE_ARGS['nas_server_name'] in \
+ nasserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_modify_nas_replication(self, nasserver_module_mock):
+ self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params())
+ nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS
+ nasserver_module_mock.to_update = MagicMock(return_value=False)
+ nasserver_module_mock.get_nas_server = \
+ MagicMock(return_value=MockSDKObject(self.get_nas_response()))
+ nasserver_module_mock.get_replication_session_on_filter = MagicMock()
+ nasserver_module_mock.perform_module_operation()
+ assert nasserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_disable_replication(self, nasserver_module_mock):
+ self.NAS_SERVER_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'})
+ nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS
+ nasserver_module_mock.get_nas_server = \
+ MagicMock(return_value=MockSDKObject(self.get_nas_response()))
+ nasserver_module_mock.to_update = MagicMock(return_value=False)
+ nasserver_module_mock.update_replication_params = MagicMock()
+ nasserver_module_mock.perform_module_operation()
+ assert nasserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_disable_replication_throws_ex(self, nasserver_module_mock):
+ self.NAS_SERVER_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'})
+ nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS
+ nasserver_module_mock.get_nas_server = \
+ MagicMock(return_value=MockSDKObject(self.get_nas_response()))
+ nasserver_module_mock.to_update = MagicMock(return_value=False)
+ nasserver_module_mock.get_replication_session = MagicMock(side_effect=Exception)
+ nasserver_module_mock.perform_module_operation()
+ assert "Disabling replication on the nas server %s failed with error" \
+ % self.NAS_SERVER_MODULE_ARGS['nas_server_name'] in \
+ nasserver_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py
new file mode 100644
index 000000000..ed138147c
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py
@@ -0,0 +1,183 @@
+# 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 nfs module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_nfs_api \
+ import MockNfsApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules import nfs
+
+
+class TestNfs():
+
+ get_module_args = MockNfsApi.NFS_MODULE_ARGS
+
+ @pytest.fixture
+ def nfs_module_mock(self):
+ nfs_module_mock = nfs.NFS()
+ nfs_module_mock.unity = MagicMock()
+ return nfs_module_mock
+
+ def test_add_host_in_nfs_share_on_advhostmgmt_true(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'adv_host_mgmt_enabled': True,
+ 'no_access_hosts': [{'host_name': "host1"}, {'ip_address': "**.***.2.2"}],
+ 'host_state': 'present-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ utils.UnityNfsShareList = MagicMock
+ nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('add', True)
+ nfs_object.modify = MagicMock(return_value=None)
+ nfs_object.add_to_skip_list('modify')
+ fs_object = MockNfsApi.FILESYSTEM_OBJECT
+ get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('add', True)
+ nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object)
+ nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object)
+ nfs_module_mock.unity.get_host = MagicMock(side_effect=[MockNfsApi.get_host_obj(id=1), MockNfsApi.get_host_obj(id=2)])
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_remove_host_in_nfs_share_on_advhostmgmt_true(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'adv_host_mgmt_enabled': True,
+ 'no_access_hosts': [{'host_name': "host1"}, {'ip_address': "**.***.2.2"}],
+ 'host_state': 'absent-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ utils.UnityNfsShareList = MagicMock
+ nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('remove', True)
+ nfs_object.modify = MagicMock(return_value=None)
+ nfs_object.add_to_skip_list('modify')
+ fs_object = MockNfsApi.FILESYSTEM_OBJECT
+ get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('remove', True)
+ nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object)
+ nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object)
+ nfs_module_mock.unity.get_host = MagicMock(side_effect=[MockNfsApi.get_host_obj(id=1), MockNfsApi.get_host_obj(id=2),
+ MockNfsApi.get_host_obj(id=1), MockNfsApi.get_host_obj(id=2)])
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_add_host_in_nfs_share_on_advhostmgmt_false(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'adv_host_mgmt_enabled': False,
+ 'read_only_root_hosts': [{'domain': MockNfsApi.DUMMY_DOMAIN_VALUE}, {'subnet': MockNfsApi.DUMMY_SUBNET_VALUE}],
+ 'host_state': 'present-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ utils.UnityNfsShareList = MagicMock
+ nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('add', False)
+ nfs_object.modify = MagicMock(return_value=None)
+ nfs_object.add_to_skip_list('modify')
+ fs_object = MockNfsApi.FILESYSTEM_OBJECT
+ get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('add', False)
+ nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object)
+ nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object)
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_remove_host_in_nfs_share_on_advhostmgmt_false(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'adv_host_mgmt_enabled': False,
+ 'read_only_root_hosts': [{'domain': MockNfsApi.DUMMY_DOMAIN_VALUE}, {'subnet': MockNfsApi.DUMMY_SUBNET_VALUE}],
+ 'host_state': 'absent-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ utils.UnityNfsShareList = MagicMock
+ nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('remove', False)
+ nfs_object.modify = MagicMock(return_value=None)
+ nfs_object.add_to_skip_list('modify')
+ fs_object = MockNfsApi.FILESYSTEM_OBJECT
+ get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('remove', False)
+ nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object)
+ nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object)
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_host_access_nfs_share_subnet_negative(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'adv_host_mgmt_enabled': False,
+ 'read_only_root_hosts': [{'subnet': "1x.x.x.x"}],
+ 'host_state': 'present-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ nfs_module_mock.get_filesystem = MagicMock(return_value=None)
+ nfs_module_mock.get_nfs_share = MagicMock(return_value=None)
+ nfs_module_mock.create_nfs_share = MagicMock(return_value=None)
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=None)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.fail_json.call_args[1]['msg'] == MockNfsApi.host_access_negative_response('subnet_validation')
+
+ def test_host_access_nfs_share_advhostmngmt_negative(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'read_only_root_hosts': [{'subnet': "1x.x.x.x/10"}],
+ 'host_state': 'present-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ nfs_module_mock.get_filesystem = MagicMock(return_value=None)
+ nfs_module_mock.get_nfs_share = MagicMock(return_value=None)
+ nfs_module_mock.create_nfs_share = MagicMock(return_value=None)
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=None)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.fail_json.call_args[1]['msg'] == MockNfsApi.host_access_negative_response('advhostmngmnt_field_validation')
+
+ def test_host_access_nfs_share_exception_negative(self, nfs_module_mock):
+ self.get_module_args.update({
+ 'nfs_export_name': "nfsshare_dummy_name",
+ 'filesystem_id': "fs_id_1",
+ 'adv_host_mgmt_enabled': False,
+ 'read_only_root_hosts': [{'domain': MockNfsApi.DUMMY_DOMAIN_VALUE}, {'subnet': MockNfsApi.DUMMY_SUBNET_VALUE}],
+ 'host_state': 'absent-in-export',
+ 'state': 'present'
+ })
+ nfs_module_mock.module.params = self.get_module_args
+ utils.UnityNfsShareList = MagicMock
+ nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('remove', False)
+ nfs_object.modify = MagicMock(side_effect=MockApiException)
+ nfs_object.add_to_skip_list('modify')
+ fs_object = MockNfsApi.FILESYSTEM_OBJECT
+ nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object)
+ nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object)
+ nfs.get_nfs_share_display_attrs = MagicMock(return_value=None)
+ nfs_module_mock.perform_module_operation()
+ assert nfs_module_mock.module.fail_json.call_args[1]['msg'] == MockNfsApi.host_access_negative_response('modify_exception')
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py
new file mode 100644
index 000000000..c2a680487
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py
@@ -0,0 +1,225 @@
+# 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 NFS server module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_nfsserver_api \
+ import MockNFSServerApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import HttpError as http_error, MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+utils.UnityNfsServer = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+from ansible_collections.dellemc.unity.plugins.modules.nfsserver import NFSServer
+
+
+class TestNFSServer():
+
+ get_module_args = MockNFSServerApi.NFS_SERVER_MODULE_ARGS
+
+ @pytest.fixture
+ def nfsserver_module_mock(self):
+ nfsserver_module_mock = NFSServer()
+ nfsserver_module_mock.unity_conn = MagicMock()
+ utils.nfsserver = MagicMock()
+ nfsserver_module_mock.module.check_mode = False
+ return nfsserver_module_mock
+
+ def test_get_nfs_server_details(self, nfsserver_module_mock):
+ self.get_module_args.update({
+ 'nfs_server_id': 'nfs_95',
+ 'state': 'present'
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ host_details = MockNFSServerApi.get_nas_server_id()
+ host_details.get_id = MagicMock(return_value="nas_10")
+ host_details.add_to_skip_list('get_id')
+ nfsserver_module_mock.unity_conn.get_nas_server = MagicMock(return_value=host_details)
+ nfsserver_module_mock.unity_conn.get_nfs_server = MagicMock(return_value=MockNFSServerApi.get_nfs_server_details()[0])
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.get_nfs_server_details_method_response() == \
+ nfsserver_module_mock.module.exit_json.call_args[1]['nfs_server_details']
+
+ def test_get_nfs_server_details_with_exception(self, nfsserver_module_mock):
+ self.get_module_args.update({
+ 'nas_server_name': 'test_nas_server',
+ 'state': 'present'
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ host_details = MockNFSServerApi.get_nas_server_id()
+ host_details.get_id = MagicMock(return_value="nas_10")
+ host_details.add_to_skip_list('get_id')
+ nfsserver_module_mock.unity_conn.get_nas_server = MagicMock(return_value=host_details)
+ utils.HttpError = http_error
+ nfsserver_module_mock.unity_conn.get_nfs_server = MagicMock(side_effect=http_error)
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.get_nfs_server_api_exception() == \
+ nfsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_nfs_server(self, nfsserver_module_mock):
+ self.get_module_args.update({
+ 'nas_server_name': 'dummy_name',
+ 'host_name': "dummy_nas23",
+ 'is_secure_enabled': True,
+ 'kerberos_domain_controller_type': "WINDOWS",
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'is_extended_credentials_enabled': False,
+ 'nfs_v4_enabled': True,
+ 'state': "present"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None)
+ utils.KdcTypeEnum = MagicMock(return_value={"KdcTypeEnum": {"description": "Windows", "name": "WINDOWS", "value": 2}})
+ utils.UnityNfsServer = MagicMock()
+ utils.UnityNfsServer.create = MagicMock(return_value=True)
+ nfsserver_module_mock.perform_module_operation()
+ assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_create_nfs_server_with_unix(self, nfsserver_module_mock):
+ self.get_module_args.update({
+ 'nas_server_name': 'dummy_name',
+ 'host_name': "dummy_nas23",
+ 'is_secure_enabled': True,
+ 'kerberos_domain_controller_type': "UNIX",
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'is_extended_credentials_enabled': False,
+ 'nfs_v4_enabled': True,
+ 'state': "present"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None)
+ utils.KdcTypeEnum = MagicMock(return_value={"KdcTypeEnum": {"description": "Windows", "name": "UNIX", "value": 1}})
+ utils.UnityNfsServer = MagicMock()
+ utils.UnityNfsServer.create = MagicMock(return_value=True)
+ nfsserver_module_mock.perform_module_operation()
+ assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_create_nfs_server_throws_exception(self, nfsserver_module_mock):
+ self.get_module_args.update({
+ 'nas_server_name': 'dummy_name',
+ 'host_name': "dummy_nas23",
+ 'is_secure_enabled': True,
+ 'kerberos_domain_controller_type': "WINDOWS",
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'is_extended_credentials_enabled': False,
+ 'nfs_v4_enabled': True,
+ 'state': "present"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None)
+ utils.UnityNfsServer = MagicMock()
+ utils.UnityNfsServer.create = MagicMock(side_effect=MockApiException)
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.create_nfs_server_with_api_exception() in nfsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_delete_nfs_server(self, nfsserver_module_mock):
+ nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response()
+ self.get_module_args.update({
+ 'nas_server_name': 'test_nas_server',
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'remove_spn_from_kerberos': True,
+ 'state': "absent"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details)
+ nfsserver_module_mock.perform_module_operation()
+ assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_delete_nfs_server_with_spn_false(self, nfsserver_module_mock):
+ nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response()
+ self.get_module_args.update({
+ 'nas_server_name': 'test_nas_server',
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'remove_spn_from_kerberos': False,
+ 'state': "absent"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details)
+ nfsserver_module_mock.perform_module_operation()
+ assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_delete_nfs_server_with_exception(self, nfsserver_module_mock):
+ nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response()
+ self.get_module_args.update({
+ 'nas_server_name': 'test_nas_server',
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'remove_spn_from_kerberos': False,
+ 'state': "absent"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details)
+ nfsserver_module_mock.unity_conn.get_nfs_server = MagicMock(side_effect=MockApiException)
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.delete_exception() in nfsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_is_modification_required(self, nfsserver_module_mock):
+ nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response()
+ self.get_module_args.update({
+ 'nas_server_name': 'test_nas_server',
+ 'is_extended_credentials_enabled': True,
+ 'state': 'present'
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details)
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.modify_error_msg() == nfsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_get_nas_server_id_exception(self, nfsserver_module_mock):
+ nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response()
+ self.get_module_args.update({
+ 'nas_server_name': 'dummy_name',
+ 'is_secure_enabled': True,
+ 'host_name': "dummy_nas23",
+ 'kerberos_domain_controller_type': "WINDOWS",
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'is_extended_credentials_enabled': False,
+ 'nfs_v4_enabled': True,
+ 'state': "present"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=MockApiException)
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details)
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.get_nas_server_id_api_exception() in \
+ nfsserver_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_nas_server_without_nas_server_id(self, nfsserver_module_mock):
+ self.get_module_args.update({
+ 'is_secure_enabled': True,
+ 'host_name': "dummy_nas23",
+ 'kerberos_domain_controller_type': "WINDOWS",
+ 'kerberos_domain_controller_username': "xxxxxxxx",
+ 'kerberos_domain_controller_password': "xxxxxxxx",
+ 'is_extended_credentials_enabled': False,
+ 'nfs_v4_enabled': True,
+ 'state': "present"
+ })
+ nfsserver_module_mock.module.params = self.get_module_args
+ nfsserver_module_mock.get_nas_server_id = MagicMock(return_value=None)
+ nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None)
+ nfsserver_module_mock.create_nfs_server = MagicMock(return_value=None)
+ nfsserver_module_mock.perform_module_operation()
+ assert MockNFSServerApi.create_nfs_server_without_nas_server_id() in \
+ nfsserver_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py
new file mode 100644
index 000000000..94bf18c35
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py
@@ -0,0 +1,132 @@
+# 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 host module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_storagepool_api \
+ import MockStoragePoolApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.storagepool import StoragePool
+
+
+class TestUnityStoragePool():
+
+ get_module_args = MockStoragePoolApi.STORAGE_POOL_MODULE_ARGS
+
+ @pytest.fixture
+ def storagepool_module_mock(self):
+ storagepool_module_mock = StoragePool()
+ storagepool_module_mock.conn = MagicMock()
+ return storagepool_module_mock
+
+ def test_get_host_details(self, storagepool_module_mock):
+ self.get_module_args.update({
+ 'pool_name': 'Ansible_Unity_TEST_1',
+ })
+ storagepool_module_mock.module.params = self.get_module_args
+ get_pool = MockSDKObject(MockStoragePoolApi.get_pool_details_response('get_pool'))
+ get_pool._get_property_from_raw = MagicMock(return_value=MockSDKObject({'is_schedule_enabled': True}))
+ get_pool.add_to_skip_list('_get_property_from_raw')
+ storagepool_module_mock.conn.get_pool = MagicMock(return_value=get_pool)
+ pool_object = MockStoragePoolApi.get_pool_details_response('pool_object')
+ utils.UnityPool = MagicMock()
+ utils.UnityPool.get = MagicMock(return_value=MockSDKObject(pool_object))
+ disk_list = MockStoragePoolApi.get_pool_details_response('disk_list')
+ utils.UnityDiskList = MagicMock()
+ utils.UnityDiskList.get = MagicMock(return_value=disk_list)
+ storagepool_module_mock.perform_module_operation()
+ assert MockStoragePoolApi.get_pool_details_response('module')['storage_pool_details'] == \
+ storagepool_module_mock.module.exit_json.call_args[1]['storage_pool_details']
+
+ def test_get_host_details_throws_exception(self, storagepool_module_mock):
+ self.get_module_args.update({
+ 'pool_name': 'Ansible_Unity_SP_3',
+ })
+ storagepool_module_mock.module.params = self.get_module_args
+ storagepool_module_mock.conn.get_pool = MagicMock(side_effect=MockApiException)
+ storagepool_module_mock.result = MagicMock()
+ storagepool_module_mock.get_pool_drives = MagicMock()
+ storagepool_module_mock.perform_module_operation()
+ storagepool_module_mock.is_pool_modification_required = MagicMock(return_value=False)
+ assert MockStoragePoolApi.get_pool_details_response('error') == storagepool_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_create_pool(self, storagepool_module_mock):
+ self.get_module_args.update({
+ 'pool_name': 'test_pool',
+ 'pool_description': 'Unity test pool.',
+ 'raid_groups': {
+ 'disk_group_id': "dg_16",
+ 'disk_num': 3,
+ 'raid_type': 'RAID10',
+ 'stripe_width': 'BEST_FIT',
+ },
+ 'alert_threshold': 50,
+ 'is_harvest_enabled': True,
+ 'pool_harvest_high_threshold': 59,
+ 'pool_harvest_low_threshold': 40,
+ 'is_snap_harvest_enabled': True,
+ 'snap_harvest_high_threshold': 80,
+ 'snap_harvest_low_threshold': 60,
+ 'fast_vp': "enabled",
+ 'fast_cache': "disabled",
+ 'pool_type': 'TRADITIONAL',
+ 'state': 'present'
+ })
+ storagepool_module_mock.module.params = self.get_module_args
+ storagepool_module_mock.get_raid_groups_response = MagicMock(return_value=None)
+ storagepool_module_mock.get_details = MagicMock(return_value=None)
+ pool_object = MockStoragePoolApi.create_pool_response('api')
+ utils.UnityPool = MagicMock()
+ utils.UnityPool.create = MagicMock(return_value=MockSDKObject(pool_object))
+ storagepool_module_mock.perform_module_operation()
+ assert storagepool_module_mock.module.exit_json.call_args[1]['changed']
+
+ def test_create_pool_throws_exception(self, storagepool_module_mock):
+ self.get_module_args.update({
+ 'pool_name': 'test_pool',
+ 'pool_description': 'Unity test pool.',
+ 'raid_groups': {
+ 'disk_group_id': "dg_16",
+ 'disk_num': 3,
+ 'raid_type': 'RAID10',
+ 'stripe_width': 'BEST_FIT',
+ },
+ 'alert_threshold': 50,
+ 'is_harvest_enabled': True,
+ 'pool_harvest_high_threshold': 59,
+ 'pool_harvest_low_threshold': 40,
+ 'is_snap_harvest_enabled': True,
+ 'snap_harvest_high_threshold': 80,
+ 'snap_harvest_low_threshold': 60,
+ 'fast_vp': "enabled",
+ 'fast_cache': "disabled",
+ 'pool_type': 'TRADITIONAL',
+ 'state': 'present'
+ })
+ storagepool_module_mock.module.params = self.get_module_args
+ storagepool_module_mock.get_details = MagicMock(return_value=None)
+ utils.UnityPool = MagicMock()
+ storagepool_module_mock.get_raid_groups_response = MagicMock(side_effect=MockApiException)
+ storagepool_module_mock.perform_module_operation()
+ assert MockStoragePoolApi.create_pool_response('error') in \
+ storagepool_module_mock.module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py
new file mode 100644
index 000000000..1081f8c07
--- /dev/null
+++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py
@@ -0,0 +1,128 @@
+# 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 volume module on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import pytest
+from mock.mock import MagicMock
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_volume_api \
+ import MockVolumeApi
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \
+ import MockSDKObject
+from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \
+ import MockApiException
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+
+utils.get_logger = MagicMock()
+utils.get_unity_management_host_parameters = MagicMock()
+utils.ensure_required_libs = MagicMock()
+utils.get_unity_unisphere_connection = MagicMock()
+utils.UnityPool = MagicMock()
+utils.UnityPool.get_size_in_gb = MagicMock()
+from ansible.module_utils import basic
+basic.AnsibleModule = MagicMock()
+
+from ansible_collections.dellemc.unity.plugins.modules.volume import Volume
+
+
+class TestUnityVolume():
+
+ get_module_args = MockVolumeApi.VOLUME_MODULE_ARGS
+
+ @pytest.fixture
+ def volume_module_mock(self):
+ volume_module_mock = Volume()
+ volume_module_mock.conn = MagicMock()
+ return volume_module_mock
+
+ def test_create_volume(self, volume_module_mock):
+ self.get_module_args.update({
+ 'vol_name': "Atest",
+ 'pool_name': "Extreme_Perf_tier",
+ 'size': 2,
+ 'cap_unit': "GB",
+ 'is_thin': True,
+ 'compression': True,
+ 'advanced_dedup': True,
+ 'state': 'present'
+ })
+ volume_module_mock.module.params = self.get_module_args
+ volume_module_mock.host_access_modify_required = MagicMock(return_value=False)
+ obj_pool = MockSDKObject(MockVolumeApi.pool)
+ volume_object = MockVolumeApi.create_volume_response('api')['volume_details']
+ volume_module_mock.unity_conn.get_pool = MagicMock(return_value=obj_pool)
+ volume_module_mock.unity_conn.get_lun = MagicMock(return_value=None)
+ obj_pool.create_lun = MagicMock(return_value=MockSDKObject(volume_object))
+ volume_module_mock.perform_module_operation()
+ assert volume_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_create_volume_exception(self, volume_module_mock):
+ self.get_module_args.update({
+ 'vol_name': "Atest",
+ 'pool_name': "Extreme_Perf_tier",
+ 'size': 2,
+ 'cap_unit': "GB",
+ 'is_thin': True,
+ 'compression': True,
+ 'advanced_dedup': True,
+ 'state': 'present'
+ })
+ volume_module_mock.module.params = self.get_module_args
+ volume_module_mock.host_access_modify_required = MagicMock(return_value=False)
+ obj_pool = MockSDKObject(MockVolumeApi.pool)
+ volume_module_mock.unity_conn.get_pool = MagicMock(return_value=obj_pool)
+ volume_module_mock.unity_conn.get_lun = MagicMock(return_value=None)
+ obj_pool.create_lun = MagicMock(side_effect=MockApiException)
+ volume_module_mock.perform_module_operation()
+ assert MockVolumeApi.create_volume_response('error') in \
+ volume_module_mock.module.fail_json.call_args[1]['msg']
+
+ def test_modify_volume(self, volume_module_mock):
+ self.get_module_args.update({
+ 'vol_name': "Atest",
+ 'pool_name': "Extreme_Perf_tier",
+ 'size': 2,
+ 'cap_unit': "GB",
+ 'is_thin': True,
+ 'compression': True,
+ 'advanced_dedup': False,
+ 'state': 'present'
+ })
+ volume_module_mock.module.params = self.get_module_args
+ volume_module_mock.host_access_modify_required = MagicMock(return_value=False)
+ obj_vol = MockSDKObject(MockVolumeApi.modify_volume_response('api')['volume_details'])
+ volume_object = MockVolumeApi.modify_volume_response('api')['volume_details']
+ volume_module_mock.unity_conn.get_lun = MagicMock(return_value=obj_vol)
+ obj_vol.modify = MagicMock(return_value=MockSDKObject(volume_object))
+ volume_module_mock.volume_modify_required = MagicMock()
+ volume_module_mock.get_volume_display_attributes = MagicMock()
+ volume_module_mock.perform_module_operation()
+ assert volume_module_mock.module.exit_json.call_args[1]['changed'] is True
+
+ def test_modify_volume_exception(self, volume_module_mock):
+ self.get_module_args.update({
+ 'vol_name': "Atest",
+ 'pool_name': "Extreme_Perf_tier",
+ 'size': 2,
+ 'cap_unit': "GB",
+ 'is_thin': True,
+ 'compression': True,
+ 'advanced_dedup': False,
+ 'state': 'present'
+ })
+ volume_module_mock.module.params = self.get_module_args
+ volume_module_mock.host_access_modify_required = MagicMock(return_value=False)
+ obj_vol = MockSDKObject(MockVolumeApi.modify_volume_response('api')['volume_details'])
+ volume_module_mock.unity_conn.get_lun = MagicMock(return_value=obj_vol)
+ obj_vol.modify = MagicMock(side_effect=MockApiException)
+ volume_module_mock.volume_modify_required = MagicMock()
+ volume_module_mock.get_volume_display_attributes = MagicMock()
+ volume_module_mock.perform_module_operation()
+ assert MockVolumeApi.modify_volume_response('error') in \
+ volume_module_mock.module.fail_json.call_args[1]['msg']