summaryrefslogtreecommitdiffstats
path: root/ansible_collections/netapp/azure/tests/unit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/netapp/azure/tests/unit
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/netapp/azure/tests/unit')
-rw-r--r--ansible_collections/netapp/azure/tests/unit/compat/__init__.py0
-rw-r--r--ansible_collections/netapp/azure/tests/unit/compat/builtins.py33
-rw-r--r--ansible_collections/netapp/azure/tests/unit/compat/mock.py122
-rw-r--r--ansible_collections/netapp/azure/tests/unit/compat/unittest.py44
-rw-r--r--ansible_collections/netapp/azure/tests/unit/plugins/module_utils/test_netapp_module.py149
-rw-r--r--ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_account.py173
-rw-r--r--ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_capacity_pool.py197
-rw-r--r--ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_snapshot.py165
-rw-r--r--ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume.py501
-rw-r--r--ansible_collections/netapp/azure/tests/unit/plugins/modules/test_azure_rm_netapp_volume_import.py74
-rw-r--r--ansible_collections/netapp/azure/tests/unit/requirements.txt3
11 files changed, 1461 insertions, 0 deletions
diff --git a/ansible_collections/netapp/azure/tests/unit/compat/__init__.py b/ansible_collections/netapp/azure/tests/unit/compat/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/netapp/azure/tests/unit/compat/__init__.py
diff --git a/ansible_collections/netapp/azure/tests/unit/compat/builtins.py b/ansible_collections/netapp/azure/tests/unit/compat/builtins.py
new file mode 100644
index 000000000..f60ee6782
--- /dev/null
+++ b/ansible_collections/netapp/azure/tests/unit/compat/builtins.py
@@ -0,0 +1,33 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+#
+# Compat for python2.7
+#
+
+# One unittest needs to import builtins via __import__() so we need to have
+# the string that represents it
+try:
+ import __builtin__
+except ImportError:
+ BUILTINS = 'builtins'
+else:
+ BUILTINS = '__builtin__'
diff --git a/ansible_collections/netapp/azure/tests/unit/compat/mock.py b/ansible_collections/netapp/azure/tests/unit/compat/mock.py
new file mode 100644
index 000000000..0972cd2e8
--- /dev/null
+++ b/ansible_collections/netapp/azure/tests/unit/compat/mock.py
@@ -0,0 +1,122 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+'''
+Compat module for Python3.x's unittest.mock module
+'''
+import sys
+
+# Python 2.7
+
+# Note: Could use the pypi mock library on python3.x as well as python2.x. It
+# is the same as the python3 stdlib mock library
+
+try:
+ # Allow wildcard import because we really do want to import all of mock's
+ # symbols into this compat shim
+ # pylint: disable=wildcard-import,unused-wildcard-import
+ from unittest.mock import *
+except ImportError:
+ # Python 2
+ # pylint: disable=wildcard-import,unused-wildcard-import
+ try:
+ from mock import *
+ except ImportError:
+ print('You need the mock library installed on python2.x to run tests')
+
+
+# Prior to 3.4.4, mock_open cannot handle binary read_data
+if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
+ file_spec = None
+
+ def _iterate_read_data(read_data):
+ # Helper for mock_open:
+ # Retrieve lines from read_data via a generator so that separate calls to
+ # readline, read, and readlines are properly interleaved
+ sep = b'\n' if isinstance(read_data, bytes) else '\n'
+ data_as_list = [l + sep for l in read_data.split(sep)]
+
+ if data_as_list[-1] == sep:
+ # If the last line ended in a newline, the list comprehension will have an
+ # extra entry that's just a newline. Remove this.
+ data_as_list = data_as_list[:-1]
+ else:
+ # If there wasn't an extra newline by itself, then the file being
+ # emulated doesn't have a newline to end the last line remove the
+ # newline that our naive format() added
+ data_as_list[-1] = data_as_list[-1][:-1]
+
+ for line in data_as_list:
+ yield line
+
+ def mock_open(mock=None, read_data=''):
+ """
+ A helper function to create a mock to replace the use of `open`. It works
+ for `open` called directly or used as a context manager.
+
+ The `mock` argument is the mock object to configure. If `None` (the
+ default) then a `MagicMock` will be created for you, with the API limited
+ to methods or attributes available on standard file handles.
+
+ `read_data` is a string for the `read` methoddline`, and `readlines` of the
+ file handle to return. This is an empty string by default.
+ """
+ def _readlines_side_effect(*args, **kwargs):
+ if handle.readlines.return_value is not None:
+ return handle.readlines.return_value
+ return list(_data)
+
+ def _read_side_effect(*args, **kwargs):
+ if handle.read.return_value is not None:
+ return handle.read.return_value
+ return type(read_data)().join(_data)
+
+ def _readline_side_effect():
+ if handle.readline.return_value is not None:
+ while True:
+ yield handle.readline.return_value
+ for line in _data:
+ yield line
+
+ global file_spec
+ if file_spec is None:
+ import _io
+ file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
+
+ if mock is None:
+ mock = MagicMock(name='open', spec=open)
+
+ handle = MagicMock(spec=file_spec)
+ handle.__enter__.return_value = handle
+
+ _data = _iterate_read_data(read_data)
+
+ handle.write.return_value = None
+ handle.read.return_value = None
+ handle.readline.return_value = None
+ handle.readlines.return_value = None
+
+ handle.read.side_effect = _read_side_effect
+ handle.readline.side_effect = _readline_side_effect()
+ handle.readlines.side_effect = _readlines_side_effect
+
+ mock.return_value = handle
+ return mock
diff --git a/ansible_collections/netapp/azure/tests/unit/compat/unittest.py b/ansible_collections/netapp/azure/tests/unit/compat/unittest.py
new file mode 100644
index 000000000..73a20cf8c
--- /dev/null
+++ b/ansible_collections/netapp/azure/tests/unit/compat/unittest.py
@@ -0,0 +1,44 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+'''
+Compat module for Python2.7's unittest module
+'''
+
+import sys
+
+import pytest
+
+# Allow wildcard import because we really do want to import all of
+# unittests's symbols into this compat shim
+# pylint: disable=wildcard-import,unused-wildcard-import
+if sys.version_info < (2, 7):
+ try:
+ # Need unittest2 on python2.6
+ from unittest2 import *
+ except ImportError:
+ print('You need unittest2 installed on python2.6.x to run tests')
+
+ class TestCase:
+ """ skip everything """
+ pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as unittest2 may not be available')
+else:
+ from unittest import *
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']
diff --git a/ansible_collections/netapp/azure/tests/unit/requirements.txt b/ansible_collections/netapp/azure/tests/unit/requirements.txt
new file mode 100644
index 000000000..0b89f6365
--- /dev/null
+++ b/ansible_collections/netapp/azure/tests/unit/requirements.txt
@@ -0,0 +1,3 @@
+azure-mgmt-netapp ; python_version >= '2.7'
+msrestazure ; python_version >= '3.5'
+requests ; python_version >= '2.7'