mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-05-06 09:11:29 -07:00
Refactor gitlab modules (#51141)
* gitlab_group: refactor module * gitlab_user: refactor module * gitlab_group, gitlab_user; pylint * gitlab_project: refactor module * gitlab_group, gitlab_project, gitlab_user: Enchance modules - Add generic loop to update object - Enchance return messages - PyLint * gitlab_runner: refactor module * gitlab_hooks: refactor module * gitlab_deploy_key: refactor module * gitlab_group: enchance module and documentation - Enchange function arguments - Add check_mode break - Rewrite module documentation * gitlab_hook: enchance module and documentation - Rewrite documentation - Enchance function parameters - Rename functions * gitlab_project: enchance module and documentation - Rewrite documentation - Enchance function parameters - Add try/except on project creation * gitlab_runner: enchance module and documentation - Rewrite documentation - Fix Copyright - Enchance function arguments - Add check_mode break - Add missing function: deletion * gitlab_user: enchance module and documentation - Rewrite documentation - Enchance function parameters - Add check_mode break - Add try/except on user creation * gitlab_deploy_key, gitlab_group, gitlab_hooks, gitlab_project, gitlab_runner, gitlab_user: Fix residual bugs - Fix Copyright - Fix result messages - Add missing check_mode break * gitlab_deploy_key, gitlab_group, gitlab_hooks, gitlab_project, gitlab_runner, gitlab_user: pylint * gitlab_runner: Add substitution function for 'cmp' in python3 * unit-test: remove deprecated gitlab module tests - gitlab_deploy_key - gitlab_hooks - gitlab_project Actually, they can't be reused because of the modification of the way that the module communicate with the Gitlab instance. It doesn't make direct call to the API, now it use a python library that do the job. So using a pytest mocker to test the module won't work. * gitlab_deploy_key, gitlab_group, gitlab_hooks, gitlab_project, gitlab_runner, gitlab_user: add copyright * gitlab_deploy_key, gitlab_group, gitlab_hooks, gitlab_project, gitlab_runner, gitlab_user: Support old parameters format * module_utils Gitlab: Edit copyright * gitlab_deploy_key, gitlab_group, gitlab_hooks, gitlab_project, gitlab_runner, gitlab_user: Unifying module inputs - Rename verify_ssl into validate_certs to match standards - Remove unused alias parameters - Unify parameters type and requirement - Reorder list order * gitlab_deploy_key, gitlab_group, gitlab_hooks, gitlab_project, gitlab_runner, gitlab_user: Unifying module outputs - Use standard output parameter "msg" instead of "return" - Use snail_case for return values instead of camelCase * validate-module: remove sanity ignore * BOTMETA: remove gitlab_* test - This tests need to be completely rewriten because of the refactoring of these modules - TodoList Community Wiki was updated * gitlab_user: Fix group identifier * gitlab_project: Fix when group was empty * gitlab_deploy_key: edit return msg * module_utils gitlab: fall back to user namespace is project not found * gitlab modules: Add units tests * unit test: gitlab module fake current user * gitlab_user: fix access_level verification * gitlab unit tests: use decoration instead of with statement * unit tests: gitlab module skip python 2.6 * unit tests: gitlab module skip library import if python 2.6 * gitlab unit tests: use builtin unittest class * gitlab unit tests: use custom test class * unit test: gitlab module lint * unit tests: move gitlab utils * unit test: gitlab fix imports * gitlab_module: edit requirement python-gitlab library require python >= 2.7 * gitlab_module: add myself as author * gitlab_modules: add python encoding tag * gitlab_modules: keep consistency between variable name "validate_certs" * gitlab_modules: enchance documentation * gitlab_runner: fix syntax error in documentation * gitlab_module: use basic_auth module_utils and add deprecation warning * gitlab_module: documentation corrections * gitlab_module: python lint * gitlab_module: deprecate options and aliases for ansible 2.10 * gitlab_group: don't use 'local_action' is documentation example * gitlab_module: correct return messages * gitlab_module: use module_util 'missing_required_lib' when python library is missing * gitlab_module: fix typo in function name. * gitlab_modules: unify return msg on check_mode * gitlab_modules: don't use deprecated options in examples
This commit is contained in:
parent
a682a0292d
commit
959939b866
17 changed files with 2874 additions and 1847 deletions
|
@ -1,285 +1,79 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Marcus Watkins <marwatk@marcuswatkins.net>
|
||||
|
||||
# Copyright: (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from units.compat.mock import patch
|
||||
from ansible.modules.source_control import gitlab_hooks
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils import basic
|
||||
from __future__ import absolute_import
|
||||
|
||||
import pytest
|
||||
import json
|
||||
from ansible.modules.source_control.gitlab_hooks import GitLabHook
|
||||
|
||||
from units.modules.utils import set_module_args
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_get_project, resp_find_project_hook,
|
||||
resp_create_project_hook, resp_delete_project_hook)
|
||||
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import ProjectHook
|
||||
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
fake_server_state = [
|
||||
{
|
||||
"id": 1,
|
||||
"url": "https://notification-server.example.com/gitlab-hook",
|
||||
"project_id": 10,
|
||||
"push_events": True,
|
||||
"issues_events": True,
|
||||
"merge_requests_events": True,
|
||||
"tag_push_events": True,
|
||||
"note_events": True,
|
||||
"job_events": True,
|
||||
"pipeline_events": True,
|
||||
"wiki_page_events": True,
|
||||
"enable_ssl_verification": True,
|
||||
"created_at": "2012-10-12T17:04:47Z"
|
||||
},
|
||||
]
|
||||
class TestGitlabHook(GitlabModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGitlabHook, self).setUp()
|
||||
|
||||
self.moduleUtil = GitLabHook(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
class FakeReader:
|
||||
def __init__(self, object):
|
||||
self.content = json.dumps(object, sort_keys=True)
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_hook)
|
||||
def test_hook_exist(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
def read(self):
|
||||
return self.content
|
||||
rvalue = self.moduleUtil.existsHooks(project, "http://example.com/hook")
|
||||
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
class AnsibleExitJson(Exception):
|
||||
"""Exception class to be raised by module.exit_json and caught by the test case"""
|
||||
pass
|
||||
rvalue = self.moduleUtil.existsHooks(project, "http://gitlab.com/hook")
|
||||
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
class AnsibleFailJson(Exception):
|
||||
"""Exception class to be raised by module.fail_json and caught by the test case"""
|
||||
pass
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_create_project_hook)
|
||||
def test_create_hook(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
hook = self.moduleUtil.createHook(project, {"url": "http://example.com/hook"})
|
||||
|
||||
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)
|
||||
self.assertEqual(type(hook), ProjectHook)
|
||||
self.assertEqual(hook.url, "http://example.com/hook")
|
||||
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_hook)
|
||||
def test_update_hook(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
hook = self.moduleUtil.findHook(project, "http://example.com/hook")
|
||||
|
||||
def fail_json(*args, **kwargs):
|
||||
"""function to patch over fail_json; package return data into an exception"""
|
||||
kwargs['failed'] = True
|
||||
raise AnsibleFailJson(kwargs)
|
||||
changed, newHook = self.moduleUtil.updateHook(hook, {"url": "http://gitlab.com/hook"})
|
||||
|
||||
self.assertEqual(changed, True)
|
||||
self.assertEqual(type(newHook), ProjectHook)
|
||||
self.assertEqual(newHook.url, "http://gitlab.com/hook")
|
||||
|
||||
@pytest.fixture
|
||||
def fetch_url_mock(mocker):
|
||||
return mocker.patch('ansible.module_utils.gitlab.fetch_url')
|
||||
changed, newHook = self.moduleUtil.updateHook(hook, {"url": "http://gitlab.com/hook"})
|
||||
|
||||
self.assertEqual(changed, False)
|
||||
self.assertEqual(newHook.url, "http://gitlab.com/hook")
|
||||
|
||||
@pytest.fixture
|
||||
def module_mock(mocker):
|
||||
return mocker.patch.multiple(basic.AnsibleModule,
|
||||
exit_json=exit_json,
|
||||
fail_json=fail_json)
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_hook)
|
||||
@with_httmock(resp_delete_project_hook)
|
||||
def test_delete_hook(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
self.moduleUtil.existsHooks(project, "http://example.com/hook")
|
||||
|
||||
def test_access_token_output(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://my-ci-server.example.com/gitlab-hook',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
rvalue = self.moduleUtil.deleteHook()
|
||||
|
||||
first_call = fetch_url_mock.call_args_list[0][1]
|
||||
assert first_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/hooks'
|
||||
assert first_call['headers']['Authorization'] == 'Bearer test-access-token'
|
||||
assert 'Private-Token' not in first_call['headers']
|
||||
assert first_call['method'] == 'GET'
|
||||
|
||||
|
||||
def test_private_token_output(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'private_token': 'test-private-token',
|
||||
'project': 'foo/bar',
|
||||
'hook_url': 'https://my-ci-server.example.com/gitlab-hook',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
first_call = fetch_url_mock.call_args_list[0][1]
|
||||
assert first_call['url'] == 'https://gitlab.example.com/api/v4/projects/foo%2Fbar/hooks'
|
||||
assert first_call['headers']['Private-Token'] == 'test-private-token'
|
||||
assert 'Authorization' not in first_call['headers']
|
||||
assert first_call['method'] == 'GET'
|
||||
|
||||
|
||||
def test_bad_http_first_response(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.side_effect = [[FakeReader("Permission denied"), {'status': 403}], [FakeReader("Permission denied"), {'status': 403}]]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://my-ci-server.example.com/gitlab-hook',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleFailJson):
|
||||
gitlab_hooks.main()
|
||||
|
||||
|
||||
def test_bad_http_second_response(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.side_effect = [[FakeReader(fake_server_state), {'status': 200}], [FakeReader("Permission denied"), {'status': 403}]]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://my-ci-server.example.com/gitlab-hook',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleFailJson):
|
||||
gitlab_hooks.main()
|
||||
|
||||
|
||||
def test_delete_non_existing(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://my-ci-server.example.com/gitlab-hook',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
assert result.value.args[0]['changed'] is False
|
||||
|
||||
|
||||
def test_delete_existing(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://notification-server.example.com/gitlab-hook',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/hooks/1'
|
||||
assert second_call['method'] == 'DELETE'
|
||||
|
||||
assert result.value.args[0]['changed'] is True
|
||||
|
||||
|
||||
def test_add_new(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://my-ci-server.example.com/gitlab-hook',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/hooks'
|
||||
assert second_call['method'] == 'POST'
|
||||
assert second_call['data'] == ('{"enable_ssl_verification": false, "issues_events": false, "job_events": false, '
|
||||
'"merge_requests_events": false, "note_events": false, "pipeline_events": false, "push_events": true, "tag_push_events": '
|
||||
'false, "token": null, "url": "https://my-ci-server.example.com/gitlab-hook", "wiki_page_events": false}')
|
||||
assert result.value.args[0]['changed'] is True
|
||||
|
||||
|
||||
def test_update_existing(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://notification-server.example.com/gitlab-hook',
|
||||
'push_events': 'yes',
|
||||
'issues_events': 'yes',
|
||||
'merge_requests_events': 'yes',
|
||||
'tag_push_events': 'yes',
|
||||
'note_events': 'yes',
|
||||
'job_events': 'yes',
|
||||
'pipeline_events': 'yes',
|
||||
'wiki_page_events': 'no',
|
||||
'enable_ssl_verification': 'yes',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/hooks/1'
|
||||
assert second_call['method'] == 'PUT'
|
||||
assert second_call['data'] == ('{"enable_ssl_verification": true, "issues_events": true, "job_events": true, '
|
||||
'"merge_requests_events": true, "note_events": true, "pipeline_events": true, "push_events": true, "tag_push_events": '
|
||||
'true, "token": null, "url": "https://notification-server.example.com/gitlab-hook", "wiki_page_events": false}')
|
||||
assert result.value.args[0]['changed'] is True
|
||||
|
||||
|
||||
def test_unchanged_existing(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://notification-server.example.com/gitlab-hook',
|
||||
'push_events': 'yes',
|
||||
'issues_events': 'yes',
|
||||
'merge_requests_events': 'yes',
|
||||
'tag_push_events': 'yes',
|
||||
'note_events': 'yes',
|
||||
'job_events': 'yes',
|
||||
'pipeline_events': 'yes',
|
||||
'wiki_page_events': 'yes',
|
||||
'enable_ssl_verification': 'yes',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
assert result.value.args[0]['changed'] is False
|
||||
assert fetch_url_mock.call_count == 1
|
||||
|
||||
|
||||
def test_unchanged_existing_with_token(capfd, fetch_url_mock, module_mock):
|
||||
fetch_url_mock.return_value = [FakeReader(fake_server_state), {'status': 200}]
|
||||
set_module_args({
|
||||
'api_url': 'https://gitlab.example.com/api',
|
||||
'access_token': 'test-access-token',
|
||||
'project': '10',
|
||||
'hook_url': 'https://notification-server.example.com/gitlab-hook',
|
||||
'push_events': 'yes',
|
||||
'issues_events': 'yes',
|
||||
'merge_requests_events': 'yes',
|
||||
'tag_push_events': 'yes',
|
||||
'note_events': 'yes',
|
||||
'job_events': 'yes',
|
||||
'pipeline_events': 'yes',
|
||||
'wiki_page_events': 'yes',
|
||||
'enable_ssl_verification': 'yes',
|
||||
'state': 'present',
|
||||
'token': 'secret-token',
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_hooks.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/hooks/1'
|
||||
assert second_call['method'] == 'PUT'
|
||||
assert second_call['data'] == ('{"enable_ssl_verification": true, "issues_events": true, "job_events": true, '
|
||||
'"merge_requests_events": true, "note_events": true, "pipeline_events": true, "push_events": true, '
|
||||
'"tag_push_events": true, "token": "secret-token", "url": "https://notification-server.example.com/gitlab-hook", '
|
||||
'"wiki_page_events": true}')
|
||||
assert result.value.args[0]['changed'] is True
|
||||
self.assertEqual(rvalue, None)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue