diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:22 +0000 |
commit | 38b7c80217c4e72b1d8988eb1e60bb6e77334114 (patch) | |
tree | 356e9fd3762877d07cde52d21e77070aeff7e789 /ansible_collections/netapp/um_info | |
parent | Adding upstream version 7.7.0+dfsg. (diff) | |
download | ansible-38b7c80217c4e72b1d8988eb1e60bb6e77334114.tar.xz ansible-38b7c80217c4e72b1d8988eb1e60bb6e77334114.zip |
Adding upstream version 9.4.0+dfsg.upstream/9.4.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/netapp/um_info')
13 files changed, 871 insertions, 10 deletions
diff --git a/ansible_collections/netapp/um_info/.github/workflows/main.yml b/ansible_collections/netapp/um_info/.github/workflows/main.yml index fbcf92002..9294078a2 100644 --- a/ansible_collections/netapp/um_info/.github/workflows/main.yml +++ b/ansible_collections/netapp/um_info/.github/workflows/main.yml @@ -17,6 +17,7 @@ jobs: - stable-2.10 - stable-2.11 - stable-2.12 + - stable-2.13 - devel steps: @@ -26,7 +27,8 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: 3.8 + # Ansible 2.14 requires 3.9 as a minimum + python-version: 3.9 - name: Install ansible (${{ matrix.ansible }}) run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check diff --git a/ansible_collections/netapp/um_info/FILES.json b/ansible_collections/netapp/um_info/FILES.json index 0d45bda4d..769a883a4 100644 --- a/ansible_collections/netapp/um_info/FILES.json +++ b/ansible_collections/netapp/um_info/FILES.json @@ -46,7 +46,7 @@ "name": "plugins/module_utils/netapp.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "821070453abf1ec684677f43878fdd4ceb66bb30e40aeeb16b35aa71c0294249", + "chksum_sha256": "a255d934e0f25750f739d26bc124f7542db92b11385d5a3f350409ed6ae3fc2f", "format": 1 }, { @@ -232,6 +232,27 @@ "format": 1 }, { + "name": "tests/unit/plugins/modules/test_na_um_list_svms.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7933824403b197ec756f540be054a5e2c75b5a3a28cf60280cd11493f4c4b235", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_na_um_list_aggregates.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ba3687cb122aa7452f21052b5a6f26448df8356e92e4b78c20cce55c66ea3026", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_na_um_list_clusters.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "11f9aa85947d440b6a647a2cc6be1cf16d93d69b08ed288a33fa8168836d2521", + "format": 1 + }, + { "name": "tests/unit/plugins/modules/test_na_um_nodes_info.py", "ftype": "file", "chksum_type": "sha256", @@ -246,6 +267,13 @@ "format": 1 }, { + "name": "tests/unit/plugins/modules/test_na_um_list_volumes.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b8a2d4ca0f304a588de4d642da415362f3b15b2926fa12a90117b58b9f71d6d9", + "format": 1 + }, + { "name": "tests/unit/plugins/modules/test_na_um_svms_info.py", "ftype": "file", "chksum_type": "sha256", @@ -253,6 +281,13 @@ "format": 1 }, { + "name": "tests/unit/plugins/modules/test_na_um_list_nodes.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cf4ded8134d30ed7b82769252addf2094d07b6bf3ec81e7aba0615b290558cfb", + "format": 1 + }, + { "name": "meta", "ftype": "dir", "chksum_type": null, @@ -260,10 +295,17 @@ "format": 1 }, { + "name": "meta/execution-environment.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "db75f5fcae43fd2db36d3c9a004748dd1ec4165a6e2ebb36ada6943a8b440f4a", + "format": 1 + }, + { "name": "meta/runtime.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "88d46a475f366fffbd8ec430a85972ed1aa180268564bd88434cceaaaf13712c", + "chksum_sha256": "2fe9f7286aadaf2d0c4dbd2a0f118f155f564496bbc1bc742478ef7e8ece8269", "format": 1 }, { @@ -347,7 +389,7 @@ "name": "README.md", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "ae574e5d7e3e4d82a855ed53b06c34a26134d7a9d50e023bf2408b51e0f8a679", + "chksum_sha256": "69664a93902d708863a70abc626b771889dce8cd6682efc449bb01a0efcc9dca", "format": 1 }, { @@ -358,6 +400,13 @@ "format": 1 }, { + "name": "metadata-29PbAy.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "424c5b110233e003275aaa5d6886c892f39c23b72a69bbf72e9a3172933691a6", + "format": 1 + }, + { "name": ".github", "ftype": "dir", "chksum_type": null, @@ -382,7 +431,7 @@ "name": ".github/workflows/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "fa99709b97a6f722ae1a51afaf32ad66aa2d1306b708b8b9c8d723be715ca4c4", + "chksum_sha256": "e7781e9cc514eb5cb80bbee9a821af8661cbd39542ddfe6aa59e811afbabdf13", "format": 1 }, { diff --git a/ansible_collections/netapp/um_info/MANIFEST.json b/ansible_collections/netapp/um_info/MANIFEST.json index 40b3df1ae..5683ca1df 100644 --- a/ansible_collections/netapp/um_info/MANIFEST.json +++ b/ansible_collections/netapp/um_info/MANIFEST.json @@ -2,7 +2,7 @@ "collection_info": { "namespace": "netapp", "name": "um_info", - "version": "21.8.0", + "version": "21.8.1", "authors": [ "NetApp Ansible Team <ng-ansibleteam@netapp.com>" ], @@ -27,7 +27,7 @@ "name": "FILES.json", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "cb6c57414d2dfe99a63f715ea33254ca1d6cd458b50fa0cbae778ea41b14ef2c", + "chksum_sha256": "e33360247a1805f8191170f1cba1aa27a57e3abac652d447b398169adb14a626", "format": 1 }, "format": 1 diff --git a/ansible_collections/netapp/um_info/README.md b/ansible_collections/netapp/um_info/README.md index 193bbab59..c1ad29008 100644 --- a/ansible_collections/netapp/um_info/README.md +++ b/ansible_collections/netapp/um_info/README.md @@ -1,6 +1,7 @@ [![Documentation](https://img.shields.io/badge/docs-brightgreen.svg)](https://docs.ansible.com/ansible/devel/collections/netapp/um_info/index.html) ![example workflow](https://github.com/ansible-collections/netapp.um_info/actions/workflows/main.yml/badge.svg) [![codecov](https://codecov.io/gh/ansible-collections/netapp.um_info/branch/main/graph/badge.svg?token=weBYkksxSi)](https://codecov.io/gh/ansible-collections/netapp.um_info) +[![Discord](https://img.shields.io/discord/855068651522490400)](https://discord.gg/NetApp) ============================================================= @@ -30,7 +31,7 @@ https://docs.ansible.com/ansible/devel/collections/netapp/um_info/ This collection follows the [Ansible project's Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html). # Need help -Join our Slack Channel at [Netapp.io](http://netapp.io/slack) +Join our [Discord](https://discord.gg/NetApp) # Release Notes diff --git a/ansible_collections/netapp/um_info/meta/execution-environment.yml b/ansible_collections/netapp/um_info/meta/execution-environment.yml new file mode 100644 index 000000000..315d71a13 --- /dev/null +++ b/ansible_collections/netapp/um_info/meta/execution-environment.yml @@ -0,0 +1,3 @@ +version: 1 +dependencies: + python: ../requirements.txt diff --git a/ansible_collections/netapp/um_info/meta/runtime.yml b/ansible_collections/netapp/um_info/meta/runtime.yml index 04c66ffeb..cc45f44f7 100644 --- a/ansible_collections/netapp/um_info/meta/runtime.yml +++ b/ansible_collections/netapp/um_info/meta/runtime.yml @@ -1,5 +1,5 @@ --- -requires_ansible: ">=2.9.10" +requires_ansible: ">=2.13" action_groups: netapp_um_info: - na_um_aggregates_info diff --git a/ansible_collections/netapp/um_info/metadata-29PbAy.json b/ansible_collections/netapp/um_info/metadata-29PbAy.json new file mode 100644 index 000000000..7ccf48221 --- /dev/null +++ b/ansible_collections/netapp/um_info/metadata-29PbAy.json @@ -0,0 +1,14 @@ +{ + "change_description": { + "changed_paths": [], + "command": "", + "deleted_paths": [], + "focused_command_targets": {}, + "no_integration_paths": [], + "regular_command_targets": {} + }, + "changes": {}, + "ci_provider": "", + "cloud_config": null, + "instance_config": null +} diff --git a/ansible_collections/netapp/um_info/plugins/module_utils/netapp.py b/ansible_collections/netapp/um_info/plugins/module_utils/netapp.py index ba58f56e8..15a113ae4 100644 --- a/ansible_collections/netapp/um_info/plugins/module_utils/netapp.py +++ b/ansible_collections/netapp/um_info/plugins/module_utils/netapp.py @@ -43,7 +43,7 @@ try: except ImportError: ansible_version = 'unknown' -COLLECTION_VERSION = "21.8.0" +COLLECTION_VERSION = "21.8.1" try: import requests diff --git a/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_aggregates.py b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_aggregates.py new file mode 100644 index 000000000..9d2479484 --- /dev/null +++ b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_aggregates.py @@ -0,0 +1,159 @@ +# (c) 2020, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" unit tests for Ansible module: na_um_aggregates_info """ + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import pytest +import sys + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.um_info.tests.unit.compat import unittest +from ansible_collections.netapp.um_info.tests.unit.compat.mock import patch, Mock +import ansible_collections.netapp.um_info.plugins.module_utils.netapp as netapp_utils + +from ansible_collections.netapp.um_info.plugins.modules.na_um_aggregates_info\ + import NetAppUMAggregate as my_module # module under test + + +if not netapp_utils.HAS_REQUESTS and sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + + +# REST API canned responses when mocking send_request +SRR = { + # common responses + 'empty_not_so_good': ({}, None), + 'end_of_sequence': (None, "Unexpected call to send_request"), + 'generic_error': (None, "Expected error"), + 'get_next': (dict(_links=dict(self='me', next=dict(href='next_records'))), None), + 'get_data': (dict(_links=dict(self='me'), records=['data1', 'data2'], total_records=2), None), + 'get_data_missing_field': (dict(_links=dict(self='me'), records=['data1', 'data2']), None), + # module specific responses + 'get_aggregates': {'name': 'ansible'} +} + + +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""" + pass + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + pass + + +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 MockUMConnection(object): + ''' mock server connection to Unified Manager host ''' + + def __init__(self): + ''' pass init ''' + + +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.server = MockUMConnection() + # whether to use a mock or a simulator + self.onbox = False + + def set_default_args(self): + if self.onbox: + hostname = '10.10.10.10' + username = 'admin' + password = 'password' + else: + hostname = 'hostname' + username = 'username' + password = 'password' + return dict({ + 'hostname': hostname, + 'username': username, + 'password': password, + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + my_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_aggregates_info.NetAppUMAggregate.get_aggregates') + def test_ensure_list_aggregates_get_called(self, get_aggregates): + ''' fetching details of aggregates ''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.server = self.server + my_obj.get_aggregates = Mock(return_value=SRR['get_aggregates']) + with pytest.raises(AnsibleExitJson) as exc: + my_obj.apply() + assert exc.value.args[0]['changed'] + # to reset na_helper from remembering the previous 'changed' value + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_aggregates_info.NetAppUMAggregate.get_aggregates') + def test_ensure_get_called_existing(self, get_aggregates): + ''' test for existing aggregates''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.get_aggregates = Mock(return_value=SRR['get_aggregates']) + assert my_obj.get_aggregates() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_get_next(self, mock_request): + ''' test for existing aggregates''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + assert my_obj.get_aggregates() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_negative_get_next(self, mock_request): + ''' test for existing aggregates''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data_missing_field'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + with pytest.raises(AnsibleFailJson) as exc: + my_obj.get_aggregates() is not None + print(exc.value.args[0]) + msg = 'unexpected response from datacenter/storage/aggregates?order_by=performance_capacity.used' + assert msg in exc.value.args[0]['msg'] + msg = "expecting key: 'total_records'" + assert msg in exc.value.args[0]['msg'] diff --git a/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_clusters.py b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_clusters.py new file mode 100644 index 000000000..c4939adb8 --- /dev/null +++ b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_clusters.py @@ -0,0 +1,159 @@ +# (c) 2020, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" unit tests for Ansible module: na_um_clusters_info """ + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import pytest +import sys + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.um_info.tests.unit.compat import unittest +from ansible_collections.netapp.um_info.tests.unit.compat.mock import patch, Mock +import ansible_collections.netapp.um_info.plugins.module_utils.netapp as netapp_utils + +from ansible_collections.netapp.um_info.plugins.modules.na_um_clusters_info\ + import NetAppUMCluster as my_module # module under test + + +if not netapp_utils.HAS_REQUESTS and sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + + +# REST API canned responses when mocking send_request +SRR = { + # common responses + 'empty_good': ({}, None), + 'end_of_sequence': (None, "Unexpected call to send_request"), + 'generic_error': (None, "Expected error"), + 'get_next': (dict(_links=dict(self='me', next=dict(href='next_records'))), None), + 'get_data': (dict(_links=dict(self='me'), records=['data1', 'data2'], total_records=2), None), + 'get_data_missing_field': (dict(_links=dict(self='me'), records=['data1', 'data2']), None), + # module specific responses + 'get_cluster': {'name': 'ansible'} +} + + +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""" + pass + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + pass + + +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 MockUMConnection(object): + ''' mock server connection to Unified Manager host ''' + + def __init__(self): + ''' pass init ''' + + +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.server = MockUMConnection() + # whether to use a mock or a simulator + self.onbox = False + + def set_default_args(self): + if self.onbox: + hostname = '10.10.10.10' + username = 'admin' + password = 'password' + else: + hostname = 'hostname' + username = 'username' + password = 'password' + return dict({ + 'hostname': hostname, + 'username': username, + 'password': password, + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + my_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_clusters_info.NetAppUMCluster.get_clusters') + def test_ensure_list_cluster_get_called(self, get_cluster): + ''' fetching details of cluster ''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.server = self.server + my_obj.get_cluster = Mock(return_value=SRR['get_cluster']) + with pytest.raises(AnsibleExitJson) as exc: + my_obj.apply() + assert exc.value.args[0]['changed'] + # to reset na_helper from remembering the previous 'changed' value + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_clusters_info.NetAppUMCluster.get_clusters') + def test_ensure_get_called_existing(self, get_cluster): + ''' test for existing cluster''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.get_cluster = Mock(return_value=SRR['get_cluster']) + assert my_obj.get_cluster() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_get_next(self, mock_request): + ''' test for existing clusters''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + assert my_obj.get_clusters() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_negative_get_next(self, mock_request): + ''' test for existing clusters''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data_missing_field'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + with pytest.raises(AnsibleFailJson) as exc: + my_obj.get_clusters() is not None + print(exc.value.args[0]) + msg = 'unexpected response from datacenter/cluster/clusters' + assert msg in exc.value.args[0]['msg'] + msg = "expecting key: 'total_records'" + assert msg in exc.value.args[0]['msg'] diff --git a/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_nodes.py b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_nodes.py new file mode 100644 index 000000000..e5769d1f1 --- /dev/null +++ b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_nodes.py @@ -0,0 +1,158 @@ +# (c) 2020, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" unit tests for Ansible module: na_um_nodes_info """ + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import pytest +import sys + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.um_info.tests.unit.compat import unittest +from ansible_collections.netapp.um_info.tests.unit.compat.mock import patch, Mock +import ansible_collections.netapp.um_info.plugins.module_utils.netapp as netapp_utils + +from ansible_collections.netapp.um_info.plugins.modules.na_um_nodes_info\ + import NetAppUMNode as my_module # module under test + + +if not netapp_utils.HAS_REQUESTS and sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + + +# REST API canned responses when mocking send_request +SRR = { + # common responses + 'empty_good': ({}, None), + 'end_of_sequence': (None, "Unexpected call to send_request"), + 'generic_error': (None, "Expected error"), + 'get_next': (dict(_links=dict(self='me', next=dict(href='next_records'))), None), + 'get_data': (dict(_links=dict(self='me'), records=['data1', 'data2'], total_records=2), None), + 'get_data_missing_field': (dict(_links=dict(self='me'), records=['data1', 'data2']), None), + # module specific responses + 'get_nodes': {'name': 'ansible'} +} + + +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""" + pass + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + pass + + +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 MockUMConnection(object): + ''' mock server connection to Unified Manager host ''' + + def __init__(self): + ''' pass init ''' + + +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.server = MockUMConnection() + # whether to use a mock or a simulator + self.onbox = False + + def set_default_args(self): + if self.onbox: + hostname = '10.10.10.10' + username = 'admin' + password = 'password' + else: + hostname = 'hostname' + username = 'username' + password = 'password' + return dict({ + 'hostname': hostname, + 'username': username, + 'password': password, + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + my_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_nodes_info.NetAppUMNode.get_nodes') + def test_ensure_list_nodes_get_called(self, get_nodes): + ''' fetching details of nodes ''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.server = self.server + my_obj.get_nodes = Mock(return_value=SRR['get_nodes']) + with pytest.raises(AnsibleExitJson) as exc: + my_obj.apply() + assert exc.value.args[0]['changed'] + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_nodes_info.NetAppUMNode.get_nodes') + def test_ensure_get_called_existing(self, get_nodes): + ''' test for existing nodes''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.get_nodes = Mock(return_value=SRR['get_nodes']) + assert my_obj.get_nodes() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_get_next(self, mock_request): + ''' test for existing nodes''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + assert my_obj.get_nodes() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_negative_get_next(self, mock_request): + ''' test for existing nodes''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data_missing_field'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + with pytest.raises(AnsibleFailJson) as exc: + my_obj.get_nodes() is not None + print(exc.value.args[0]) + msg = 'unexpected response from datacenter/cluster/nodes' + assert msg in exc.value.args[0]['msg'] + msg = "expecting key: 'total_records'" + assert msg in exc.value.args[0]['msg'] diff --git a/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_svms.py b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_svms.py new file mode 100644 index 000000000..2eafd508f --- /dev/null +++ b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_svms.py @@ -0,0 +1,158 @@ +# (c) 2020, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" unit tests for Ansible module: na_um_svms_info """ + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import pytest +import sys + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.um_info.tests.unit.compat import unittest +from ansible_collections.netapp.um_info.tests.unit.compat.mock import patch, Mock +import ansible_collections.netapp.um_info.plugins.module_utils.netapp as netapp_utils + +from ansible_collections.netapp.um_info.plugins.modules.na_um_svms_info\ + import NetAppUMSVM as my_module # module under test + + +if not netapp_utils.HAS_REQUESTS and sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + + +# REST API canned responses when mocking send_request +SRR = { + # common responses + 'empty_good': ({}, None), + 'end_of_sequence': (None, "Unexpected call to send_request"), + 'generic_error': (None, "Expected error"), + 'get_next': (dict(_links=dict(self='me', next=dict(href='next_records'))), None), + 'get_data': (dict(_links=dict(self='me'), records=['data1', 'data2'], total_records=2), None), + 'get_data_missing_field': (dict(_links=dict(self='me'), records=['data1', 'data2']), None), + # module specific responses + 'get_svms': {'name': 'ansible'} +} + + +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""" + pass + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + pass + + +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 MockUMConnection(object): + ''' mock server connection to Unified Manager host ''' + + def __init__(self): + ''' pass init ''' + + +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.server = MockUMConnection() + # whether to use a mock or a simulator + self.onbox = False + + def set_default_args(self): + if self.onbox: + hostname = '10.10.10.10' + username = 'admin' + password = 'password' + else: + hostname = 'hostname' + username = 'username' + password = 'password' + return dict({ + 'hostname': hostname, + 'username': username, + 'password': password, + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + my_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_svms_info.NetAppUMSVM.get_svms') + def test_ensure_list_svms_get_called(self, get_svms): + ''' fetching details of svms ''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.server = self.server + my_obj.get_svms = Mock(return_value=SRR['get_svms']) + with pytest.raises(AnsibleExitJson) as exc: + my_obj.apply() + assert exc.value.args[0]['changed'] + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_svms_info.NetAppUMSVM.get_svms') + def test_ensure_get_called_existing(self, get_svms): + ''' test for existing svms''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.get_svms = Mock(return_value=SRR['get_svms']) + assert my_obj.get_svms() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_get_next(self, mock_request): + ''' test for existing svms''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + assert my_obj.get_svms() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_negative_get_next(self, mock_request): + ''' test for existing svms''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data_missing_field'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + with pytest.raises(AnsibleFailJson) as exc: + my_obj.get_svms() is not None + print(exc.value.args[0]) + msg = 'unexpected response from datacenter/svm/svms' + assert msg in exc.value.args[0]['msg'] + msg = "expecting key: 'total_records'" + assert msg in exc.value.args[0]['msg'] diff --git a/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_volumes.py b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_volumes.py new file mode 100644 index 000000000..4c8a267fb --- /dev/null +++ b/ansible_collections/netapp/um_info/tests/unit/plugins/modules/test_na_um_list_volumes.py @@ -0,0 +1,158 @@ +# (c) 2020, NetApp, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" unit tests for Ansible module: na_um_volumes_info """ + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type +import json +import pytest +import sys + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible_collections.netapp.um_info.tests.unit.compat import unittest +from ansible_collections.netapp.um_info.tests.unit.compat.mock import patch, Mock +import ansible_collections.netapp.um_info.plugins.module_utils.netapp as netapp_utils + +from ansible_collections.netapp.um_info.plugins.modules.na_um_volumes_info\ + import NetAppUMVolume as my_module # module under test + + +if not netapp_utils.HAS_REQUESTS and sys.version_info < (2, 7): + pytestmark = pytest.mark.skip('Skipping Unit Tests on 2.6 as requests is not be available') + + +# REST API canned responses when mocking send_request +SRR = { + # common responses + 'empty_good': ({}, None), + 'end_of_sequence': (None, "Unexpected call to send_request"), + 'generic_error': (None, "Expected error"), + 'get_next': (dict(_links=dict(self='me', next=dict(href='next_records'))), None), + 'get_data': (dict(_links=dict(self='me'), records=['data1', 'data2'], total_records=2), None), + 'get_data_missing_field': (dict(_links=dict(self='me'), records=['data1', 'data2']), None), + # module specific responses + 'get_volumes': {'name': 'ansible'} +} + + +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""" + pass + + +class AnsibleFailJson(Exception): + """Exception class to be raised by module.fail_json and caught by the test case""" + pass + + +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 MockUMConnection(object): + ''' mock server connection to Unified Manager host ''' + + def __init__(self): + ''' pass init ''' + + +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.server = MockUMConnection() + # whether to use a mock or a simulator + self.onbox = False + + def set_default_args(self): + if self.onbox: + hostname = '10.10.10.10' + username = 'admin' + password = 'password' + else: + hostname = 'hostname' + username = 'username' + password = 'password' + return dict({ + 'hostname': hostname, + 'username': username, + 'password': password, + }) + + def test_module_fail_when_required_args_missing(self): + ''' required arguments are reported as errors ''' + with pytest.raises(AnsibleFailJson) as exc: + set_module_args({}) + my_module() + print('Info: %s' % exc.value.args[0]['msg']) + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_volumes_info.NetAppUMVolume.get_volumes') + def test_ensure_list_volumes_get_called(self, get_volumes): + ''' fetching details of volumes ''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.server = self.server + my_obj.get_volumes = Mock(return_value=SRR['get_volumes']) + with pytest.raises(AnsibleExitJson) as exc: + my_obj.apply() + assert exc.value.args[0]['changed'] + + @patch('ansible_collections.netapp.um_info.plugins.modules.na_um_volumes_info.NetAppUMVolume.get_volumes') + def test_ensure_get_called_existing(self, get_volumes): + ''' test for existing volumes''' + set_module_args(self.set_default_args()) + my_obj = my_module() + my_obj.get_volumes = Mock(return_value=SRR['get_volumes']) + assert my_obj.get_volumes() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_get_next(self, mock_request): + ''' test for existing volumes''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + assert my_obj.get_volumes() is not None + + @patch('ansible_collections.netapp.um_info.plugins.module_utils.netapp.UMRestAPI.send_request') + def test_negative_get_next(self, mock_request): + ''' test for existing volumes''' + set_module_args(self.set_default_args()) + mock_request.side_effect = [ + SRR['get_next'], + SRR['get_data_missing_field'], + SRR['end_of_sequence'], + ] + my_obj = my_module() + with pytest.raises(AnsibleFailJson) as exc: + my_obj.get_volumes() is not None + print(exc.value.args[0]) + msg = 'unexpected response from datacenter/storage/volumes' + assert msg in exc.value.args[0]['msg'] + msg = "expecting key: 'total_records'" + assert msg in exc.value.args[0]['msg'] |