diff options
Diffstat (limited to 'ansible_collections/community/grafana/tests/unit/modules')
4 files changed, 970 insertions, 0 deletions
diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py new file mode 100644 index 000000000..d2fba0fe1 --- /dev/null +++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py @@ -0,0 +1,212 @@ +from __future__ import (absolute_import, division, print_function) + +from unittest import TestCase +from unittest.mock import call, patch, MagicMock +from ansible_collections.community.grafana.plugins.modules import grafana_datasource +from ansible.module_utils._text import to_bytes +from ansible.module_utils import basic +from ansible.module_utils.urls import basic_auth_header +import json + +__metaclass__ = type + + +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) + + +def exit_json(*args, **kwargs): + """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): + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +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 + + +class GrafanaDatasource(TestCase): + + def setUp(self): + self.authorization = basic_auth_header("admin", "admin") + 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) + + def test_payload_prometheus(self): + expected_payload = { + 'access': 'proxy', + 'basicAuth': False, + 'database': '', + 'isDefault': False, + 'jsonData': { + 'tlsAuth': False, + 'tlsAuthWithCACert': False, + 'tlsSkipVerify': True + }, + 'name': 'openshift_prometheus', + 'uid': 'xyz123', + 'orgId': 1, + 'secureJsonData': {}, + 'type': 'prometheus', + 'url': 'https://openshift-monitoring.company.com', + 'user': '', + 'withCredentials': False + } + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'admin', + 'name': 'openshift_prometheus', + 'uid': 'xyz123', + 'ds_type': 'prometheus', + 'ds_url': 'https://openshift-monitoring.company.com', + 'access': 'proxy', + 'tls_skip_verify': 'true', + }) + module = grafana_datasource.setup_module_object() + payload = grafana_datasource.get_datasource_payload(module.params) + self.assertEqual(payload, expected_payload) + + def test_payload_prometheus_with_basic_auth(self): + expected_payload = { + 'access': 'proxy', + 'basicAuth': True, + 'basicAuthUser': 'admin', + 'database': '', + 'isDefault': False, + 'jsonData': { + 'tlsAuth': False, + 'tlsAuthWithCACert': False, + 'tlsSkipVerify': True + }, + 'name': 'openshift_prometheus', + 'uid': 'xyz123', + 'orgId': 1, + 'secureJsonData': {'basicAuthPassword': 'admin'}, + 'type': 'prometheus', + 'url': 'https://openshift-monitoring.company.com', + 'user': '', + 'withCredentials': False + } + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'admin', + 'name': 'openshift_prometheus', + 'uid': 'xyz123', + 'ds_type': 'prometheus', + 'ds_url': 'https://openshift-monitoring.company.com', + 'access': 'proxy', + 'basic_auth_user': 'admin', + 'basic_auth_password': 'admin', + 'tls_skip_verify': 'true', + }) + module = grafana_datasource.setup_module_object() + payload = grafana_datasource.get_datasource_payload(module.params) + self.assertEqual(payload, expected_payload) + + def test_payload_influxdb(self): + expected_payload = { + 'access': 'proxy', + 'basicAuth': False, + 'database': 'telegraf', + 'isDefault': False, + 'jsonData': { + 'timeInterval': '>10s', + 'tlsAuth': False, + 'tlsAuthWithCACert': True + }, + 'name': 'datasource-influxdb', + 'uid': 'xyz123', + 'orgId': 1, + 'secureJsonData': { + 'tlsCACert': '/etc/ssl/certs/ca.pem' + }, + 'type': 'influxdb', + 'url': 'https://influx.company.com:8086', + 'user': '', + 'withCredentials': False + } + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'admin', + 'name': 'datasource-influxdb', + 'uid': 'xyz123', + 'ds_type': 'influxdb', + 'ds_url': 'https://influx.company.com:8086', + 'database': 'telegraf', + 'time_interval': '>10s', + 'tls_ca_cert': '/etc/ssl/certs/ca.pem' + }) + module = grafana_datasource.setup_module_object() + payload = grafana_datasource.get_datasource_payload(module.params) + self.assertEqual(payload, expected_payload) + + def test_payload_elastic(self): + expected_payload = { + 'access': 'proxy', + 'basicAuth': True, + 'basicAuthUser': 'grafana', + 'database': '[logstash_]YYYY.MM.DD', + 'isDefault': False, + 'jsonData': { + 'esVersion': 56, + 'interval': 'Daily', + 'maxConcurrentShardRequests': 42, + 'timeField': '@timestamp', + 'timeInterval': '1m', + 'tlsAuth': False, + 'tlsAuthWithCACert': True + }, + 'name': 'datasource-elastic', + 'uid': 'xyz123', + 'orgId': 1, + 'secureJsonData': { + 'basicAuthPassword': 'grafana', + 'tlsCACert': '/etc/ssl/certs/ca.pem' + }, + 'type': 'elasticsearch', + 'url': 'https://elastic.company.com:9200', + 'user': '', + 'withCredentials': False + } + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'admin', + 'name': 'datasource-elastic', + 'uid': 'xyz123', + 'ds_type': 'elasticsearch', + 'ds_url': 'https://elastic.company.com:9200', + 'database': '[logstash_]YYYY.MM.DD', + 'basic_auth_user': 'grafana', + 'basic_auth_password': 'grafana', + 'time_field': '@timestamp', + 'time_interval': '1m', + 'interval': 'Daily', + 'es_version': 56, + 'max_concurrent_shard_requests': 42, + 'tls_ca_cert': '/etc/ssl/certs/ca.pem' + }) + module = grafana_datasource.setup_module_object() + payload = grafana_datasource.get_datasource_payload(module.params) + self.assertEqual(payload, expected_payload) diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py new file mode 100644 index 000000000..b3b025c4e --- /dev/null +++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py @@ -0,0 +1,111 @@ +from __future__ import (absolute_import, division, print_function) + +from unittest import TestCase +from unittest.mock import patch, MagicMock +from ansible_collections.community.grafana.plugins.modules import grafana_plugin + +__metaclass__ = type + + +def run_command_ls(): + STDERR = "" + STDOUT = """ +installed plugins: +alexanderzobnin-zabbix-app @ 3.10.5 + +Restart grafana after installing plugins . <service grafana-server restart> +""" + return 0, STDOUT, STDERR + + +def run_command_install_zip(): + STDERR = "" + STDOUT = """ +installing alexanderzobnin-grafana-zabbix @ +from: /home/grafana//alexanderzobnin-grafana-zabbix-v3.10.5-1-g2219691.zip +into: /var/lib/grafana/plugins + +... Installed alexanderzobnin-grafana-zabbix successfully + +Restart grafana after installing plugins . <service grafana-server restart> + +""" + return 0, STDOUT, STDERR + + +def run_command_uninstall(): + STDERR = "" + STDOUT = """ +Removing plugin: alexanderzobnin-zabbix-app + +Restart grafana after installing plugins . <service grafana-server restart> +""" + return 0, STDOUT, STDERR + + +def run_command_uninstall_again(): + STDERR = "" + STDOUT = """ +Removing plugin: alexanderzobnin-zabbix-app +Error: ✗ plugin does not exist +""" + return 1, STDOUT, STDERR + + +class GrafanaPlugin(TestCase): + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin') + def test_plugin_install_zip(self, mock_grafana_cli_bin): + mock_grafana_cli_bin.return_value = "grafana-cli plugins" + + params = { + "name": "alexanderzobnin-zabbix-app" + } + + module = MagicMock() + module.run_command.return_value = run_command_install_zip() + + result = grafana_plugin.get_grafana_plugin_version(module, params) + self.assertEqual(result, None) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin') + def test_plugin_ls(self, mock_grafana_cli_bin): + mock_grafana_cli_bin.return_value = "grafana-cli plugins" + + params = { + "name": "alexanderzobnin-zabbix-app" + } + + module = MagicMock() + module.run_command.return_value = run_command_ls() + + result = grafana_plugin.get_grafana_plugin_version(module, params) + self.assertEqual(result, "3.10.5") + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin') + def test_plugin_uninstall(self, mock_grafana_cli_bin): + mock_grafana_cli_bin.return_value = "grafana-cli plugins" + + params = { + "name": "alexanderzobnin-zabbix-app" + } + + module = MagicMock() + module.run_command.return_value = run_command_uninstall() + + result = grafana_plugin.get_grafana_plugin_version(module, params) + self.assertEqual(result, None) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin') + def test_plugin_uninstall_again(self, mock_grafana_cli_bin): + mock_grafana_cli_bin.return_value = "grafana-cli plugins" + + params = { + "name": "alexanderzobnin-zabbix-app" + } + + module = MagicMock() + module.run_command.return_value = run_command_uninstall_again() + + result = grafana_plugin.get_grafana_plugin_version(module, params) + self.assertEqual(result, None) diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py new file mode 100644 index 000000000..c59953afa --- /dev/null +++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py @@ -0,0 +1,447 @@ +from __future__ import (absolute_import, division, print_function) + +from unittest import TestCase +from unittest.mock import patch, MagicMock +from ansible_collections.community.grafana.plugins.modules import grafana_team +from ansible.module_utils._text import to_bytes +from ansible.module_utils import basic +from ansible.module_utils.urls import basic_auth_header +import json + +__metaclass__ = type + + +class MockedReponse(object): + def __init__(self, data): + self.data = data + + def read(self): + return self.data + + +def exit_json(*args, **kwargs): + """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): + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +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 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) + + +def unauthorized_resp(): + return (None, {"status": 401}) + + +def permission_denied_resp(): + return (None, {"status": 403}) + + +def get_version_resp(): + return {"major": 6, "minor": 0, "rev": 0} + + +def get_low_version_resp(): + return {"major": 4, "minor": 6, "rev": 0} + + +def team_exists_resp(): + server_response = json.dumps({"totalCount": 1, "teams": [{"name": "MyTestTeam", "email": "email@test.com"}]}, sort_keys=True) + return (MockedReponse(server_response), {"status": 200}) + + +def team_not_found_resp(): + server_response = json.dumps({"totalCount": 0, "teams": []}) + return (MockedReponse(server_response), {"status": 200}) + + +def team_created_resp(): + server_response = json.dumps({"message": "Team created", "teamId": 2}) + return (MockedReponse(server_response), {"status": 200}) + + +def team_updated_resp(): + server_response = json.dumps({"message": "Team updated"}) + return (MockedReponse(server_response), {"status": 200}) + + +def team_deleted_resp(): + server_response = json.dumps({"message": "Team deleted"}) + return (MockedReponse(server_response), {"status": 200}) + + +def team_members_resp(): + server_response = json.dumps([{ + "orgId": 1, + "teamId": 2, + "userId": 3, + "email": "user1@email.com", + "login": "user1", + "avatarUrl": r"\/avatar\/1b3c32f6386b0185c40d359cdc733a79" + }, { + "orgId": 1, + "teamId": 2, + "userId": 2, + "email": "user2@email.com", + "login": "user2", + "avatarUrl": r"\/avatar\/cad3c68da76e45d10269e8ef02f8e73e" + }]) + return (MockedReponse(server_response), {"status": 200}) + + +def team_members_no_members_resp(): + server_response = json.dumps([]) + return (MockedReponse(server_response), {"status": 200}) + + +def add_team_member_resp(): + server_response = json.dumps({"message": "Member added to Team"}) + return (MockedReponse(server_response), {"status": 200}) + + +def delete_team_member_resp(): + server_response = json.dumps({"message": "Team Member removed"}) + return (MockedReponse(server_response), {"status": 200}) + + +class GrafanaTeamsTest(TestCase): + + def setUp(self): + self.authorization = basic_auth_header("admin", "admin") + 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) + + def test_module_setup_fails_without_params(self): + set_module_args({}) + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + err, arg_list = result.exception.args[0]['msg'].split(':') + missing_args = [item.strip() for item in arg_list.split(',')] + self.assertEqual(err, 'missing required arguments') + self.assertEqual(arg_list, ["name", "email", "url"]) + + def test_module_setup_fails_without_name(self): + set_module_args({ + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertEqual(result.exception.args[0]['msg'], 'missing required arguments: name') + + def test_module_setup_fails_without_email(self): + set_module_args({ + 'name': 'MyTestTeam', + 'url': 'http://grafana.example.com' + }) + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertEqual(result.exception.args[0]['msg'], 'missing required arguments: email') + + def test_module_setup_fails_without_url(self): + set_module_args({ + 'name': 'MyTestTeam', + 'email': 'email@test.com', + }) + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertEqual(result.exception.args[0]['msg'], 'missing required arguments: url') + + def test_module_setup_fails_with_mutually_exclusive_auth_methods(self): + set_module_args({ + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com', + 'grafana_user': 'admin', + 'grafana_api_key': 'random_api_key', + }) + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertEqual(result.exception.args[0]['msg'], 'parameters are mutually exclusive: url_username|grafana_api_key') + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + def test_module_fails_with_low_grafana_version(self, mock_get_version): + set_module_args({ + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com', + 'grafana_user': 'admin', + 'grafana_password': 'admin', + }) + + module = grafana_team.setup_module_object() + mock_get_version.return_value = get_low_version_resp() + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertEqual(result.exception.args[0]['msg'], 'Teams API is available starting Grafana v5') + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_module_failure_with_unauthorized_resp(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com', + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = unauthorized_resp() + mock_get_version.return_value = get_version_resp() + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertTrue(result.exception.args[0]['msg'].startswith('Unauthorized to perform action')) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_module_failure_with_permission_denied_resp(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com', + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = permission_denied_resp() + mock_get_version.return_value = get_version_resp() + + with self.assertRaises(AnsibleFailJson) as result: + grafana_team.main() + self.assertTrue(result.exception.args[0]['msg'].startswith('Permission Denied')) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_get_team_method_with_existing_team(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_exists_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + res = grafana_iface.get_team("MyTestTeam") + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/search?name=MyTestTeam', + data=None, + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='GET') + self.assertEquals(res, {"email": "email@test.com", "name": "MyTestTeam"}) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_get_team_method_with_non_existing_team(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_not_found_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + res = grafana_iface.get_team("MyTestTeam") + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/search?name=MyTestTeam', + data=None, + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='GET') + self.assertEquals(res, None) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_create_team_method(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_created_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + + res = grafana_iface.create_team("MyTestTeam", "email@test.com") + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams', + data=json.dumps({"email": "email@test.com", "name": "MyTestTeam"}, sort_keys=True), + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='POST') + self.assertEquals(res, {"message": "Team created", "teamId": 2}) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_update_team_method(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_updated_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + res = grafana_iface.update_team(2, "MyTestTeam", "email@test.com") + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/2', + data=json.dumps({"email": "email@test.com", "name": "MyTestTeam"}, sort_keys=True), + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='PUT') + self.assertEquals(res, {"message": "Team updated"}) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_delete_team_method(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'absent', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_deleted_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + res = grafana_iface.delete_team(2) + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/2', + data=None, + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='DELETE') + self.assertEquals(res, {"message": "Team deleted"}) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_get_team_members_method(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_members_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + res = grafana_iface.get_team_members(2) + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/2/members', + data=None, + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='GET') + self.assertEquals(res, ["user1@email.com", "user2@email.com"]) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_get_team_members_method_no_members_returned(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = team_members_no_members_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + res = grafana_iface.get_team_members(2) + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/2/members', + data=None, + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='GET') + self.assertEquals(res, []) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_add_team_member_method(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = add_team_member_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + with patch.object(grafana_team.GrafanaTeamInterface, 'get_user_id_from_mail') as mock_get_user_id_from_mail: + mock_get_user_id_from_mail.return_value = 42 + res = grafana_iface.add_team_member(2, "another@test.com") + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/2/members', + data=json.dumps({'userId': 42}), + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='POST') + self.assertEquals(res, None) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version') + @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url') + def test_delete_team_member_method(self, mock_fetch_url, mock_get_version): + set_module_args({ + 'state': 'present', + 'name': 'MyTestTeam', + 'email': 'email@test.com', + 'url': 'http://grafana.example.com' + }) + module = grafana_team.setup_module_object() + mock_fetch_url.return_value = delete_team_member_resp() + mock_get_version.return_value = get_version_resp() + + grafana_iface = grafana_team.GrafanaTeamInterface(module) + with patch.object(grafana_team.GrafanaTeamInterface, 'get_user_id_from_mail') as mock_get_user_id_from_mail: + mock_get_user_id_from_mail.return_value = 42 + res = grafana_iface.delete_team_member(2, "another@test.com") + mock_fetch_url.assert_called_once_with( + module, 'http://grafana.example.com/api/teams/2/members/42', + data=None, + headers={'Content-Type': 'application/json', 'Authorization': self.authorization}, + method='DELETE') + self.assertEquals(res, None) + + def test_diff_members_function(self): + list1 = ["foo@example.com", "bar@example.com"] + list2 = ["bar@example.com", "random@example.com"] + + res = grafana_team.diff_members(list1, list2) + self.assertEquals(res, {"to_del": ["random@example.com"], "to_add": ["foo@example.com"]}) diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py new file mode 100644 index 000000000..925c01655 --- /dev/null +++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py @@ -0,0 +1,200 @@ +from __future__ import (absolute_import, division, print_function) + +from unittest import TestCase +from unittest.mock import call, patch, MagicMock +from ansible_collections.community.grafana.plugins.modules import grafana_user +from ansible.module_utils._text import to_bytes +from ansible.module_utils import basic +from ansible.module_utils.urls import basic_auth_header +import json + +__metaclass__ = type + + +class MockedReponse(object): + def __init__(self, data): + self.data = data + + def read(self): + return self.data + + +def exit_json(*args, **kwargs): + """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): + """function to patch over fail_json; package return data into an exception""" + kwargs['failed'] = True + raise AnsibleFailJson(kwargs) + + +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 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) + + +def user_deleted_resp(): + server_response = json.dumps({"message": "User deleted"}) + return (MockedReponse(server_response), {"status": 200}) + + +def user_already_exists_resp(): + server_response = json.dumps({"message": "failed to create user"}) + return (MockedReponse(server_response), {"status": 500}) + + +def user_created_resp(): + server_response = json.dumps({ + "id": 2, + "email": "robin@gotham.com", + "name": "Robin", + "login": "adrobinmin", + "theme": "light", + "orgId": 1, + "isGrafanaAdmin": False, + "isDisabled": False, + "isExternal": False, + "authLabels": None, + "updatedAt": "2019-09-25T14:44:37+01:00", + "createdAt": "2019-09-25T14:44:37+01:00" + }, sort_keys=True) + return (MockedReponse(server_response), {"status": 200}) + + +class GrafanaUserTest(TestCase): + + def setUp(self): + self.authorization = basic_auth_header("admin", "changeme") + 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) + + # create an already existing user + @patch('ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url') + def test_create_user_existing_user(self, mock_fetch_url): + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'changeme', + 'name': 'Joker', + 'email': 'joker@gotham.com', + 'login': 'joker', + 'password': 'oups', + 'state': 'present' + }) + module = grafana_user.setup_module_object() + mock_fetch_url.return_value = user_already_exists_resp() + + grafana_iface = grafana_user.GrafanaUserInterface(module) + with self.assertRaises(AnsibleFailJson): + grafana_iface.create_user( + 'Joker', 'joker@gotham.com', 'joker', 'oups') + mock_fetch_url.assert_called_once_with( + module, + 'https://grafana.example.com/api/admin/users', + data=json.dumps({'name': 'Joker', 'email': 'joker@gotham.com', + 'login': 'joker', 'password': 'oups'}, sort_keys=True), + headers={'Content-Type': 'application/json', + 'Authorization': self.authorization}, + method='POST') + + # create a new user + @patch('ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url') + def test_create_user_new_user(self, mock_fetch_url): + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'changeme', + 'name': 'Robin', + 'email': 'robin@gotham.com', + 'login': 'robin', + 'password': 'oups', + 'state': 'present' + }) + module = grafana_user.setup_module_object() + + mock_fetch_url.return_value = user_created_resp() + + expected_fetch_url_calls = [ + # first call to create user + call( + module, + 'https://grafana.example.com/api/admin/users', + data=json.dumps({'name': 'Robin', 'email': 'robin@gotham.com', + 'login': 'robin', 'password': 'oups'}, sort_keys=True), + headers={'Content-Type': 'application/json', + 'Authorization': self.authorization}, + method='POST'), + + # second call to return created user + call( + module, + 'https://grafana.example.com/api/users/lookup?loginOrEmail=robin', + data=None, + headers={'Content-Type': 'application/json', + 'Authorization': self.authorization}, + method='GET'), + ] + + grafana_iface = grafana_user.GrafanaUserInterface(module) + result = grafana_iface.create_user( + 'Robin', 'robin@gotham.com', 'robin', 'oups') + + mock_fetch_url.assert_has_calls( + expected_fetch_url_calls, any_order=False) + + self.assertEquals(result, { + "id": 2, + "email": "robin@gotham.com", + "name": "Robin", + "login": "adrobinmin", + "theme": "light", + "orgId": 1, + "isGrafanaAdmin": False, + "isDisabled": False, + "isExternal": False, + "authLabels": None, + "updatedAt": "2019-09-25T14:44:37+01:00", + "createdAt": "2019-09-25T14:44:37+01:00" + }) + + @patch('ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url') + def test_delete_user(self, mock_fetch_url): + set_module_args({ + 'url': 'https://grafana.example.com', + 'url_username': 'admin', + 'url_password': 'changeme', + 'login': 'batman', + 'state': 'absent' + }) + module = grafana_user.setup_module_object() + mock_fetch_url.return_value = user_deleted_resp() + + grafana_iface = grafana_user.GrafanaUserInterface(module) + user_id = 42 + result = grafana_iface.delete_user(user_id) + mock_fetch_url.assert_called_once_with( + module, + 'https://grafana.example.com/api/admin/users/42', + data=None, + headers={'Content-Type': 'application/json', + 'Authorization': self.authorization}, + method='DELETE') + self.assertEquals(result, {"message": "User deleted"}) |