mirror of https://github.com/ansible/ansible.git
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 examplespull/51897/head
parent
a682a0292d
commit
959939b866
@ -0,0 +1,563 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
|
||||
from httmock import response # noqa
|
||||
from httmock import urlmatch # noqa
|
||||
|
||||
from units.compat import unittest
|
||||
|
||||
from gitlab import Gitlab
|
||||
|
||||
|
||||
class FakeAnsibleModule(object):
|
||||
def __init__(self):
|
||||
self.check_mode = False
|
||||
|
||||
def fail_json(self, **args):
|
||||
pass
|
||||
|
||||
def exit_json(self, **args):
|
||||
pass
|
||||
|
||||
|
||||
class GitlabModuleTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
unitest_python_version_check_requirement(self)
|
||||
|
||||
self.mock_module = FakeAnsibleModule()
|
||||
|
||||
self.gitlab_instance = Gitlab("http://localhost", private_token="private_token", api_version=4)
|
||||
|
||||
|
||||
# Python 2.7+ is needed for python-gitlab
|
||||
GITLAB_MINIMUM_PYTHON_VERSION = (2, 7)
|
||||
|
||||
|
||||
# Verify if the current Python version is higher than GITLAB_MINIMUM_PYTHON_VERSION
|
||||
def python_version_match_requirement():
|
||||
return sys.version_info >= GITLAB_MINIMUM_PYTHON_VERSION
|
||||
|
||||
|
||||
# Skip unittest test case if python version don't match requirement
|
||||
def unitest_python_version_check_requirement(unittest_testcase):
|
||||
if not python_version_match_requirement():
|
||||
unittest_testcase.skipTest("Python %s+ is needed for python-gitlab" % ",".join(map(str, GITLAB_MINIMUM_PYTHON_VERSION)))
|
||||
|
||||
|
||||
'''
|
||||
USER API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users", method="get")
|
||||
def resp_find_user(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1, "username": "john_smith", "name": "John Smith", "state": "active",'
|
||||
'"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",'
|
||||
'"web_url": "http://localhost:3000/john_smith"}, {"id": 2,'
|
||||
'"username": "jack_smith", "name": "Jack Smith", "state": "blocked",'
|
||||
'"avatar_url": "http://gravatar.com/../e32131cd8.jpeg",'
|
||||
'"web_url": "http://localhost:3000/jack_smith"}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users", method="post")
|
||||
def resp_create_user(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "username": "john_smith", "name": "John Smith", "state": "active",'
|
||||
'"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",'
|
||||
'"web_url": "http://localhost:3000/john_smith","created_at": "2012-05-23T08:00:58Z",'
|
||||
'"bio": null, "location": null, "public_email": "john@example.com", "skype": "",'
|
||||
'"linkedin": "", "twitter": "", "website_url": "", "organization": ""}')
|
||||
content = content.encode("utf-8")
|
||||
return response(201, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1", method="get")
|
||||
def resp_get_user(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "username": "john_smith", "name": "John Smith",'
|
||||
'"state": "active",'
|
||||
'"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",'
|
||||
'"web_url": "http://localhost:3000/john_smith",'
|
||||
'"created_at": "2012-05-23T08:00:58Z", "bio": null, "location": null,'
|
||||
'"public_email": "john@example.com", "skype": "", "linkedin": "",'
|
||||
'"twitter": "", "website_url": "", "organization": "", "is_admin": false}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1", method="get")
|
||||
def resp_get_missing_user(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(404, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1", method="delete")
|
||||
def resp_delete_user(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(204, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1", method="delete")
|
||||
def resp_delete_missing_user(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(404, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
USER SSHKEY API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1/keys", method="get")
|
||||
def resp_get_user_keys(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1, "title": "Public key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596'
|
||||
'k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQa'
|
||||
'SeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",'
|
||||
'"created_at": "2014-08-01T14:47:39.080Z"},{"id": 3,'
|
||||
'"title": "Another Public key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596'
|
||||
'k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaS'
|
||||
'eP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",'
|
||||
'"created_at": "2014-08-01T14:47:39.080Z"}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1/keys", method="post")
|
||||
def resp_create_user_keys(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "title": "Private key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDA1YotVDm2mAyk2tPt4E7AHm01sS6JZmcUdRuSuA5z'
|
||||
'szUJzYPPUSRAX3BCgTqLqYx//UuVncK7YqLVSbbwjKR2Ez5lISgCnVfLVEXzwhv+xawxKWmI7hJ5S0tOv6MJ+Ixy'
|
||||
'Ta4xcKwJTwB86z22n9fVOQeJTR2dSOH1WJrf0PvRk+KVNY2jTiGHTi9AIjLnyD/jWRpOgtdfkLRc8EzAWrWlgNmH'
|
||||
'2WOKBw6za0az6XoG75obUdFVdW3qcD0xc809OHLi7FDf+E7U4wiZJCFuUizMeXyuK/SkaE1aee4Qp5R4dxTR4TP9'
|
||||
'M1XAYkf+kF0W9srZ+mhF069XD/zhUPJsvwEF",'
|
||||
'"created_at": "2014-08-01T14:47:39.080Z"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(201, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
GROUP API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups", method="get")
|
||||
def resp_find_group(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1, "name": "Foobar Group", "path": "foo-bar",'
|
||||
'"description": "An interesting group", "visibility": "public",'
|
||||
'"lfs_enabled": true, "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",'
|
||||
'"web_url": "http://localhost:3000/groups/foo-bar", "request_access_enabled": false,'
|
||||
'"full_name": "Foobar Group", "full_path": "foo-bar",'
|
||||
'"file_template_project_id": 1, "parent_id": null, "projects": []}, {"id": 2, "name": "BarFoo Group", "path": "bar-foor",'
|
||||
'"description": "An interesting group", "visibility": "public",'
|
||||
'"lfs_enabled": true, "avatar_url": "http://localhost:3000/uploads/group/avatar/2/bar.jpg",'
|
||||
'"web_url": "http://localhost:3000/groups/bar-foo", "request_access_enabled": false,'
|
||||
'"full_name": "BarFoo Group", "full_path": "bar-foo",'
|
||||
'"file_template_project_id": 1, "parent_id": null, "projects": []}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1", method="get")
|
||||
def resp_get_group(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "name": "Foobar Group", "path": "foo-bar",'
|
||||
'"description": "An interesting group", "visibility": "public",'
|
||||
'"lfs_enabled": true, "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",'
|
||||
'"web_url": "http://localhost:3000/groups/foo-bar", "request_access_enabled": false,'
|
||||
'"full_name": "Foobar Group", "full_path": "foo-bar",'
|
||||
'"file_template_project_id": 1, "parent_id": null, "projects": [{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}]}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1", method="get")
|
||||
def resp_get_missing_group(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(404, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups", method="post")
|
||||
def resp_create_group(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "name": "Foobar Group", "path": "foo-bar",'
|
||||
'"description": "An interesting group", "visibility": "public",'
|
||||
'"lfs_enabled": true, "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",'
|
||||
'"web_url": "http://localhost:3000/groups/foo-bar", "request_access_enabled": false,'
|
||||
'"full_name": "Foobar Group", "full_path": "foo-bar",'
|
||||
'"file_template_project_id": 1, "parent_id": null}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups", method="post")
|
||||
def resp_create_subgroup(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 2, "name": "BarFoo Group", "path": "bar-foor",'
|
||||
'"description": "An interesting group", "visibility": "public",'
|
||||
'"lfs_enabled": true, "avatar_url": "http://localhost:3000/uploads/group/avatar/2/bar.jpg",'
|
||||
'"web_url": "http://localhost:3000/groups/foo-bar/bar-foo", "request_access_enabled": false,'
|
||||
'"full_name": "BarFoo Group", "full_path": "foo-bar/bar-foo",'
|
||||
'"file_template_project_id": 1, "parent_id": 1}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/users/1", method="delete")
|
||||
def resp_delete_group(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(204, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
GROUP MEMBER API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/members/1", method="get")
|
||||
def resp_get_member(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "username": "raymond_smith", "name": "Raymond Smith", "state": "active",'
|
||||
'"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",'
|
||||
'"web_url": "http://192.168.1.8:3000/root", "expires_at": "2012-10-22T14:13:35Z", "access_level": 30}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/members", method="get")
|
||||
def resp_find_member(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1, "username": "raymond_smith", "name": "Raymond Smith", "state": "active",'
|
||||
'"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",'
|
||||
'"web_url": "http://192.168.1.8:3000/root", "expires_at": "2012-10-22T14:13:35Z", "access_level": 30},{'
|
||||
'"id": 2, "username": "john_doe", "name": "John Doe","state": "active",'
|
||||
'"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",'
|
||||
'"web_url": "http://192.168.1.8:3000/root","expires_at": "2012-10-22T14:13:35Z",'
|
||||
'"access_level": 30}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/members", method="post")
|
||||
def resp_add_member(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "username": "raymond_smith", "name": "Raymond Smith",'
|
||||
'"state": "active",'
|
||||
'"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",'
|
||||
'"web_url": "http://192.168.1.8:3000/root", "expires_at": "2012-10-22T14:13:35Z",'
|
||||
'"access_level": 30}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/members/1", method="put")
|
||||
def resp_update_member(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1, "username": "raymond_smith", "name": "Raymond Smith",'
|
||||
'"state": "active",'
|
||||
'"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",'
|
||||
'"web_url": "http://192.168.1.8:3000/root", "expires_at": "2012-10-22T14:13:35Z",'
|
||||
'"access_level": 10}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
DEPLOY KEY API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/deploy_keys", method="get")
|
||||
def resp_find_project_deploy_key(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1,"title": "Public key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc'
|
||||
'KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",'
|
||||
'"created_at": "2013-10-02T10:12:29Z"},{"id": 3,"title": "Another Public key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc'
|
||||
'KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",'
|
||||
'"created_at": "2013-10-02T11:12:29Z"}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/deploy_keys/1", method="get")
|
||||
def resp_get_project_deploy_key(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"title": "Public key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc'
|
||||
'KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",'
|
||||
'"created_at": "2013-10-02T10:12:29Z"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/deploy_keys", method="post")
|
||||
def resp_create_project_deploy_key(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"title": "Public key",'
|
||||
'"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc'
|
||||
'KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",'
|
||||
'"created_at": "2013-10-02T10:12:29Z"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(201, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/deploy_keys/1", method="delete")
|
||||
def resp_delete_project_deploy_key(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(204, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
PROJECT API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get")
|
||||
def resp_find_project(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1", method="get")
|
||||
def resp_get_project(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/foo-bar%2Fdiaspora-client", method="get")
|
||||
def resp_get_project_by_name(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/projects", method="get")
|
||||
def resp_find_group_project(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/projects/1", method="get")
|
||||
def resp_get_group_project(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="post")
|
||||
def resp_create_project(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"description": null, "default_branch": "master",'
|
||||
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
|
||||
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
|
||||
'"web_url": "http://example.com/diaspora/diaspora-client",'
|
||||
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
|
||||
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
|
||||
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
|
||||
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
|
||||
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
|
||||
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
|
||||
'"star_count": 0}')
|
||||
content = content.encode("utf-8")
|
||||
return response(201, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1", method="delete")
|
||||
def resp_delete_project(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
|
||||
return response(204, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
HOOK API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/hooks", method="get")
|
||||
def resp_find_project_hook(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"id": 1,"url": "http://example.com/hook","project_id": 3,'
|
||||
'"push_events": true,"push_events_branch_filter": "","issues_events": true,'
|
||||
'"confidential_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"}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/hooks/1", method="get")
|
||||
def resp_get_project_hook(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"url": "http://example.com/hook","project_id": 3,'
|
||||
'"push_events": true,"push_events_branch_filter": "","issues_events": true,'
|
||||
'"confidential_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"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/hooks", method="post")
|
||||
def resp_create_project_hook(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"id": 1,"url": "http://example.com/hook","project_id": 3,'
|
||||
'"push_events": true,"push_events_branch_filter": "","issues_events": true,'
|
||||
'"confidential_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"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(201, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/hooks/1", method="delete")
|
||||
def resp_delete_project_hook(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(204, content, headers, None, 5, request)
|
||||
|
||||
|
||||
'''
|
||||
HOOK API
|
||||
'''
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/runners/all", method="get")
|
||||
def resp_find_runners(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('[{"active": true,"description": "test-1-20150125","id": 1,'
|
||||
'"is_shared": false,"ip_address": "127.0.0.1","name": null,'
|
||||
'"online": true,"status": "online"},{"active": true,'
|
||||
'"description": "test-2-20150125","id": 2,"ip_address": "127.0.0.1",'
|
||||
'"is_shared": false,"name": null,"online": false,"status": "offline"}]')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/runners/1", method="get")
|
||||
def resp_get_runner(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"active": true,"description": "test-1-20150125","id": 1,'
|
||||
'"is_shared": false,"ip_address": "127.0.0.1","name": null,'
|
||||
'"online": true,"status": "online"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(200, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/runners", method="post")
|
||||
def resp_create_runner(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{"active": true,"description": "test-1-20150125","id": 1,'
|
||||
'"is_shared": false,"ip_address": "127.0.0.1","name": null,'
|
||||
'"online": true,"status": "online"}')
|
||||
content = content.encode("utf-8")
|
||||
return response(201, content, headers, None, 5, request)
|
||||
|
||||
|
||||
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/runners/1", method="delete")
|
||||
def resp_delete_runner(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = ('{}')
|
||||
content = content.encode("utf-8")
|
||||
return response(204, content, headers, None, 5, request)
|
@ -1,233 +1,84 @@
|
||||
# -*- 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_deploy_key
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils import basic
|
||||
from __future__ import absolute_import
|
||||
|
||||
from ansible.modules.source_control.gitlab_deploy_key import GitLabDeployKey
|
||||
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_get_project, resp_find_project_deploy_key,
|
||||
resp_create_project_deploy_key, resp_delete_project_deploy_key)
|
||||
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import ProjectKey
|
||||
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
class TestGitlabDeployKey(GitlabModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGitlabDeployKey, self).setUp()
|
||||
|
||||
self.moduleUtil = GitLabDeployKey(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_deploy_key)
|
||||
def test_deploy_key_exist(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
rvalue = self.moduleUtil.existsDeployKey(project, "Public key")
|
||||
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
rvalue = self.moduleUtil.existsDeployKey(project, "Private key")
|
||||
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_create_project_deploy_key)
|
||||
def test_create_deploy_key(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
deploy_key = self.moduleUtil.createDeployKey(project, {"title": "Public key",
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM"
|
||||
"4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc"
|
||||
"KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfD"
|
||||
"zpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="})
|
||||
|
||||
self.assertEqual(type(deploy_key), ProjectKey)
|
||||
self.assertEqual(deploy_key.title, "Public key")
|
||||
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_deploy_key)
|
||||
@with_httmock(resp_create_project_deploy_key)
|
||||
def test_update_deploy_key(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
deployKey = self.moduleUtil.findDeployKey(project, "Public key")
|
||||
|
||||
changed, newDeploy_key = self.moduleUtil.updateDeployKey(deployKey, {"title": "Private key"})
|
||||
|
||||
self.assertEqual(changed, True)
|
||||
self.assertEqual(type(newDeploy_key), ProjectKey)
|
||||
self.assertEqual(newDeploy_key.title, "Private key")
|
||||
|
||||
import pytest
|
||||
import json
|
||||
changed, newDeploy_key = self.moduleUtil.updateDeployKey(deployKey, {"title": "Private key"})
|
||||
|
||||
from units.modules.utils import set_module_args
|
||||
self.assertEqual(changed, False)
|
||||
self.assertEqual(newDeploy_key.title, "Private key")
|
||||
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_deploy_key)
|
||||
@with_httmock(resp_delete_project_deploy_key)
|
||||
def test_delete_deploy_key(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
fake_server_state = [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Public key",
|
||||
"key": 'ssh-rsa long/+base64//+string==',
|
||||
"created_at": "2013-10-02T10:12:29Z",
|
||||
"can_push": False
|
||||
},
|
||||
]
|
||||
self.moduleUtil.existsDeployKey(project, "Public key")
|
||||
|
||||
rvalue = self.moduleUtil.deleteDeployKey()
|
||||
|
||||
class FakeReader:
|
||||
def __init__(self, object):
|
||||
self.content = json.dumps(object, sort_keys=True)
|
||||
|
||||
def read(self):
|
||||
return self.content
|
||||
|
||||
|
||||
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):
|
||||
"""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)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fetch_url_mock(mocker):
|
||||
return mocker.patch('ansible.module_utils.gitlab.fetch_url')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def module_mock(mocker):
|
||||
return mocker.patch.multiple(basic.AnsibleModule,
|
||||
exit_json=exit_json,
|
||||
fail_json=fail_json)
|
||||
|
||||
|
||||
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',
|
||||
'key': 'ssh-key foobar',
|
||||
'title': 'a title',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.main()
|
||||
|
||||
first_call = fetch_url_mock.call_args_list[0][1]
|
||||
assert first_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/deploy_keys'
|
||||
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',
|
||||
'key': 'ssh-key foobar',
|
||||
'title': 'a title',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.main()
|
||||
|
||||
first_call = fetch_url_mock.call_args_list[0][1]
|
||||
assert first_call['url'] == 'https://gitlab.example.com/api/v4/projects/foo%2Fbar/deploy_keys'
|
||||
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',
|
||||
'key': 'ssh-key foobar',
|
||||
'title': 'a title',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleFailJson):
|
||||
gitlab_deploy_key.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',
|
||||
'key': 'ssh-key foobar',
|
||||
'title': 'a title',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleFailJson):
|
||||
gitlab_deploy_key.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',
|
||||
'key': 'ssh-key foobar',
|
||||
'title': 'a title',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.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',
|
||||
'key': 'ssh-rsa long/+base64//+string==',
|
||||
'title': 'a title',
|
||||
'state': 'absent'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/deploy_keys/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',
|
||||
'key': 'ssh-key foobar',
|
||||
'title': 'a title',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/deploy_keys'
|
||||
assert second_call['method'] == 'POST'
|
||||
assert second_call['data'] == '{"can_push": false, "key": "ssh-key foobar", "title": "a title"}'
|
||||
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',
|
||||
'title': 'Public key',
|
||||
'key': 'ssh-rsa long/+base64//+string==',
|
||||
'can_push': 'yes',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.main()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/deploy_keys/1'
|
||||
assert second_call['method'] == 'PUT'
|
||||
assert second_call['data'] == ('{"can_push": true, "key": "ssh-rsa long/+base64//+string==", "title": "Public key"}')
|
||||
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',
|
||||
'title': 'Public key',
|
||||
'key': 'ssh-rsa long/+base64//+string==',
|
||||
'can_push': 'no',
|
||||
'state': 'present'
|
||||
})
|
||||
with pytest.raises(AnsibleExitJson) as result:
|
||||
gitlab_deploy_key.main()
|
||||
|
||||
assert result.value.args[0]['changed'] is False
|
||||
assert fetch_url_mock.call_count == 1
|
||||
self.assertEqual(rvalue, None)
|
||||
|
@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 __future__ import absolute_import
|
||||
|
||||
from ansible.modules.source_control.gitlab_group import GitLabGroup
|
||||
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_get_group, resp_get_missing_group, resp_create_group,
|
||||
resp_create_subgroup, resp_delete_group, resp_find_group_project)
|
||||
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import Group
|
||||
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
class TestGitlabGroup(GitlabModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGitlabGroup, self).setUp()
|
||||
|
||||
self.moduleUtil = GitLabGroup(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
def test_exist_group(self):
|
||||
rvalue = self.moduleUtil.existsGroup(1)
|
||||
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
@with_httmock(resp_get_missing_group)
|
||||
def test_exist_group(self):
|
||||
rvalue = self.moduleUtil.existsGroup(1)
|
||||
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
@with_httmock(resp_create_group)
|
||||
def test_create_group(self):
|
||||
group = self.moduleUtil.createGroup({'name': "Foobar Group", 'path': "foo-bar"})
|
||||
|
||||
self.assertEqual(type(group), Group)
|
||||
self.assertEqual(group.name, "Foobar Group")
|
||||
self.assertEqual(group.path, "foo-bar")
|
||||
self.assertEqual(group.id, 1)
|
||||
|
||||
@with_httmock(resp_create_subgroup)
|
||||
def test_create_subgroup(self):
|
||||
group = self.moduleUtil.createGroup({'name': "BarFoo Group", 'path': "bar-foo", "parent_id": 1})
|
||||
|
||||
self.assertEqual(type(group), Group)
|
||||
self.assertEqual(group.name, "BarFoo Group")
|
||||
self.assertEqual(group.full_path, "foo-bar/bar-foo")
|
||||
self.assertEqual(group.id, 2)
|
||||
self.assertEqual(group.parent_id, 1)
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
def test_update_group(self):
|
||||
group = self.gitlab_instance.groups.get(1)
|
||||
changed, newGroup = self.moduleUtil.updateGroup(group, {'name': "BarFoo Group", "visibility": "private"})
|
||||
|
||||
self.assertEqual(changed, True)
|
||||
self.assertEqual(newGroup.name, "BarFoo Group")
|
||||
self.assertEqual(newGroup.visibility, "private")
|
||||
|
||||
changed, newGroup = self.moduleUtil.updateGroup(group, {'name': "BarFoo Group"})
|
||||
|
||||
self.assertEqual(changed, False)
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_find_group_project)
|
||||
@with_httmock(resp_delete_group)
|
||||
def test_delete_group(self):
|
||||
self.moduleUtil.existsGroup(1)
|
||||
|
||||
print(self.moduleUtil.groupObject.projects)
|
||||
|
||||
rvalue = self.moduleUtil.deleteGroup()
|
||||
|
||||
self.assertEqual(rvalue, None)
|
@ -1,285 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Marcus Watkins <marwatk@marcuswatkins.net>
|
||||
# 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
|
||||
|
||||
import pytest
|
||||
import json
|
||||
|
||||
from units.modules.utils import set_module_args
|
||||
|
||||
|
||||
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 FakeReader:
|
||||
def __init__(self, object):
|
||||
self.content = json.dumps(object, sort_keys=True)
|
||||
|
||||
def read(self):
|
||||
return self.content
|
||||
|
||||
|
||||
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):
|
||||
"""function to patch over exit_json; package return data into an exception"""
|
||||
if 'changed' not in kwargs:
|
||||
kwargs['changed'] = False
|
||||
raise AnsibleExitJson(kwargs)
|
||||
|
||||
# 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)
|
||||
|
||||
def fail_json(*args, **kwargs):
|
||||
"""function to patch over fail_json; package return data into an exception"""
|
||||
kwargs['failed'] = True
|
||||
raise AnsibleFailJson(kwargs)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fetch_url_mock(mocker):
|
||||
return mocker.patch('ansible.module_utils.gitlab.fetch_url')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def module_mock(mocker):
|
||||
return mocker.patch.multiple(basic.AnsibleModule,
|
||||
exit_json=exit_json,
|
||||
fail_json=fail_json)
|
||||
|
||||
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
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()
|
||||
from ansible.modules.source_control.gitlab_hooks import GitLabHook
|
||||
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_get_project, resp_find_project_hook,
|
||||
resp_create_project_hook, resp_delete_project_hook)
|
||||
|
||||
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()
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import ProjectHook
|
||||
|
||||
assert result.value.args[0]['changed'] is False
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
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()
|
||||
class TestGitlabHook(GitlabModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGitlabHook, self).setUp()
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
self.moduleUtil = GitLabHook(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
assert second_call['url'] == 'https://gitlab.example.com/api/v4/projects/10/hooks/1'
|
||||
assert second_call['method'] == 'DELETE'
|
||||
@with_httmock(resp_get_project)
|
||||
@with_httmock(resp_find_project_hook)
|
||||
def test_hook_exist(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
assert result.value.args[0]['changed'] is True
|
||||
rvalue = self.moduleUtil.existsHooks(project, "http://example.com/hook")
|
||||
|
||||
self.assertEqual(rvalue, 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()
|
||||
rvalue = self.moduleUtil.existsHooks(project, "http://gitlab.com/hook")
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
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
|
||||
@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 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()
|
||||
self.assertEqual(type(hook), ProjectHook)
|
||||
self.assertEqual(hook.url, "http://example.com/hook")
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
@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")
|
||||
|
||||
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
|
||||
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")
|
||||
|
||||
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()
|
||||
changed, newHook = self.moduleUtil.updateHook(hook, {"url": "http://gitlab.com/hook"})
|
||||
|
||||
assert result.value.args[0]['changed'] is False
|
||||
assert fetch_url_mock.call_count == 1
|
||||
self.assertEqual(changed, False)
|
||||
self.assertEqual(newHook.url, "http://gitlab.com/hook")
|
||||
|
||||
@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)
|
||||
|
||||
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()
|
||||
self.moduleUtil.existsHooks(project, "http://example.com/hook")
|
||||
|
||||
second_call = fetch_url_mock.call_args_list[1][1]
|
||||
rvalue = self.moduleUtil.deleteHook()
|
||||
|
||||
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)
|
||||
|
@ -1,82 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Pierre-Louis Bonicoli <pierre-louis@libregerbil.fr>
|
||||
|
||||
# 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)
|
||||
|
||||
import json
|
||||
|
||||
from units.compat.mock import MagicMock
|
||||
from ansible.modules.source_control import gitlab_project
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_gitlab_project(mocker):
|
||||
mocker.patch.object(gitlab_project, 'HAS_GITLAB_PACKAGE', mocker.PropertyMock(return_value=True))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
|
||||
@pytest.mark.usefixtures('patch_ansible_module')
|
||||
def test_without_required_parameters(capfd):
|
||||
"""Failure must occurs when all parameters are missing"""
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
gitlab_project.main()
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results['failed']
|
||||
assert 'missing required arguments' in results['msg']
|
||||
|
||||
|
||||
TEST_CASES = [
|
||||
[
|
||||
{
|
||||
'server_url': 'http://gitlab.test/gitlab',
|
||||
'validate_certs': True,
|
||||
'login_user': 'john',
|
||||
'login_token': 'TOKEN',
|
||||
'name': 'new_test_repo',
|
||||
'group': 'my_repo_group',
|
||||
'public': True,
|
||||
'visibility_level': 20,
|
||||
'issues_enabled': False,
|
||||
'wiki_enabled': True,
|
||||
'snippets_enabled': True,
|
||||
'import_url': 'http://gitlab.test/gitlab/gitrepothatdoesnotexist.git',
|
||||
'state': 'present'
|
||||
},
|
||||
{
|
||||
'msg': "Failed to create project 'new_test_repo'",
|
||||
'failed': True,
|
||||
}
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, indirect=['patch_ansible_module'])
|
||||
@pytest.mark.usefixtures('patch_ansible_module')
|
||||
def test_fail_if_url_import_doesnt_exist(mocker, capfd, patch_gitlab_project, testcase):
|
||||
""" Test for #36495
|
||||
|
||||
Ensure errors are reported (meaning task report a failure),
|
||||
for example when url_import doesn't exist, an error must occur.
|
||||
"""
|
||||
|
||||
git = MagicMock()
|
||||
git.createprojectuser.return_value = False
|
||||
|
||||
gitlab = MagicMock()
|
||||
gitlab.Gitlab.return_value = git
|
||||
gitlab_project.gitlab = gitlab
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
gitlab_project.main()
|
||||
|
||||
# Check that 1. createprojectuser method has been called 2. with expected parameter
|
||||
assert git.createprojectuser.call_count == 1
|
||||
assert git.createprojectuser.call_args[1]['import_url'] == 'http://gitlab.test/gitlab/gitrepothatdoesnotexist.git'
|
||||
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results.get('failed') == testcase.get('failed')
|
||||
assert results['msg'] == testcase['msg']
|
||||
from __future__ import absolute_import
|
||||
|
||||
from ansible.modules.source_control.gitlab_project import GitLabProject
|
||||
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_get_group, resp_get_project_by_name, resp_create_project,
|
||||
resp_get_project, resp_delete_project, resp_get_user)
|
||||
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import Project
|
||||
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
class TestGitlabProject(GitlabModuleTestCase):
|
||||
@with_httmock(resp_get_user)
|
||||
def setUp(self):
|
||||
super(TestGitlabProject, self).setUp()
|
||||
|
||||
self.gitlab_instance.user = self.gitlab_instance.users.get(1)
|
||||
self.moduleUtil = GitLabProject(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_get_project_by_name)
|
||||
def test_project_exist(self):
|
||||
group = self.gitlab_instance.groups.get(1)
|
||||
|
||||
rvalue = self.moduleUtil.existsProject(group, "diaspora-client")
|
||||
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
rvalue = self.moduleUtil.existsProject(group, "missing-project")
|
||||
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_create_project)
|
||||
def test_create_project(self):
|
||||
group = self.gitlab_instance.groups.get(1)
|
||||
project = self.moduleUtil.createProject(group, {"name": "Diaspora Client", "path": "diaspora-client", "namespace_id": group.id})
|
||||
|
||||
self.assertEqual(type(project), Project)
|
||||
self.assertEqual(project.name, "Diaspora Client")
|
||||
|
||||
@with_httmock(resp_get_project)
|
||||
def test_update_project(self):
|
||||
project = self.gitlab_instance.projects.get(1)
|
||||
|
||||
changed, newProject = self.moduleUtil.updateProject(project, {"name": "New Name"})
|
||||
|
||||
self.assertEqual(changed, True)
|
||||
self.assertEqual(type(newProject), Project)
|
||||
self.assertEqual(newProject.name, "New Name")
|
||||
|
||||
changed, newProject = self.moduleUtil.updateProject(project, {"name": "New Name"})
|
||||
|
||||
self.assertEqual(changed, False)
|
||||
self.assertEqual(newProject.name, "New Name")
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_get_project_by_name)
|
||||
@with_httmock(resp_delete_project)
|
||||
def test_delete_project(self):
|
||||
group = self.gitlab_instance.groups.get(1)
|
||||
|
||||
self.moduleUtil.existsProject(group, "diaspora-client")
|
||||
|
||||
rvalue = self.moduleUtil.deleteProject()
|
||||
|
||||
self.assertEqual(rvalue, None)
|
||||
|
@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 __future__ import absolute_import
|
||||
|
||||
from ansible.modules.source_control.gitlab_runner import GitLabRunner
|
||||
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_find_runners, resp_get_runner,
|
||||
resp_create_runner, resp_delete_runner)
|
||||
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import Runner
|
||||
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
class TestGitlabRunner(GitlabModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGitlabRunner, self).setUp()
|
||||
|
||||
self.moduleUtil = GitLabRunner(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
@with_httmock(resp_find_runners)
|
||||
@with_httmock(resp_get_runner)
|
||||
def test_runner_exist(self):
|
||||
rvalue = self.moduleUtil.existsRunner("test-1-20150125")
|
||||
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
rvalue = self.moduleUtil.existsRunner("test-3-00000000")
|
||||
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
@with_httmock(resp_create_runner)
|
||||
def test_create_runner(self):
|
||||
runner = self.moduleUtil.createRunner({"token": "token", "description": "test-1-20150125"})
|
||||
|
||||
self.assertEqual(type(runner), Runner)
|
||||
self.assertEqual(runner.description, "test-1-20150125")
|
||||
|
||||
@with_httmock(resp_find_runners)
|
||||
@with_httmock(resp_get_runner)
|
||||
def test_update_runner(self):
|
||||
runner = self.moduleUtil.findRunner("test-1-20150125")
|
||||
|
||||
changed, newRunner = self.moduleUtil.updateRunner(runner, {"description": "Runner description"})
|
||||
|
||||
self.assertEqual(changed, True)
|
||||
self.assertEqual(type(newRunner), Runner)
|
||||
self.assertEqual(newRunner.description, "Runner description")
|
||||
|
||||
changed, newRunner = self.moduleUtil.updateRunner(runner, {"description": "Runner description"})
|
||||
|
||||
self.assertEqual(changed, False)
|
||||
self.assertEqual(newRunner.description, "Runner description")
|
||||
|
||||
@with_httmock(resp_find_runners)
|
||||
@with_httmock(resp_get_runner)
|
||||
@with_httmock(resp_delete_runner)
|
||||
def test_delete_runner(self):
|
||||
self.moduleUtil.existsRunner("test-1-20150125")
|
||||
|
||||
rvalue = self.moduleUtil.deleteRunner()
|
||||
|
||||
self.assertEqual(rvalue, None)
|
@ -0,0 +1,133 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 __future__ import absolute_import
|
||||
|
||||
from ansible.modules.source_control.gitlab_user import GitLabUser
|
||||
|
||||
from .gitlab import (GitlabModuleTestCase,
|
||||
python_version_match_requirement,
|
||||
resp_find_user, resp_get_user, resp_get_user_keys,
|
||||
resp_create_user_keys, resp_create_user, resp_delete_user,
|
||||
resp_get_member, resp_get_group, resp_add_member,
|
||||
resp_update_member, resp_get_member)
|
||||
|
||||
# Gitlab module requirements
|
||||
if python_version_match_requirement():
|
||||
from gitlab.v4.objects import User
|
||||
|
||||
# Unit tests requirements
|
||||
from httmock import with_httmock # noqa
|
||||
|
||||
|
||||
class TestGitlabUser(GitlabModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGitlabUser, self).setUp()
|
||||
|
||||
self.moduleUtil = GitLabUser(module=self.mock_module, gitlab_instance=self.gitlab_instance)
|
||||
|
||||
@with_httmock(resp_find_user)
|
||||
def test_exist_user(self):
|
||||
rvalue = self.moduleUtil.existsUser("john_smith")
|
||||
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
rvalue = self.moduleUtil.existsUser("paul_smith")
|
||||
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
@with_httmock(resp_find_user)
|
||||
def test_find_user(self):
|
||||
user = self.moduleUtil.findUser("john_smith")
|
||||
|
||||
self.assertEqual(type(user), User)
|
||||
self.assertEqual(user.name, "John Smith")
|
||||
self.assertEqual(user.id, 1)
|
||||
|
||||
@with_httmock(resp_create_user)
|
||||
def test_create_user(self):
|
||||
user = self.moduleUtil.createUser({'email': 'john@example.com', 'password': 's3cur3s3cr3T',
|
||||
'username': 'john_smith', 'name': 'John Smith'})
|
||||
self.assertEqual(type(user), User)
|
||||
self.assertEqual(user.name, "John Smith")
|
||||
self.assertEqual(user.id, 1)
|
||||
|
||||
@with_httmock(resp_get_user)
|
||||
def test_update_user(self):
|
||||
user = self.gitlab_instance.users.get(1)
|
||||
changed, newUser = self.moduleUtil.updateUser(user, {'name': "Jack Smith", "is_admin": "true"})
|
||||
|
||||
self.assertEqual(changed, True)
|
||||
self.assertEqual(newUser.name, "Jack Smith")
|
||||
self.assertEqual(newUser.is_admin, "true")
|
||||
|
||||
changed, newUser = self.moduleUtil.updateUser(user, {'name': "Jack Smith"})
|
||||
|
||||
self.assertEqual(changed, False)
|
||||
|
||||
@with_httmock(resp_find_user)
|
||||
@with_httmock(resp_delete_user)
|
||||
def test_delete_user(self):
|
||||
self.moduleUtil.existsUser("john_smith")
|
||||
rvalue = self.moduleUtil.deleteUser()
|
||||
|
||||
self.assertEqual(rvalue, None)
|
||||
|
||||
@with_httmock(resp_get_user)
|
||||
@with_httmock(resp_get_user_keys)
|
||||
def test_sshkey_exist(self):
|
||||
user = self.gitlab_instance.users.get(1)
|
||||
|
||||
exist = self.moduleUtil.sshKeyExists(user, "Public key")
|
||||
self.assertEqual(exist, True)
|
||||
|
||||
notExist = self.moduleUtil.sshKeyExists(user, "Private key")
|
||||
self.assertEqual(notExist, False)
|
||||
|
||||
@with_httmock(resp_get_user)
|
||||
@with_httmock(resp_create_user_keys)
|
||||
@with_httmock(resp_get_user_keys)
|
||||
def test_create_sshkey(self):
|
||||
user = self.gitlab_instance.users.get(1)
|
||||
|
||||
rvalue = self.moduleUtil.addSshKeyToUser(user, {
|
||||
'name': "Public key",
|
||||
'file': "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJe"
|
||||
"jgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4"
|
||||
"soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="})
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
rvalue = self.moduleUtil.addSshKeyToUser(user, {
|
||||
'name': "Private key",
|
||||
'file': "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDA1YotVDm2mAyk2tPt4E7AHm01sS6JZmcU"
|
||||
"dRuSuA5zszUJzYPPUSRAX3BCgTqLqYx//UuVncK7YqLVSbbwjKR2Ez5lISgCnVfLVEXzwhv+"
|
||||
"xawxKWmI7hJ5S0tOv6MJ+IxyTa4xcKwJTwB86z22n9fVOQeJTR2dSOH1WJrf0PvRk+KVNY2j"
|
||||
"TiGHTi9AIjLnyD/jWRpOgtdfkLRc8EzAWrWlgNmH2WOKBw6za0az6XoG75obUdFVdW3qcD0x"
|
||||
"c809OHLi7FDf+E7U4wiZJCFuUizMeXyuK/SkaE1aee4Qp5R4dxTR4TP9M1XAYkf+kF0W9srZ+mhF069XD/zhUPJsvwEF"})
|
||||
self.assertEqual(rvalue, True)
|
||||
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_get_member)
|
||||
def test_find_member(self):
|
||||
group = self.gitlab_instance.groups.get(1)
|
||||
|
||||
user = self.moduleUtil.findMember(group, 1)
|
||||
self.assertEqual(user.username, "raymond_smith")
|
||||
|
||||
@with_httmock(resp_get_user)
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_get_group)
|
||||
@with_httmock(resp_get_member)
|
||||
@with_httmock(resp_add_member)
|
||||
@with_httmock(resp_update_member)
|
||||
def test_assign_user_to_group(self):
|
||||
group = self.gitlab_instance.groups.get(1)
|
||||
user = self.gitlab_instance.users.get(1)
|
||||
|
||||
rvalue = self.moduleUtil.assignUserToGroup(user, group.id, "developer")
|
||||
self.assertEqual(rvalue, False)
|
||||
|
||||
rvalue = self.moduleUtil.assignUserToGroup(user, group.id, "guest")
|
||||
self.assertEqual(rvalue, True)
|
Loading…
Reference in New Issue