diff options
Diffstat (limited to 'ansible_collections/netapp/azure/tests/unit/plugins')
6 files changed, 1259 insertions, 0 deletions
diff --git a/ansible_collections/netapp/azure/tests/unit/plugins/module_utils/test_netapp_module.py b/ansible_collections/netapp/azure/tests/unit/plugins/module_utils/test_netapp_module.py new file mode 100644 index 000000000..fb83c464e --- /dev/null +++ b/ansible_collections/netapp/azure/tests/unit/plugins/module_utils/test_netapp_module.py @@ -0,0 +1,149 @@ +# Copyright (c) 2018 NetApp +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +''' unit tests for module_utils netapp_module.py ''' +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible_collections.netapp.azure.tests.unit.compat import unittest +from ansible_collections.netapp.azure.plugins.module_utils.netapp_module import NetAppModule as na_helper + + +class TestMyModule(unittest.TestCase): + ''' a group of related Unit Tests ''' + + def test_get_cd_action_create(self): + ''' validate cd_action for create ''' + current = None + desired = {'state': 'present'} + my_obj = na_helper() + result = my_obj.get_cd_action(current, desired) + assert result == 'create' + + def test_get_cd_action_delete(self): + ''' validate cd_action for delete ''' + current = {'state': 'absent'} + desired = {'state': 'absent'} + my_obj = na_helper() + result = my_obj.get_cd_action(current, desired) + assert result == 'delete' + + def test_get_cd_action(self): + ''' validate cd_action for returning None ''' + current = None + desired = {'state': 'absent'} + my_obj = na_helper() + result = my_obj.get_cd_action(current, desired) + assert result is None + + def test_get_modified_attributes_for_no_data(self): + ''' validate modified attributes when current is None ''' + current = None + desired = {'name': 'test'} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired) + assert result == {} + + def test_get_modified_attributes(self): + ''' validate modified attributes ''' + current = {'name': ['test', 'abcd', 'xyz', 'pqr'], 'state': 'present'} + desired = {'name': ['abcd', 'abc', 'xyz', 'pqr'], 'state': 'absent'} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired) + assert result == desired + + def test_get_modified_attributes_for_intersecting_mixed_list(self): + ''' validate modified attributes for list diff ''' + current = {'name': [2, 'four', 'six', 8]} + desired = {'name': ['a', 8, 'ab', 'four', 'abcd']} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {'name': ['a', 'ab', 'abcd']} + + def test_get_modified_attributes_for_intersecting_list(self): + ''' validate modified attributes for list diff ''' + current = {'name': ['two', 'four', 'six', 'eight']} + desired = {'name': ['a', 'six', 'ab', 'four', 'abc']} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {'name': ['a', 'ab', 'abc']} + + def test_get_modified_attributes_for_nonintersecting_list(self): + ''' validate modified attributes for list diff ''' + current = {'name': ['two', 'four', 'six', 'eight']} + desired = {'name': ['a', 'ab', 'abd']} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {'name': ['a', 'ab', 'abd']} + + def test_get_modified_attributes_for_list_of_dicts_no_data(self): + ''' validate modified attributes for list diff ''' + current = None + desired = {'address_blocks': [{'start': '10.20.10.40', 'size': 5}]} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {} + + def test_get_modified_attributes_for_intersecting_list_of_dicts(self): + ''' validate modified attributes for list diff ''' + current = {'address_blocks': [{'start': '10.10.10.23', 'size': 5}, {'start': '10.10.10.30', 'size': 5}]} + desired = {'address_blocks': [{'start': '10.10.10.23', 'size': 5}, {'start': '10.10.10.30', 'size': 5}, {'start': '10.20.10.40', 'size': 5}]} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {'address_blocks': [{'start': '10.20.10.40', 'size': 5}]} + + def test_get_modified_attributes_for_nonintersecting_list_of_dicts(self): + ''' validate modified attributes for list diff ''' + current = {'address_blocks': [{'start': '10.10.10.23', 'size': 5}, {'start': '10.10.10.30', 'size': 5}]} + desired = {'address_blocks': [{'start': '10.20.10.23', 'size': 5}, {'start': '10.20.10.30', 'size': 5}, {'start': '10.20.10.40', 'size': 5}]} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {'address_blocks': [{'start': '10.20.10.23', 'size': 5}, {'start': '10.20.10.30', 'size': 5}, {'start': '10.20.10.40', 'size': 5}]} + + def test_get_modified_attributes_for_list_diff(self): + ''' validate modified attributes for list diff ''' + current = {'name': ['test', 'abcd'], 'state': 'present'} + desired = {'name': ['abcd', 'abc'], 'state': 'present'} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired, True) + assert result == {'name': ['abc']} + + def test_get_modified_attributes_for_no_change(self): + ''' validate modified attributes for same data in current and desired ''' + current = {'name': 'test'} + desired = {'name': 'test'} + my_obj = na_helper() + result = my_obj.get_modified_attributes(current, desired) + assert result == {} + + def test_is_rename_action_for_empty_input(self): + ''' validate rename action for input None ''' + source = None + target = None + my_obj = na_helper() + result = my_obj.is_rename_action(source, target) + assert result == source + + def test_is_rename_action_for_no_source(self): + ''' validate rename action when source is None ''' + source = None + target = 'test2' + my_obj = na_helper() + result = my_obj.is_rename_action(source, target) + assert result is False + + def test_is_rename_action_for_no_target(self): + ''' validate rename action when target is None ''' + source = 'test2' + target = None + my_obj = na_helper() + result = my_obj.is_rename_action(source, target) + assert result is True + + def test_is_rename_action(self): + ''' validate rename action ''' + source = 'test' + target = 'test2' + my_obj = na_helper() + result = my_obj.is_rename_action(source, target) + assert result is False diff --git a/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_account.py b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_account.py new file mode 100644 index 000000000..0d140b4a0 --- /dev/null +++ b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_account.py @@ -0,0 +1,173 @@ +# (c) 2019, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +''' unit tests ONTAP Ansible module: azure_rm_netapp_account''' + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import sys + +import pytest +try: + from requests import Response +except ImportError: + if sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.azure.tests.unit.compat import unittest +from ansible_collections.netapp.azure.tests.unit.compat.mock import patch, Mock + +HAS_AZURE_RMNETAPP_IMPORT = True +try: + # At this point, python believes the module is already loaded, so the import inside azure_rm_netapp_volume will be skipped. + from ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_account \ + import AzureRMNetAppAccount as account_module +except ImportError: + HAS_AZURE_RMNETAPP_IMPORT = False + +HAS_AZURE_CLOUD_ERROR_IMPORT = True +try: + from msrestazure.azure_exceptions import CloudError +except ImportError: + HAS_AZURE_CLOUD_ERROR_IMPORT = False + +if not HAS_AZURE_CLOUD_ERROR_IMPORT and sys.version_info < (3, 5): + pytestmark = pytest.mark.skip('skipping as missing required azure_exceptions on 2.6 and 2.7') + + +def set_module_args(args): + """prepare arguments so that they will be picked up during module creation""" + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) # pylint: disable=protected-access + + +class AnsibleExitJson(Exception): + """Exception class to be raised by module.exit_json and caught by the test case""" + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + + +def exit_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over exit_json; package return data into an exception""" + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + +def fail_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +class MockAzureClient(object): + ''' mock server connection to ONTAP host ''' + def __init__(self): + ''' save arguments ''' + self.valid_accounts = ['test1', 'test2'] + + def get(self, resource_group, account_name): # pylint: disable=unused-argument + if account_name not in self.valid_accounts: + invalid = Response() + invalid.status_code = 404 + raise CloudError(response=invalid) + return Mock(name=account_name) + + def create_or_update(self, body, resource_group, account_name): # pylint: disable=unused-argument,no-self-use + return None + + +class TestMyModule(unittest.TestCase): + ''' a group of related Unit Tests ''' + + def setUp(self): + self.mock_module_helper = patch.multiple(basic.AnsibleModule, + exit_json=exit_json, + fail_json=fail_json) + self.mock_module_helper.start() + self.addCleanup(self.mock_module_helper.stop) + self.netapp_client = Mock() + self.netapp_client.accounts = MockAzureClient() + self._netapp_client = None + + def set_default_args(self): + resource_group = 'azure' + name = 'test1' + location = 'abc' + return dict({ + 'resource_group': resource_group, + 'name': name, + 'location': location + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + account_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_get_called_valid_account(self, client_f): + set_module_args(self.set_default_args()) + client_f.return_value = Mock() + client_f.side_effect = Mock() + my_obj = account_module() + my_obj.netapp_client.accounts = self.netapp_client.accounts + assert my_obj.get_azure_netapp_account() is not None + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_get_called_non_existing_account(self, client_f): + data = self.set_default_args() + data['name'] = 'invalid' + set_module_args(data) + client_f.return_value = Mock() + client_f.side_effect = Mock() + my_obj = account_module() + my_obj.netapp_client.accounts = self.netapp_client.accounts + assert my_obj.get_azure_netapp_account() is None + + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_account.AzureRMNetAppAccount.get_azure_netapp_account') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_account.AzureRMNetAppAccount.create_azure_netapp_account') + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_create_called(self, client_f, mock_create, mock_get): + data = dict(self.set_default_args()) + data['name'] = 'create' + data['tags'] = {'ttt': 'tesssttt', 'abc': 'xyz'} + set_module_args(data) + mock_get.return_value = None + client_f.return_value = Mock() + client_f.side_effect = Mock() + my_obj = account_module() + my_obj.netapp_client.accounts = self.netapp_client.accounts + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_create.assert_called_with() + + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_account.AzureRMNetAppAccount.get_azure_netapp_account') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_account.AzureRMNetAppAccount.delete_azure_netapp_account') + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_delete_called(self, client_f, mock_delete, mock_get): + data = dict(self.set_default_args()) + data['state'] = 'absent' + set_module_args(data) + mock_get.return_value = Mock() + client_f.return_value = Mock() + client_f.side_effect = Mock() + my_obj = account_module() + my_obj.netapp_client.accounts = self.netapp_client.accounts + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_delete.assert_called_with() diff --git a/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_capacity_pool.py b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_capacity_pool.py new file mode 100644 index 000000000..91c8eefd6 --- /dev/null +++ b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_capacity_pool.py @@ -0,0 +1,197 @@ +# (c) 2019, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +''' unit tests ONTAP Ansible module: azure_rm_netapp_capacity_pool''' + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import sys + +import pytest +try: + from requests import Response +except ImportError: + if sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.azure.tests.unit.compat import unittest +from ansible_collections.netapp.azure.tests.unit.compat.mock import patch, Mock + +HAS_AZURE_RMNETAPP_IMPORT = True +try: + # At this point, python believes the module is already loaded, so the import inside azure_rm_netapp_volume will be skipped. + from ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool \ + import AzureRMNetAppCapacityPool as capacity_pool_module +except ImportError: + HAS_AZURE_RMNETAPP_IMPORT = False + +HAS_AZURE_CLOUD_ERROR_IMPORT = True +try: + from msrestazure.azure_exceptions import CloudError +except ImportError: + HAS_AZURE_CLOUD_ERROR_IMPORT = False + +if not HAS_AZURE_CLOUD_ERROR_IMPORT and sys.version_info < (3, 5): + pytestmark = pytest.mark.skip('skipping as missing required azure_exceptions on 2.6 and 2.7') + + +def set_module_args(args): + """prepare arguments so that they will be picked up during module creation""" + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) # pylint: disable=protected-access + + +class AnsibleExitJson(Exception): + """Exception class to be raised by module.exit_json and caught by the test case""" + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + + +def exit_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over exit_json; package return data into an exception""" + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + +def fail_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +class MockAzureClient(object): + ''' mock server connection to ONTAP host ''' + def __init__(self): + ''' save arguments ''' + self.valid_pools = ['test1', 'test2'] + + def get(self, resource_group, account_name, pool_name): # pylint: disable=unused-argument + if pool_name not in self.valid_pools: + invalid = Response() + invalid.status_code = 404 + raise CloudError(response=invalid) + else: + return Mock(name=pool_name) + + def create_or_update(self, body, resource_group, account_name, pool_name): # pylint: disable=unused-argument + return None + + def update(self, body, resource_group, account_name, pool_name): # pylint: disable=unused-argument + return None + + +class TestMyModule(unittest.TestCase): + ''' a group of related Unit Tests ''' + + def setUp(self): + self.mock_module_helper = patch.multiple(basic.AnsibleModule, + exit_json=exit_json, + fail_json=fail_json) + self.mock_module_helper.start() + self.addCleanup(self.mock_module_helper.stop) + self.netapp_client = Mock() + self.netapp_client.pools = MockAzureClient() + self._netapp_client = None + + def set_default_args(self): + resource_group = 'azure' + account_name = 'azure' + name = 'test1' + location = 'abc' + size = 1 + service_level = 'Standard' + return dict({ + 'resource_group': resource_group, + 'account_name': account_name, + 'name': name, + 'location': location, + 'size': size, + 'service_level': service_level + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + capacity_pool_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_get_called_valid_capacity_pool(self, client_f): + set_module_args(self.set_default_args()) + client_f.return_value = Mock() + my_obj = capacity_pool_module() + my_obj.netapp_client.pools = self.netapp_client.pools + assert my_obj.get_azure_netapp_capacity_pool() is not None + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_get_called_non_existing_capacity_pool(self, client_f): + data = self.set_default_args() + data['name'] = 'invalid' + set_module_args(data) + client_f.return_value = Mock() + my_obj = capacity_pool_module() + my_obj.netapp_client.pools = self.netapp_client.pools + assert my_obj.get_azure_netapp_capacity_pool() is None + + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool.AzureRMNetAppCapacityPool.get_azure_netapp_capacity_pool') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool.AzureRMNetAppCapacityPool.create_azure_netapp_capacity_pool') + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_create_called(self, client_f, mock_create, mock_get): + data = dict(self.set_default_args()) + data['name'] = 'create' + set_module_args(data) + mock_get.return_value = None + client_f.return_value = Mock() + my_obj = capacity_pool_module() + my_obj.netapp_client.pools = self.netapp_client.pools + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_create.assert_called_with() + + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool.AzureRMNetAppCapacityPool.get_azure_netapp_capacity_pool') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool.AzureRMNetAppCapacityPool.create_azure_netapp_capacity_pool') + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_modify_called(self, client_f, mock_modify, mock_get): + data = dict(self.set_default_args()) + data['name'] = 'create' + data['size'] = 3 + set_module_args(data) + mock_get.return_value = None + client_f.return_value = Mock() + my_obj = capacity_pool_module() + my_obj.netapp_client.pools = self.netapp_client.pools + with pytest.raises(AnsibleExitJson) as exc: + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_modify.assert_called_with() + + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool.AzureRMNetAppCapacityPool.get_azure_netapp_capacity_pool') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_capacity_pool.AzureRMNetAppCapacityPool.delete_azure_netapp_capacity_pool') + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_delete_called(self, client_f, mock_delete, mock_get): + data = self.set_default_args() + data['state'] = 'absent' + set_module_args(data) + mock_get.return_value = Mock() + client_f.return_value = Mock() + my_obj = capacity_pool_module() + my_obj.netapp_client.pools = self.netapp_client.pools + with pytest.raises(AnsibleExitJson) as exc: + data['state'] = 'absent' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_delete.assert_called_with() diff --git a/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_snapshot.py b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_snapshot.py new file mode 100644 index 000000000..0415a4039 --- /dev/null +++ b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_snapshot.py @@ -0,0 +1,165 @@ +# (c) 2019, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +''' unit tests ONTAP Ansible module: azure_rm_netapp_snapshot''' + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import sys + +import pytest +try: + from requests import Response +except ImportError: + if sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.azure.tests.unit.compat import unittest +from ansible_collections.netapp.azure.tests.unit.compat.mock import patch, Mock + +HAS_AZURE_RMNETAPP_IMPORT = True +try: + # At this point, python believes the module is already loaded, so the import inside azure_rm_netapp_volume will be skipped. + from ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_snapshot \ + import AzureRMNetAppSnapshot as snapshot_module +except ImportError: + HAS_AZURE_RMNETAPP_IMPORT = False + +HAS_AZURE_CLOUD_ERROR_IMPORT = True +try: + from msrestazure.azure_exceptions import CloudError +except ImportError: + HAS_AZURE_CLOUD_ERROR_IMPORT = False + +if not HAS_AZURE_CLOUD_ERROR_IMPORT and sys.version_info < (3, 5): + pytestmark = pytest.mark.skip('skipping as missing required azure_exceptions on 2.6 and 2.7') + + +def set_module_args(args): + """prepare arguments so that they will be picked up during module creation""" + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) # pylint: disable=protected-access + + +class AnsibleExitJson(Exception): + """Exception class to be raised by module.exit_json and caught by the test case""" + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + + +def exit_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over exit_json; package return data into an exception""" + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + +def fail_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +class MockAzureClient(object): + ''' mock server connection to ONTAP host ''' + def __init__(self): + ''' save arguments ''' + self.valid_snapshots = ['test1', 'test2'] + + def get(self, resource_group, account_name, pool_name, volume_name, snapshot_name): # pylint: disable=unused-argument + if snapshot_name not in self.valid_snapshots: + invalid = Response() + invalid.status_code = 404 + raise CloudError(response=invalid) + else: + return Mock(name=snapshot_name) + + def create(self, body, resource_group, account_name, pool_name, volume_name, snapshot_name): # pylint: disable=unused-argument + return None + + +class TestMyModule(unittest.TestCase): + ''' a group of related Unit Tests ''' + + def setUp(self): + self.mock_module_helper = patch.multiple(basic.AnsibleModule, + exit_json=exit_json, + fail_json=fail_json) + self.mock_module_helper.start() + self.addCleanup(self.mock_module_helper.stop) + self.netapp_client = Mock() + self.netapp_client.pools = MockAzureClient() + self._netapp_client = None + + def set_default_args(self): + resource_group = 'azure' + account_name = 'azure' + pool_name = 'azure' + volume_name = 'azure' + name = 'test1' + location = 'abc' + return dict({ + 'resource_group': resource_group, + 'account_name': account_name, + 'pool_name': pool_name, + 'volume_name': volume_name, + 'name': name, + 'location': location + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + snapshot_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + def test_ensure_get_called_valid_snapshot(self, client_f): + set_module_args(self.set_default_args()) + client_f.return_value = Mock() + my_obj = snapshot_module() + my_obj.netapp_client.snapshots = self.netapp_client.snapshots + assert my_obj.get_azure_netapp_snapshot() is not None + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_snapshot.AzureRMNetAppSnapshot.get_azure_netapp_snapshot') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_snapshot.AzureRMNetAppSnapshot.create_azure_netapp_snapshot') + def test_ensure_create_called(self, mock_create, mock_get, client_f): + data = dict(self.set_default_args()) + data['name'] = 'create' + set_module_args(data) + mock_get.return_value = None + client_f.return_value = Mock() + my_obj = snapshot_module() + my_obj.netapp_client.snapshots = self.netapp_client.snapshots + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_create.assert_called_with() + + @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_snapshot.AzureRMNetAppSnapshot.get_azure_netapp_snapshot') + @patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_snapshot.AzureRMNetAppSnapshot.delete_azure_netapp_snapshot') + def test_ensure_delete_called(self, mock_delete, mock_get, client_f): + data = dict(self.set_default_args()) + data['state'] = 'absent' + set_module_args(data) + client_f.return_value = Mock() + mock_get.return_value = Mock() + my_obj = snapshot_module() + my_obj.netapp_client.snapshots = self.netapp_client.snapshots + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_delete.assert_called_with() diff --git a/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume.py b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume.py new file mode 100644 index 000000000..83c7f812e --- /dev/null +++ b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume.py @@ -0,0 +1,501 @@ +# (c) 2019, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +''' unit tests ONTAP Ansible module: azure_rm_netapp_volume''' + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import sys + +import pytest +try: + from requests import Response +except ImportError: + if sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.azure.tests.unit.compat.mock import patch, Mock + +HAS_AZURE_RMNETAPP_IMPORT = True +try: + # At this point, python believes the module is already loaded, so the import inside azure_rm_netapp_volume will be skipped. + from ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume \ + import AzureRMNetAppVolume as volume_module +except ImportError: + HAS_AZURE_RMNETAPP_IMPORT = False + +HAS_AZURE_CLOUD_ERROR_IMPORT = True +try: + from msrestazure.azure_exceptions import CloudError +except ImportError: + HAS_AZURE_CLOUD_ERROR_IMPORT = False + +if not HAS_AZURE_CLOUD_ERROR_IMPORT and sys.version_info < (3, 5): + pytestmark = pytest.mark.skip('skipping as missing required azure_exceptions on 2.6 and 2.7') + + +def set_module_args(args): + """prepare arguments so that they will be picked up during module creation""" + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) # pylint: disable=protected-access + + +class AnsibleExitJson(Exception): + """Exception class to be raised by module.exit_json and caught by the test case""" + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + + +def exit_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over exit_json; package return data into an exception""" + if 'changed' not in kwargs: + kwargs['changed'] = False + raise AnsibleExitJson(kwargs) + + +def fail_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +class MockAzureClient(object): + ''' mock server connection to ONTAP host ''' + def __init__(self): + ''' save arguments ''' + self.valid_volumes = ['test1', 'test2'] + + def get(self, resource_group, account_name, pool_name, volume_name): # pylint: disable=unused-argument + if volume_name in self.valid_volumes: + return Mock(name=volume_name, + subnet_id='/resid/whatever/subnet_name', + mount_targets=[Mock(ip_address='1.2.3.4')] + ) + + invalid = Response() + invalid.status_code = 404 + raise CloudError(response=invalid) + + def create_or_update(self, body, resource_group, account_name, pool_name, volume_name): # pylint: disable=unused-argument + return None + + def begin_create_or_update(self, body, resource_group_name, account_name, pool_name, volume_name): # pylint: disable=unused-argument + return Mock(done=Mock(side_effect=[False, True])) + + def begin_update(self, body, resource_group_name, account_name, pool_name, volume_name): # pylint: disable=unused-argument + return Mock(done=Mock(side_effect=[False, True])) + + def begin_delete(self, resource_group_name, account_name, pool_name, volume_name): # pylint: disable=unused-argument + return Mock(done=Mock(side_effect=[False, True])) + + +class MockAzureClientRaise(MockAzureClient): + ''' mock server connection to ONTAP host ''' + response = Mock(status_code=400, context=None, headers=[], text=lambda: 'Forced exception') + + def begin_create_or_update(self, body, resource_group_name, account_name, pool_name, volume_name): # pylint: disable=unused-argument + raise CloudError(MockAzureClientRaise.response) + + def begin_update(self, body, resource_group_name, account_name, pool_name, volume_name): # pylint: disable=unused-argument + raise CloudError(MockAzureClientRaise.response) + + def begin_delete(self, resource_group_name, account_name, pool_name, volume_name): # pylint: disable=unused-argument + raise CloudError(MockAzureClientRaise.response) + + +# using pytest natively, without unittest.TestCase +@pytest.fixture(name="patch_ansible") +def fixture_patch_ansible(): + with patch.multiple(basic.AnsibleModule, + exit_json=exit_json, + fail_json=fail_json) as mocks: + yield mocks + + +def set_default_args(): + resource_group = 'azure' + account_name = 'azure' + pool_name = 'azure' + name = 'test1' + location = 'abc' + file_path = 'azure' + subnet_id = 'azure' + virtual_network = 'azure' + size = 100 + return dict({ + 'resource_group': resource_group, + 'account_name': account_name, + 'pool_name': pool_name, + 'name': name, + 'location': location, + 'file_path': file_path, + 'subnet_name': subnet_id, + 'virtual_network': virtual_network, + 'size': size, + 'protocol_types': 'nfs', + 'tags': {'owner': 'laurentn'} + }) + + +def test_module_fail_when_required_args_missing(patch_ansible): # pylint: disable=unused-argument + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + volume_module() + print('Info: %s' % exc.value.args[0]['msg']) + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +def test_ensure_get_called_valid_volume(client_f): + set_module_args(set_default_args()) + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + assert my_obj.get_azure_netapp_volume() is not None + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +def test_ensure_get_called_non_existing_volume(client_f): + data = dict(set_default_args()) + data['name'] = 'invalid' + set_module_args(data) + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + assert my_obj.get_azure_netapp_volume() is None + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.create_azure_netapp_volume') +def test_ensure_create_called(mock_create, mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'create' + set_module_args(data) + mock_get.side_effect = [ + None, # first get + dict(mount_targets=[dict(ip_address='11.22.33.44')], # get after create + creation_token='abcd') + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + expected_mount_path = '11.22.33.44:/abcd' + assert exc.value.args[0]['mount_path'] == expected_mount_path + mock_create.assert_called_with() + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_create(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'create' + data['protocol_types'] = ['nfsv4.1'] + set_module_args(data) + mock_get.side_effect = [ + None, # first get + dict(mount_targets=[dict(ip_address='11.22.33.44')], # get after create + creation_token='abcd') + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + expected_mount_path = '11.22.33.44:/abcd' + assert exc.value.args[0]['mount_path'] == expected_mount_path + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_create_exception(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'create' + data['protocol_types'] = 'nfsv4.1' + set_module_args(data) + mock_get.side_effect = [ + None, # first get + dict(mount_targets=[dict(ip_address='11.22.33.44')], # get after create + creation_token='abcd') + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClientRaise() + with pytest.raises(AnsibleFailJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + expected_msg = 'Error creating volume' + assert expected_msg in exc.value.args[0]['msg'] + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.create_azure_netapp_volume') +def test_ensure_create_called_but_fail_on_get(mock_create, mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'create' + set_module_args(data) + mock_get.side_effect = [ + None, # first get + dict(mount_targets=None, # get after create + creation_token='abcd') + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleFailJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + error = 'Error: volume create was created successfully, but mount target(s) cannot be found - volume details:' + assert exc.value.args[0]['msg'].startswith(error) + mock_create.assert_called_with() + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.create_azure_netapp_volume') +def test_ensure_create_called_but_fail_on_mount_target(mock_create, mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'create' + set_module_args(data) + mock_get.return_value = None + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleFailJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + error = 'Error: volume create was created successfully, but cannot be found.' + assert exc.value.args[0]['msg'] == error + mock_create.assert_called_with() + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.delete_azure_netapp_volume') +def test_ensure_delete_called(mock_delete, mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['state'] = 'absent' + set_module_args(data) + client_f.return_value = Mock() + mock_get.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + mock_delete.assert_called_with() + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_delete(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'delete' + data['state'] = 'absent' + set_module_args(data) + mock_get.side_effect = [ + dict(mount_targets=[dict(ip_address='11.22.33.44')], # first get + creation_token='abcd') + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + expected_mount_path = '' + assert exc.value.args[0]['mount_path'] == expected_mount_path + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_delete_exception(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'delete' + data['state'] = 'absent' + set_module_args(data) + mock_get.side_effect = [ + dict(mount_targets=[dict(ip_address='11.22.33.44')], # first get + creation_token='abcd') + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClientRaise() + with pytest.raises(AnsibleFailJson) as exc: + # add default args for exec_module + data['debug'] = False + my_obj.exec_module(**data) + expected_msg = 'Error deleting volume' + assert expected_msg in exc.value.args[0]['msg'] + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_modify(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'modify' + data['size'] = 200 + data['tags'] = {'added_tag': 'new_tag'} + set_module_args(data) + mock_get.side_effect = [ + dict(mount_targets=[dict(ip_address='11.22.33.44')], # first get + creation_token='abcd', + tags={}, + usage_threshold=0), + dict(mount_targets=[dict(ip_address='11.22.33.44')], # get after modify + creation_token='abcd', + usage_threshold=10000000) + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleExitJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + assert exc.value.args[0]['changed'] + print('modify', exc.value.args[0]) + expected_mount_path = '11.22.33.44:/abcd' + assert exc.value.args[0]['mount_path'] == expected_mount_path + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_modify_exception(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'modify' + data['size'] = 200 + set_module_args(data) + mock_get.side_effect = [ + dict(mount_targets=[dict(ip_address='11.22.33.44')], # first get + creation_token='abcd', + usage_threshold=0), + dict(mount_targets=[dict(ip_address='11.22.33.44')], # get after modify + creation_token='abcd', + usage_threshold=10000000) + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClientRaise() + with pytest.raises(AnsibleFailJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + expected_msg = 'Error modifying volume' + assert expected_msg in exc.value.args[0]['msg'] + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +@patch('ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume.AzureRMNetAppVolume.get_azure_netapp_volume') +def test_modify_not_supported(mock_get, client_f, patch_ansible): # pylint: disable=unused-argument + data = dict(set_default_args()) + data['name'] = 'modify' + data['location'] = 'east' + set_module_args(data) + mock_get.side_effect = [ + dict(mount_targets=[dict(ip_address='11.22.33.44')], # first get + creation_token='abcd', + usage_threshold=0, + location='west', + name='old_name'), + dict(mount_targets=[dict(ip_address='11.22.33.44')], # get after modify + creation_token='abcd', + usage_threshold=10000000) + ] + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.azure_auth = Mock(subscription_id='1234') + my_obj._new_style = True + my_obj.netapp_client.volumes = MockAzureClient() + with pytest.raises(AnsibleFailJson) as exc: + # add default args for exec_module + data['state'] = 'present' + data['debug'] = False + my_obj.exec_module(**data) + expected_msg = "Error: the following properties cannot be modified: {'location': 'east'}" + assert expected_msg in exc.value.args[0]['msg'] + + +@patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.netapp_client') +def test_get_export_policy_rules(client_f, patch_ansible): + set_module_args(set_default_args()) + client_f.return_value = Mock() + my_obj = volume_module() + my_obj.netapp_client.volumes = MockAzureClient() + rules = my_obj.get_export_policy_rules() + assert rules is None + del my_obj.parameters['protocol_types'] + rules = my_obj.get_export_policy_rules() + assert rules is None + my_obj.parameters['protocol_types'] = ['nFsv4.1'] + rules = my_obj.get_export_policy_rules() + assert rules is not None + rules = vars(rules) + assert 'rules' in rules + rules = rules['rules'] + assert rules + rule = vars(rules[0]) + assert rule['nfsv41'] + assert not rule['cifs'] + + +def test_dict_from_object(): + set_module_args(set_default_args()) + my_obj = volume_module() + # just for fun + module_dict = my_obj.dict_from_volume_object(my_obj) + print('Module dict', module_dict) + + rule_object = Mock() + rule_object.ip_address = '10.10.10.10' + export_policy_object = Mock() + export_policy_object.rules = [rule_object] + volume_object = Mock() + volume_object.export_policy = export_policy_object + volume_dict = my_obj.dict_from_volume_object(volume_object) + print('Volume dict', volume_dict) + assert 'export_policy' in volume_dict + assert 'rules' in volume_dict['export_policy'] + assert isinstance(volume_dict['export_policy']['rules'], list) + assert len(volume_dict['export_policy']['rules']) == 1 + assert 'ip_address' in volume_dict['export_policy']['rules'][0] diff --git a/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume_import.py b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume_import.py new file mode 100644 index 000000000..13d3bba29 --- /dev/null +++ b/ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume_import.py @@ -0,0 +1,74 @@ +# (c) 2021, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +''' unit tests ONTAP Ansible module: azure_rm_netapp_volume''' + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import sys + +import pytest +# from typing import Collection +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.azure.tests.unit.compat.mock import patch + + +if sys.version_info < (3, 5): + pytestmark = pytest.mark.skip('skipping as missing imports on 2.6 and 2.7') + + +def set_module_args(args): + """prepare arguments so that they will be picked up during module creation""" + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) # pylint: disable=protected-access + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + + +def fail_json(*args, **kwargs): # pylint: disable=unused-argument + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +@pytest.fixture(name="patch_ansible") +def fixture_patch_ansible(): + with patch.multiple(basic.AnsibleModule, + fail_json=fail_json) as mocks: + yield mocks + + +# @patch('ansible_collections.netapp.azure.plugins.module_utils.azure_rm_netapp_common.AzureRMNetAppModuleBase.__init__') +def test_import_error(): + orig_import = __import__ + + def import_mock(name, *args): + print('importing: %s' % name) + if name.startswith('ansible_collections.netapp.azure.plugins.modules'): + # force a relead to go through secondary imports + sys.modules.pop(name, None) + if name in ('azure.core.exceptions', 'azure.mgmt.netapp.models'): + raise ImportError('forced error on %s' % name) + return orig_import(name, *args) + + # mock_base.return_value = Mock() + data = dict() + set_module_args(data) + with patch('builtins.__import__', side_effect=import_mock): + from ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume import IMPORT_ERRORS + assert any('azure.core.exceptions' in error for error in IMPORT_ERRORS) + assert any('azure.mgmt.netapp.models' in error for error in IMPORT_ERRORS) + + +def test_main(patch_ansible): # pylint: disable=unused-argument + data = dict() + set_module_args(data) + from ansible_collections.netapp.azure.plugins.modules.azure_rm_netapp_volume import main + with pytest.raises(AnsibleFailJson) as exc: + main() + expected_msg = "missing required arguments:" + assert expected_msg in exc.value.args[0]['msg'] |