diff options
Diffstat (limited to 'tests/unit')
59 files changed, 0 insertions, 6753 deletions
diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/unit/__init__.py +++ /dev/null diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py deleted file mode 100644 index f58c77a..0000000 --- a/tests/unit/conftest.py +++ /dev/null @@ -1,84 +0,0 @@ -import pytest - -import gitlab - - -@pytest.fixture -def gl(): - return gitlab.Gitlab( - "http://localhost", - private_token="private_token", - ssl_verify=True, - api_version="4", - ) - - -@pytest.fixture -def gl_retry(): - return gitlab.Gitlab( - "http://localhost", - private_token="private_token", - ssl_verify=True, - api_version="4", - retry_transient_errors=True, - ) - - -# Todo: parametrize, but check what tests it's really useful for -@pytest.fixture -def gl_trailing(): - return gitlab.Gitlab( - "http://localhost/", private_token="private_token", api_version="4" - ) - - -@pytest.fixture -def default_config(tmpdir): - valid_config = """[global] - default = one - ssl_verify = true - timeout = 2 - - [one] - url = http://one.url - private_token = ABCDEF - """ - - config_path = tmpdir.join("python-gitlab.cfg") - config_path.write(valid_config) - return str(config_path) - - -@pytest.fixture -def tag_name(): - return "v1.0.0" - - -@pytest.fixture -def group(gl): - return gl.groups.get(1, lazy=True) - - -@pytest.fixture -def project(gl): - return gl.projects.get(1, lazy=True) - - -@pytest.fixture -def project_issue(project): - return project.issues.get(1, lazy=True) - - -@pytest.fixture -def project_merge_request(project): - return project.mergerequests.get(1, lazy=True) - - -@pytest.fixture -def release(project, tag_name): - return project.releases.get(tag_name, lazy=True) - - -@pytest.fixture -def user(gl): - return gl.users.get(1, lazy=True) diff --git a/tests/unit/data/todo.json b/tests/unit/data/todo.json deleted file mode 100644 index 93b2151..0000000 --- a/tests/unit/data/todo.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { - "id": 102, - "project": { - "id": 2, - "name": "Gitlab Ce", - "name_with_namespace": "Gitlab Org / Gitlab Ce", - "path": "gitlab-ce", - "path_with_namespace": "gitlab-org/gitlab-ce" - }, - "author": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - "web_url": "https://gitlab.example.com/root" - }, - "action_name": "marked", - "target_type": "MergeRequest", - "target": { - "id": 34, - "iid": 7, - "project_id": 2, - "title": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", - "description": "Et ea et omnis illum cupiditate. Dolor aspernatur tenetur ducimus facilis est nihil. Quo esse cupiditate molestiae illo corrupti qui quidem dolor.", - "state": "opened", - "created_at": "2016-06-17T07:49:24.419Z", - "updated_at": "2016-06-17T07:52:43.484Z", - "target_branch": "tutorials_git_tricks", - "source_branch": "DNSBL_docs", - "upvotes": 0, - "downvotes": 0, - "author": { - "name": "Maxie Medhurst", - "username": "craig_rutherford", - "id": 12, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", - "web_url": "https://gitlab.example.com/craig_rutherford" - }, - "assignee": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - "web_url": "https://gitlab.example.com/root" - }, - "source_project_id": 2, - "target_project_id": 2, - "labels": [], - "work_in_progress": false, - "milestone": { - "id": 32, - "iid": 2, - "project_id": 2, - "title": "v1.0", - "description": "Assumenda placeat ea voluptatem voluptate qui.", - "state": "active", - "created_at": "2016-06-17T07:47:34.163Z", - "updated_at": "2016-06-17T07:47:34.163Z", - "due_date": null - }, - "merge_when_pipeline_succeeds": false, - "merge_status": "cannot_be_merged", - "subscribed": true, - "user_notes_count": 7 - }, - "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ce/merge_requests/7", - "body": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", - "state": "pending", - "created_at": "2016-06-17T07:52:35.225Z" - } -] diff --git a/tests/unit/mixins/__init__.py b/tests/unit/mixins/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/unit/mixins/__init__.py +++ /dev/null diff --git a/tests/unit/mixins/test_meta_mixins.py b/tests/unit/mixins/test_meta_mixins.py deleted file mode 100644 index 4c8845b..0000000 --- a/tests/unit/mixins/test_meta_mixins.py +++ /dev/null @@ -1,58 +0,0 @@ -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - DeleteMixin, - GetMixin, - ListMixin, - NoUpdateMixin, - RetrieveMixin, - UpdateMixin, -) - - -def test_retrieve_mixin(): - class M(RetrieveMixin): - pass - - obj = M() - assert hasattr(obj, "list") - assert hasattr(obj, "get") - assert not hasattr(obj, "create") - assert not hasattr(obj, "update") - assert not hasattr(obj, "delete") - assert isinstance(obj, ListMixin) - assert isinstance(obj, GetMixin) - - -def test_crud_mixin(): - class M(CRUDMixin): - pass - - obj = M() - assert hasattr(obj, "get") - assert hasattr(obj, "list") - assert hasattr(obj, "create") - assert hasattr(obj, "update") - assert hasattr(obj, "delete") - assert isinstance(obj, ListMixin) - assert isinstance(obj, GetMixin) - assert isinstance(obj, CreateMixin) - assert isinstance(obj, UpdateMixin) - assert isinstance(obj, DeleteMixin) - - -def test_no_update_mixin(): - class M(NoUpdateMixin): - pass - - obj = M() - assert hasattr(obj, "get") - assert hasattr(obj, "list") - assert hasattr(obj, "create") - assert not hasattr(obj, "update") - assert hasattr(obj, "delete") - assert isinstance(obj, ListMixin) - assert isinstance(obj, GetMixin) - assert isinstance(obj, CreateMixin) - assert not isinstance(obj, UpdateMixin) - assert isinstance(obj, DeleteMixin) diff --git a/tests/unit/mixins/test_mixin_methods.py b/tests/unit/mixins/test_mixin_methods.py deleted file mode 100644 index 626230e..0000000 --- a/tests/unit/mixins/test_mixin_methods.py +++ /dev/null @@ -1,300 +0,0 @@ -import pytest -from httmock import HTTMock, response, urlmatch # noqa - -from gitlab import base -from gitlab.mixins import ( - CreateMixin, - DeleteMixin, - GetMixin, - GetWithoutIdMixin, - ListMixin, - RefreshMixin, - SaveMixin, - SetMixin, - UpdateMixin, -) - - -class FakeObject(base.RESTObject): - pass - - -class FakeManager(base.RESTManager): - _path = "/tests" - _obj_cls = FakeObject - - -def test_get_mixin(gl): - class M(GetMixin, FakeManager): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests/42", method="get") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"id": 42, "foo": "bar"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj = mgr.get(42) - assert isinstance(obj, FakeObject) - assert obj.foo == "bar" - assert obj.id == 42 - - -def test_refresh_mixin(gl): - class TestClass(RefreshMixin, FakeObject): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests/42", method="get") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"id": 42, "foo": "bar"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = FakeManager(gl) - obj = TestClass(mgr, {"id": 42}) - res = obj.refresh() - assert res is None - assert obj.foo == "bar" - assert obj.id == 42 - - -def test_get_without_id_mixin(gl): - class M(GetWithoutIdMixin, FakeManager): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests", method="get") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"foo": "bar"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj = mgr.get() - assert isinstance(obj, FakeObject) - assert obj.foo == "bar" - assert not hasattr(obj, "id") - - -def test_list_mixin(gl): - class M(ListMixin, FakeManager): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests", method="get") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '[{"id": 42, "foo": "bar"},{"id": 43, "foo": "baz"}]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - # test RESTObjectList - mgr = M(gl) - obj_list = mgr.list(as_list=False) - assert isinstance(obj_list, base.RESTObjectList) - for obj in obj_list: - assert isinstance(obj, FakeObject) - assert obj.id in (42, 43) - - # test list() - obj_list = mgr.list(all=True) - assert isinstance(obj_list, list) - assert obj_list[0].id == 42 - assert obj_list[1].id == 43 - assert isinstance(obj_list[0], FakeObject) - assert len(obj_list) == 2 - - -def test_list_other_url(gl): - class M(ListMixin, FakeManager): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/others", method="get") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '[{"id": 42, "foo": "bar"}]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj_list = mgr.list(path="/others", as_list=False) - assert isinstance(obj_list, base.RESTObjectList) - obj = obj_list.next() - assert obj.id == 42 - assert obj.foo == "bar" - with pytest.raises(StopIteration): - obj_list.next() - - -def test_create_mixin_missing_attrs(gl): - class M(CreateMixin, FakeManager): - _create_attrs = base.RequiredOptional( - required=("foo",), optional=("bar", "baz") - ) - - mgr = M(gl) - data = {"foo": "bar", "baz": "blah"} - mgr._check_missing_create_attrs(data) - - data = {"baz": "blah"} - with pytest.raises(AttributeError) as error: - mgr._check_missing_create_attrs(data) - assert "foo" in str(error.value) - - -def test_create_mixin(gl): - class M(CreateMixin, FakeManager): - _create_attrs = base.RequiredOptional( - required=("foo",), optional=("bar", "baz") - ) - _update_attrs = base.RequiredOptional(required=("foo",), optional=("bam",)) - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests", method="post") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"id": 42, "foo": "bar"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj = mgr.create({"foo": "bar"}) - assert isinstance(obj, FakeObject) - assert obj.id == 42 - assert obj.foo == "bar" - - -def test_create_mixin_custom_path(gl): - class M(CreateMixin, FakeManager): - _create_attrs = base.RequiredOptional( - required=("foo",), optional=("bar", "baz") - ) - _update_attrs = base.RequiredOptional(required=("foo",), optional=("bam",)) - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/others", method="post") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"id": 42, "foo": "bar"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj = mgr.create({"foo": "bar"}, path="/others") - assert isinstance(obj, FakeObject) - assert obj.id == 42 - assert obj.foo == "bar" - - -def test_update_mixin_missing_attrs(gl): - class M(UpdateMixin, FakeManager): - _update_attrs = base.RequiredOptional( - required=("foo",), optional=("bar", "baz") - ) - - mgr = M(gl) - data = {"foo": "bar", "baz": "blah"} - mgr._check_missing_update_attrs(data) - - data = {"baz": "blah"} - with pytest.raises(AttributeError) as error: - mgr._check_missing_update_attrs(data) - assert "foo" in str(error.value) - - -def test_update_mixin(gl): - class M(UpdateMixin, FakeManager): - _create_attrs = base.RequiredOptional( - required=("foo",), optional=("bar", "baz") - ) - _update_attrs = base.RequiredOptional(required=("foo",), optional=("bam",)) - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests/42", method="put") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"id": 42, "foo": "baz"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - server_data = mgr.update(42, {"foo": "baz"}) - assert isinstance(server_data, dict) - assert server_data["id"] == 42 - assert server_data["foo"] == "baz" - - -def test_update_mixin_no_id(gl): - class M(UpdateMixin, FakeManager): - _create_attrs = base.RequiredOptional( - required=("foo",), optional=("bar", "baz") - ) - _update_attrs = base.RequiredOptional(required=("foo",), optional=("bam",)) - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests", method="put") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"foo": "baz"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - server_data = mgr.update(new_data={"foo": "baz"}) - assert isinstance(server_data, dict) - assert server_data["foo"] == "baz" - - -def test_delete_mixin(gl): - class M(DeleteMixin, FakeManager): - pass - - @urlmatch( - scheme="http", netloc="localhost", path="/api/v4/tests/42", method="delete" - ) - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = "" - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - mgr.delete(42) - - -def test_save_mixin(gl): - class M(UpdateMixin, FakeManager): - pass - - class TestClass(SaveMixin, base.RESTObject): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests/42", method="put") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"id": 42, "foo": "baz"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj = TestClass(mgr, {"id": 42, "foo": "bar"}) - obj.foo = "baz" - obj.save() - assert obj._attrs["foo"] == "baz" - assert obj._updated_attrs == {} - - -def test_set_mixin(gl): - class M(SetMixin, FakeManager): - pass - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests/foo", method="put") - def resp_cont(url, request): - headers = {"Content-Type": "application/json"} - content = '{"key": "foo", "value": "bar"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - mgr = M(gl) - obj = mgr.set("foo", "bar") - assert isinstance(obj, FakeObject) - assert obj.key == "foo" - assert obj.value == "bar" diff --git a/tests/unit/mixins/test_object_mixins_attributes.py b/tests/unit/mixins/test_object_mixins_attributes.py deleted file mode 100644 index d54fa3a..0000000 --- a/tests/unit/mixins/test_object_mixins_attributes.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 Mika Mäenpää <mika.j.maenpaa@tut.fi>, -# Tampere University of Technology -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from gitlab.mixins import ( - AccessRequestMixin, - SetMixin, - SubscribableMixin, - TimeTrackingMixin, - TodoMixin, - UserAgentDetailMixin, -) - - -def test_access_request_mixin(): - class TestClass(AccessRequestMixin): - pass - - obj = TestClass() - assert hasattr(obj, "approve") - - -def test_subscribable_mixin(): - class TestClass(SubscribableMixin): - pass - - obj = TestClass() - assert hasattr(obj, "subscribe") - assert hasattr(obj, "unsubscribe") - - -def test_todo_mixin(): - class TestClass(TodoMixin): - pass - - obj = TestClass() - assert hasattr(obj, "todo") - - -def test_time_tracking_mixin(): - class TestClass(TimeTrackingMixin): - pass - - obj = TestClass() - assert hasattr(obj, "time_stats") - assert hasattr(obj, "time_estimate") - assert hasattr(obj, "reset_time_estimate") - assert hasattr(obj, "add_spent_time") - assert hasattr(obj, "reset_spent_time") - - -def test_set_mixin(): - class TestClass(SetMixin): - pass - - obj = TestClass() - assert hasattr(obj, "set") - - -def test_user_agent_detail_mixin(): - class TestClass(UserAgentDetailMixin): - pass - - obj = TestClass() - assert hasattr(obj, "user_agent_detail") diff --git a/tests/unit/objects/__init__.py b/tests/unit/objects/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/unit/objects/__init__.py +++ /dev/null diff --git a/tests/unit/objects/conftest.py b/tests/unit/objects/conftest.py deleted file mode 100644 index d8a40d9..0000000 --- a/tests/unit/objects/conftest.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Common mocks for resources in gitlab.v4.objects""" - -import re - -import pytest -import responses - - -@pytest.fixture -def binary_content(): - return b"binary content" - - -@pytest.fixture -def accepted_content(): - return {"message": "202 Accepted"} - - -@pytest.fixture -def created_content(): - return {"message": "201 Created"} - - -@pytest.fixture -def no_content(): - return {"message": "204 No Content"} - - -@pytest.fixture -def resp_export(accepted_content, binary_content): - """Common fixture for group and project exports.""" - export_status_content = { - "id": 1, - "description": "Itaque perspiciatis minima aspernatur", - "name": "Gitlab Test", - "name_with_namespace": "Gitlab Org / Gitlab Test", - "path": "gitlab-test", - "path_with_namespace": "gitlab-org/gitlab-test", - "created_at": "2017-08-29T04:36:44.383Z", - "export_status": "finished", - "_links": { - "api_url": "https://gitlab.test/api/v4/projects/1/export/download", - "web_url": "https://gitlab.test/gitlab-test/download_export", - }, - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.POST, - url=re.compile(r".*/api/v4/(groups|projects)/1/export"), - json=accepted_content, - content_type="application/json", - status=202, - ) - rsps.add( - method=responses.GET, - url=re.compile(r".*/api/v4/(groups|projects)/1/export/download"), - body=binary_content, - content_type="application/octet-stream", - status=200, - ) - # Currently only project export supports status checks - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/export", - json=export_status_content, - content_type="application/json", - status=200, - ) - yield rsps diff --git a/tests/unit/objects/test_appearance.py b/tests/unit/objects/test_appearance.py deleted file mode 100644 index 0de6524..0000000 --- a/tests/unit/objects/test_appearance.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/appearance.html -""" - -import pytest -import responses - -title = "GitLab Test Instance" -description = "gitlab-test.example.com" -new_title = "new-title" -new_description = "new-description" - - -@pytest.fixture -def resp_application_appearance(): - content = { - "title": title, - "description": description, - "logo": "/uploads/-/system/appearance/logo/1/logo.png", - "header_logo": "/uploads/-/system/appearance/header_logo/1/header.png", - "favicon": "/uploads/-/system/appearance/favicon/1/favicon.png", - "new_project_guidelines": "Please read the FAQs for help.", - "header_message": "", - "footer_message": "", - "message_background_color": "#e75e40", - "message_font_color": "#ffffff", - "email_header_and_footer_enabled": False, - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/application/appearance", - json=content, - content_type="application/json", - status=200, - ) - - updated_content = dict(content) - updated_content["title"] = new_title - updated_content["description"] = new_description - - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/application/appearance", - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_get_update_appearance(gl, resp_application_appearance): - appearance = gl.appearance.get() - assert appearance.title == title - assert appearance.description == description - appearance.title = new_title - appearance.description = new_description - appearance.save() - assert appearance.title == new_title - assert appearance.description == new_description - - -def test_update_appearance(gl, resp_application_appearance): - gl.appearance.update(title=new_title, description=new_description) diff --git a/tests/unit/objects/test_applications.py b/tests/unit/objects/test_applications.py deleted file mode 100644 index 61de019..0000000 --- a/tests/unit/objects/test_applications.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/applications.html -""" - -import pytest -import responses - -title = "GitLab Test Instance" -description = "gitlab-test.example.com" -new_title = "new-title" -new_description = "new-description" - - -@pytest.fixture -def resp_application_create(): - content = { - "name": "test_app", - "redirect_uri": "http://localhost:8080", - "scopes": ["api", "email"], - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/applications", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_create_application(gl, resp_application_create): - application = gl.applications.create( - { - "name": "test_app", - "redirect_uri": "http://localhost:8080", - "scopes": ["api", "email"], - "confidential": False, - } - ) - assert application.name == "test_app" - assert application.redirect_uri == "http://localhost:8080" - assert application.scopes == ["api", "email"] diff --git a/tests/unit/objects/test_audit_events.py b/tests/unit/objects/test_audit_events.py deleted file mode 100644 index aba778b..0000000 --- a/tests/unit/objects/test_audit_events.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/audit_events.html#project-audit-events -""" - -import re - -import pytest -import responses - -from gitlab.v4.objects.audit_events import ( - AuditEvent, - GroupAuditEvent, - ProjectAuditEvent, -) - -id = 5 - -audit_events_content = { - "id": 5, - "author_id": 1, - "entity_id": 7, - "entity_type": "Project", - "details": { - "change": "prevent merge request approval from reviewers", - "from": "", - "to": "true", - "author_name": "Administrator", - "target_id": 7, - "target_type": "Project", - "target_details": "twitter/typeahead-js", - "ip_address": "127.0.0.1", - "entity_path": "twitter/typeahead-js", - }, - "created_at": "2020-05-26T22:55:04.230Z", -} - -audit_events_url = re.compile( - r"http://localhost/api/v4/((groups|projects)/1/)?audit_events" -) - -audit_events_url_id = re.compile( - rf"http://localhost/api/v4/((groups|projects)/1/)?audit_events/{id}" -) - - -@pytest.fixture -def resp_list_audit_events(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=audit_events_url, - json=[audit_events_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_audit_event(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=audit_events_url_id, - json=audit_events_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_instance_audit_events(gl, resp_list_audit_events): - audit_events = gl.audit_events.list() - assert isinstance(audit_events, list) - assert isinstance(audit_events[0], AuditEvent) - assert audit_events[0].id == id - - -def test_get_instance_audit_events(gl, resp_get_audit_event): - audit_event = gl.audit_events.get(id) - assert isinstance(audit_event, AuditEvent) - assert audit_event.id == id - - -def test_list_group_audit_events(group, resp_list_audit_events): - audit_events = group.audit_events.list() - assert isinstance(audit_events, list) - assert isinstance(audit_events[0], GroupAuditEvent) - assert audit_events[0].id == id - - -def test_get_group_audit_events(group, resp_get_audit_event): - audit_event = group.audit_events.get(id) - assert isinstance(audit_event, GroupAuditEvent) - assert audit_event.id == id - - -def test_list_project_audit_events(project, resp_list_audit_events): - audit_events = project.audit_events.list() - assert isinstance(audit_events, list) - assert isinstance(audit_events[0], ProjectAuditEvent) - assert audit_events[0].id == id - - -def test_get_project_audit_events(project, resp_get_audit_event): - audit_event = project.audit_events.get(id) - assert isinstance(audit_event, ProjectAuditEvent) - assert audit_event.id == id diff --git a/tests/unit/objects/test_badges.py b/tests/unit/objects/test_badges.py deleted file mode 100644 index e226684..0000000 --- a/tests/unit/objects/test_badges.py +++ /dev/null @@ -1,210 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/project_badges.html -GitLab API: https://docs.gitlab.com/ee/api/group_badges.html -""" -import re - -import pytest -import responses - -from gitlab.v4.objects import GroupBadge, ProjectBadge - -link_url = ( - "http://example.com/ci_status.svg?project=example-org/example-project&ref=master" -) -image_url = "https://example.io/my/badge" - -rendered_link_url = ( - "http://example.com/ci_status.svg?project=example-org/example-project&ref=master" -) -rendered_image_url = "https://example.io/my/badge" - -new_badge = { - "link_url": link_url, - "image_url": image_url, -} - -badge_content = { - "name": "Coverage", - "id": 1, - "link_url": link_url, - "image_url": image_url, - "rendered_link_url": rendered_image_url, - "rendered_image_url": rendered_image_url, -} - -preview_badge_content = { - "link_url": link_url, - "image_url": image_url, - "rendered_link_url": rendered_link_url, - "rendered_image_url": rendered_image_url, -} - - -@pytest.fixture() -def resp_get_badge(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile(r"http://localhost/api/v4/(projects|groups)/1/badges/1"), - json=badge_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_list_badges(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile(r"http://localhost/api/v4/(projects|groups)/1/badges"), - json=[badge_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_create_badge(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url=re.compile(r"http://localhost/api/v4/(projects|groups)/1/badges"), - json=badge_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_update_badge(): - updated_content = dict(badge_content) - updated_content["link_url"] = "http://link_url" - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.PUT, - url=re.compile(r"http://localhost/api/v4/(projects|groups)/1/badges/1"), - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_delete_badge(no_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.DELETE, - url=re.compile(r"http://localhost/api/v4/(projects|groups)/1/badges/1"), - json=no_content, - content_type="application/json", - status=204, - ) - yield rsps - - -@pytest.fixture() -def resp_preview_badge(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile( - r"http://localhost/api/v4/(projects|groups)/1/badges/render" - ), - json=preview_badge_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_project_badges(project, resp_list_badges): - badges = project.badges.list() - assert isinstance(badges, list) - assert isinstance(badges[0], ProjectBadge) - - -def test_list_group_badges(group, resp_list_badges): - badges = group.badges.list() - assert isinstance(badges, list) - assert isinstance(badges[0], GroupBadge) - - -def test_get_project_badge(project, resp_get_badge): - badge = project.badges.get(1) - assert isinstance(badge, ProjectBadge) - assert badge.name == "Coverage" - assert badge.id == 1 - - -def test_get_group_badge(group, resp_get_badge): - badge = group.badges.get(1) - assert isinstance(badge, GroupBadge) - assert badge.name == "Coverage" - assert badge.id == 1 - - -def test_delete_project_badge(project, resp_delete_badge): - badge = project.badges.get(1, lazy=True) - badge.delete() - - -def test_delete_group_badge(group, resp_delete_badge): - badge = group.badges.get(1, lazy=True) - badge.delete() - - -def test_create_project_badge(project, resp_create_badge): - badge = project.badges.create(new_badge) - assert isinstance(badge, ProjectBadge) - assert badge.image_url == image_url - - -def test_create_group_badge(group, resp_create_badge): - badge = group.badges.create(new_badge) - assert isinstance(badge, GroupBadge) - assert badge.image_url == image_url - - -def test_preview_project_badge(project, resp_preview_badge): - output = project.badges.render( - link_url=link_url, - image_url=image_url, - ) - assert isinstance(output, dict) - assert "rendered_link_url" in output - assert "rendered_image_url" in output - assert output["link_url"] == output["rendered_link_url"] - assert output["image_url"] == output["rendered_image_url"] - - -def test_preview_group_badge(group, resp_preview_badge): - output = group.badges.render( - link_url=link_url, - image_url=image_url, - ) - assert isinstance(output, dict) - assert "rendered_link_url" in output - assert "rendered_image_url" in output - assert output["link_url"] == output["rendered_link_url"] - assert output["image_url"] == output["rendered_image_url"] - - -def test_update_project_badge(project, resp_update_badge): - badge = project.badges.get(1, lazy=True) - badge.link_url = "http://link_url" - badge.save() - assert badge.link_url == "http://link_url" - - -def test_update_group_badge(group, resp_update_badge): - badge = group.badges.get(1, lazy=True) - badge.link_url = "http://link_url" - badge.save() - assert badge.link_url == "http://link_url" diff --git a/tests/unit/objects/test_bridges.py b/tests/unit/objects/test_bridges.py deleted file mode 100644 index 4d39186..0000000 --- a/tests/unit/objects/test_bridges.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/jobs.html#list-pipeline-bridges -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectPipelineBridge - - -@pytest.fixture -def resp_list_bridges(): - export_bridges_content = { - "commit": { - "author_email": "admin@example.com", - "author_name": "Administrator", - "created_at": "2015-12-24T16:51:14.000+01:00", - "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", - "message": "Test the CI integration.", - "short_id": "0ff3ae19", - "title": "Test the CI integration.", - }, - "allow_failure": False, - "created_at": "2015-12-24T15:51:21.802Z", - "started_at": "2015-12-24T17:54:27.722Z", - "finished_at": "2015-12-24T17:58:27.895Z", - "duration": 240, - "id": 7, - "name": "teaspoon", - "pipeline": { - "id": 6, - "ref": "master", - "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", - "status": "pending", - "created_at": "2015-12-24T15:50:16.123Z", - "updated_at": "2015-12-24T18:00:44.432Z", - "web_url": "https://example.com/foo/bar/pipelines/6", - }, - "ref": "master", - "stage": "test", - "status": "pending", - "tag": False, - "web_url": "https://example.com/foo/bar/-/jobs/7", - "user": { - "id": 1, - "name": "Administrator", - "username": "root", - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - "web_url": "http://gitlab.dev/root", - "created_at": "2015-12-21T13:14:24.077Z", - "public_email": "", - "skype": "", - "linkedin": "", - "twitter": "", - "website_url": "", - "organization": "", - }, - "downstream_pipeline": { - "id": 5, - "sha": "f62a4b2fb89754372a346f24659212eb8da13601", - "ref": "master", - "status": "pending", - "created_at": "2015-12-24T17:54:27.722Z", - "updated_at": "2015-12-24T17:58:27.896Z", - "web_url": "https://example.com/diaspora/diaspora-client/pipelines/5", - }, - } - - export_pipelines_content = [ - { - "id": 6, - "status": "pending", - "ref": "new-pipeline", - "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", - "web_url": "https://example.com/foo/bar/pipelines/47", - "created_at": "2016-08-11T11:28:34.085Z", - "updated_at": "2016-08-11T11:32:35.169Z", - }, - ] - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/pipelines/6/bridges", - json=[export_bridges_content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/pipelines", - json=export_pipelines_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_projects_pipelines_bridges(project, resp_list_bridges): - pipeline = project.pipelines.list()[0] - bridges = pipeline.bridges.list() - - assert isinstance(bridges, list) - assert isinstance(bridges[0], ProjectPipelineBridge) - assert bridges[0].downstream_pipeline["id"] == 5 - assert ( - bridges[0].downstream_pipeline["sha"] - == "f62a4b2fb89754372a346f24659212eb8da13601" - ) diff --git a/tests/unit/objects/test_commits.py b/tests/unit/objects/test_commits.py deleted file mode 100644 index 6b98117..0000000 --- a/tests/unit/objects/test_commits.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/commits.html -""" - -import pytest -import responses - - -@pytest.fixture -def resp_create_commit(): - content = { - "id": "ed899a2f4b50b4370feeea94676502b42383c746", - "short_id": "ed899a2f", - "title": "Commit message", - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/repository/commits", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_commit(): - get_content = { - "id": "6b2257eabcec3db1f59dafbd84935e3caea04235", - "short_id": "6b2257ea", - "title": "Initial commit", - } - revert_content = { - "id": "8b090c1b79a14f2bd9e8a738f717824ff53aebad", - "short_id": "8b090c1b", - "title": 'Revert "Initial commit"', - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/repository/commits/6b2257ea", - json=get_content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/repository/commits/6b2257ea/revert", - json=revert_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_commit_gpg_signature(): - content = { - "gpg_key_id": 1, - "gpg_key_primary_keyid": "8254AAB3FBD54AC9", - "gpg_key_user_name": "John Doe", - "gpg_key_user_email": "johndoe@example.com", - "verification_status": "verified", - "gpg_key_subkey_id": None, - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/repository/commits/6b2257ea/signature", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_get_commit(project, resp_commit): - commit = project.commits.get("6b2257ea") - assert commit.short_id == "6b2257ea" - assert commit.title == "Initial commit" - - -def test_create_commit(project, resp_create_commit): - data = { - "branch": "master", - "commit_message": "Commit message", - "actions": [ - { - "action": "create", - "file_path": "README", - "content": "", - } - ], - } - commit = project.commits.create(data) - assert commit.short_id == "ed899a2f" - assert commit.title == data["commit_message"] - - -def test_revert_commit(project, resp_commit): - commit = project.commits.get("6b2257ea", lazy=True) - revert_commit = commit.revert(branch="master") - assert revert_commit["short_id"] == "8b090c1b" - assert revert_commit["title"] == 'Revert "Initial commit"' - - -def test_get_commit_gpg_signature(project, resp_get_commit_gpg_signature): - commit = project.commits.get("6b2257ea", lazy=True) - signature = commit.signature() - assert signature["gpg_key_primary_keyid"] == "8254AAB3FBD54AC9" - assert signature["verification_status"] == "verified" diff --git a/tests/unit/objects/test_deploy_tokens.py b/tests/unit/objects/test_deploy_tokens.py deleted file mode 100644 index 66a79fa..0000000 --- a/tests/unit/objects/test_deploy_tokens.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectDeployToken - -create_content = { - "id": 1, - "name": "test_deploy_token", - "username": "custom-user", - "expires_at": "2022-01-01T00:00:00.000Z", - "token": "jMRvtPNxrn3crTAGukpZ", - "scopes": ["read_repository"], -} - - -@pytest.fixture -def resp_deploy_token_create(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/deploy_tokens", - json=create_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_deploy_tokens(gl, resp_deploy_token_create): - deploy_token = gl.projects.get(1, lazy=True).deploytokens.create( - { - "name": "test_deploy_token", - "expires_at": "2022-01-01T00:00:00.000Z", - "username": "custom-user", - "scopes": ["read_repository"], - } - ) - assert isinstance(deploy_token, ProjectDeployToken) - assert deploy_token.id == 1 - assert deploy_token.expires_at == "2022-01-01T00:00:00.000Z" - assert deploy_token.username == "custom-user" - assert deploy_token.scopes == ["read_repository"] diff --git a/tests/unit/objects/test_deployments.py b/tests/unit/objects/test_deployments.py deleted file mode 100644 index 3cde8fe..0000000 --- a/tests/unit/objects/test_deployments.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/deployments.html -""" -import pytest -import responses - - -@pytest.fixture -def resp_deployment(): - content = {"id": 42, "status": "success", "ref": "master"} - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/deployments", - json=content, - content_type="application/json", - status=200, - ) - - updated_content = dict(content) - updated_content["status"] = "failed" - - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/projects/1/deployments/42", - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_deployment(project, resp_deployment): - deployment = project.deployments.create( - { - "environment": "Test", - "sha": "1agf4gs", - "ref": "master", - "tag": False, - "status": "created", - } - ) - assert deployment.id == 42 - assert deployment.status == "success" - assert deployment.ref == "master" - - deployment.status = "failed" - deployment.save() - assert deployment.status == "failed" diff --git a/tests/unit/objects/test_environments.py b/tests/unit/objects/test_environments.py deleted file mode 100644 index b49a1db..0000000 --- a/tests/unit/objects/test_environments.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/environments.html -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectEnvironment - - -@pytest.fixture -def resp_get_environment(): - content = {"name": "environment_name", "id": 1, "last_deployment": "sometime"} - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/environments/1", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_project_environments(project, resp_get_environment): - environment = project.environments.get(1) - assert isinstance(environment, ProjectEnvironment) - assert environment.id == 1 - assert environment.last_deployment == "sometime" - assert environment.name == "environment_name" diff --git a/tests/unit/objects/test_groups.py b/tests/unit/objects/test_groups.py deleted file mode 100644 index 37023d8..0000000 --- a/tests/unit/objects/test_groups.py +++ /dev/null @@ -1,155 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/groups.html -""" - -import re - -import pytest -import responses - -import gitlab -from gitlab.v4.objects import GroupDescendantGroup, GroupSubgroup - -subgroup_descgroup_content = [ - { - "id": 2, - "name": "Bar Group", - "path": "foo/bar", - "description": "A subgroup of Foo Group", - "visibility": "public", - "share_with_group_lock": False, - "require_two_factor_authentication": False, - "two_factor_grace_period": 48, - "project_creation_level": "developer", - "auto_devops_enabled": None, - "subgroup_creation_level": "owner", - "emails_disabled": None, - "mentions_disabled": None, - "lfs_enabled": True, - "default_branch_protection": 2, - "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/bar.jpg", - "web_url": "http://gitlab.example.com/groups/foo/bar", - "request_access_enabled": False, - "full_name": "Bar Group", - "full_path": "foo/bar", - "file_template_project_id": 1, - "parent_id": 123, - "created_at": "2020-01-15T12:36:29.590Z", - }, -] - - -@pytest.fixture -def resp_groups(): - content = {"name": "name", "id": 1, "path": "path"} - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/groups/1", - json=content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/groups", - json=[content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/groups", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_list_subgroups_descendant_groups(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile( - r"http://localhost/api/v4/groups/1/(subgroups|descendant_groups)" - ), - json=subgroup_descgroup_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_create_import(accepted_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/groups/import", - json=accepted_content, - content_type="application/json", - status=202, - ) - yield rsps - - -def test_get_group(gl, resp_groups): - data = gl.groups.get(1) - assert isinstance(data, gitlab.v4.objects.Group) - assert data.name == "name" - assert data.path == "path" - assert data.id == 1 - - -def test_create_group(gl, resp_groups): - name, path = "name", "path" - data = gl.groups.create({"name": name, "path": path}) - assert isinstance(data, gitlab.v4.objects.Group) - assert data.name == name - assert data.path == path - - -def test_create_group_export(group, resp_export): - export = group.exports.create() - assert export.message == "202 Accepted" - - -def test_list_group_subgroups(group, resp_list_subgroups_descendant_groups): - subgroups = group.subgroups.list() - assert isinstance(subgroups[0], GroupSubgroup) - assert subgroups[0].path == subgroup_descgroup_content[0]["path"] - - -def test_list_group_descendant_groups(group, resp_list_subgroups_descendant_groups): - descendant_groups = group.descendant_groups.list() - assert isinstance(descendant_groups[0], GroupDescendantGroup) - assert descendant_groups[0].path == subgroup_descgroup_content[0]["path"] - - -@pytest.mark.skip("GitLab API endpoint not implemented") -def test_refresh_group_export_status(group, resp_export): - export = group.exports.create() - export.refresh() - assert export.export_status == "finished" - - -def test_download_group_export(group, resp_export, binary_content): - export = group.exports.create() - download = export.download() - assert isinstance(download, bytes) - assert download == binary_content - - -def test_import_group(gl, resp_create_import): - group_import = gl.groups.import_group("file", "api-group", "API Group") - assert group_import["message"] == "202 Accepted" - - -@pytest.mark.skip("GitLab API endpoint not implemented") -def test_refresh_group_import_status(group, resp_groups): - group_import = group.imports.get() - group_import.refresh() - assert group_import.import_status == "finished" diff --git a/tests/unit/objects/test_hooks.py b/tests/unit/objects/test_hooks.py deleted file mode 100644 index 0f9dbe2..0000000 --- a/tests/unit/objects/test_hooks.py +++ /dev/null @@ -1,209 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/system_hooks.html -GitLab API: https://docs.gitlab.com/ce/api/groups.html#hooks -GitLab API: https://docs.gitlab.com/ee/api/projects.html#hooks -""" - -import re - -import pytest -import responses - -from gitlab.v4.objects import GroupHook, Hook, ProjectHook - -hooks_content = [ - { - "id": 1, - "url": "testurl", - "push_events": True, - "tag_push_events": True, - }, - { - "id": 2, - "url": "testurl_second", - "push_events": False, - "tag_push_events": False, - }, -] - -hook_content = hooks_content[0] - - -@pytest.fixture -def resp_hooks_list(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks"), - json=hooks_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_hook_get(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1"), - json=hook_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_hook_create(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url=re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks"), - json=hook_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_hook_update(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1") - rsps.add( - method=responses.GET, - url=pattern, - json=hook_content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.PUT, - url=pattern, - json=hook_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_hook_delete(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1") - rsps.add( - method=responses.GET, - url=pattern, - json=hook_content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.DELETE, - url=pattern, - status=204, - ) - yield rsps - - -def test_list_system_hooks(gl, resp_hooks_list): - hooks = gl.hooks.list() - assert hooks[0].id == 1 - assert hooks[0].url == "testurl" - assert hooks[1].id == 2 - assert hooks[1].url == "testurl_second" - - -def test_get_system_hook(gl, resp_hook_get): - data = gl.hooks.get(1) - assert isinstance(data, Hook) - assert data.url == "testurl" - assert data.id == 1 - - -def test_create_system_hook(gl, resp_hook_create): - hook = gl.hooks.create(hook_content) - assert hook.url == "testurl" - assert hook.push_events is True - assert hook.tag_push_events is True - - -# there is no update method for system hooks - - -def test_delete_system_hook(gl, resp_hook_delete): - hook = gl.hooks.get(1) - hook.delete() - gl.hooks.delete(1) - - -def test_list_group_hooks(group, resp_hooks_list): - hooks = group.hooks.list() - assert hooks[0].id == 1 - assert hooks[0].url == "testurl" - assert hooks[1].id == 2 - assert hooks[1].url == "testurl_second" - - -def test_get_group_hook(group, resp_hook_get): - data = group.hooks.get(1) - assert isinstance(data, GroupHook) - assert data.url == "testurl" - assert data.id == 1 - - -def test_create_group_hook(group, resp_hook_create): - hook = group.hooks.create(hook_content) - assert hook.url == "testurl" - assert hook.push_events is True - assert hook.tag_push_events is True - - -def test_update_group_hook(group, resp_hook_update): - hook = group.hooks.get(1) - assert hook.id == 1 - hook.url = "testurl_more" - hook.save() - - -def test_delete_group_hook(group, resp_hook_delete): - hook = group.hooks.get(1) - hook.delete() - group.hooks.delete(1) - - -def test_list_project_hooks(project, resp_hooks_list): - hooks = project.hooks.list() - assert hooks[0].id == 1 - assert hooks[0].url == "testurl" - assert hooks[1].id == 2 - assert hooks[1].url == "testurl_second" - - -def test_get_project_hook(project, resp_hook_get): - data = project.hooks.get(1) - assert isinstance(data, ProjectHook) - assert data.url == "testurl" - assert data.id == 1 - - -def test_create_project_hook(project, resp_hook_create): - hook = project.hooks.create(hook_content) - assert hook.url == "testurl" - assert hook.push_events is True - assert hook.tag_push_events is True - - -def test_update_project_hook(project, resp_hook_update): - hook = project.hooks.get(1) - assert hook.id == 1 - hook.url = "testurl_more" - hook.save() - - -def test_delete_project_hook(project, resp_hook_delete): - hook = project.hooks.get(1) - hook.delete() - project.hooks.delete(1) diff --git a/tests/unit/objects/test_issues.py b/tests/unit/objects/test_issues.py deleted file mode 100644 index a4e1454..0000000 --- a/tests/unit/objects/test_issues.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/issues.html -""" -import re - -import pytest -import responses - -from gitlab.v4.objects import ( - GroupIssuesStatistics, - IssuesStatistics, - ProjectIssuesStatistics, -) - - -@pytest.fixture -def resp_list_issues(): - content = [{"name": "name", "id": 1}, {"name": "other_name", "id": 2}] - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/issues", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_issue(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/issues/1", - json={"name": "name", "id": 1}, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_issue_statistics(): - content = {"statistics": {"counts": {"all": 20, "closed": 5, "opened": 15}}} - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile( - r"http://localhost/api/v4/((groups|projects)/1/)?issues_statistics" - ), - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_issues(gl, resp_list_issues): - data = gl.issues.list() - assert data[1].id == 2 - assert data[1].name == "other_name" - - -def test_get_issue(gl, resp_get_issue): - issue = gl.issues.get(1) - assert issue.id == 1 - assert issue.name == "name" - - -def test_get_issues_statistics(gl, resp_issue_statistics): - statistics = gl.issues_statistics.get() - assert isinstance(statistics, IssuesStatistics) - assert statistics.statistics["counts"]["all"] == 20 - - -def test_get_group_issues_statistics(group, resp_issue_statistics): - statistics = group.issues_statistics.get() - assert isinstance(statistics, GroupIssuesStatistics) - assert statistics.statistics["counts"]["all"] == 20 - - -def test_get_project_issues_statistics(project, resp_issue_statistics): - statistics = project.issues_statistics.get() - assert isinstance(statistics, ProjectIssuesStatistics) - assert statistics.statistics["counts"]["all"] == 20 diff --git a/tests/unit/objects/test_job_artifacts.py b/tests/unit/objects/test_job_artifacts.py deleted file mode 100644 index 7c5f1df..0000000 --- a/tests/unit/objects/test_job_artifacts.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/job_artifacts.html -""" - -import pytest -import responses - -ref_name = "master" -job = "build" - - -@pytest.fixture -def resp_artifacts_by_ref_name(binary_content): - url = f"http://localhost/api/v4/projects/1/jobs/artifacts/{ref_name}/download?job={job}" - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=url, - body=binary_content, - content_type="application/octet-stream", - status=200, - ) - yield rsps - - -def test_download_artifacts_by_ref_name(gl, binary_content, resp_artifacts_by_ref_name): - project = gl.projects.get(1, lazy=True) - artifacts = project.artifacts(ref_name=ref_name, job=job) - assert artifacts == binary_content diff --git a/tests/unit/objects/test_jobs.py b/tests/unit/objects/test_jobs.py deleted file mode 100644 index 104d59d..0000000 --- a/tests/unit/objects/test_jobs.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/jobs.html -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectJob - -job_content = { - "commit": { - "author_email": "admin@example.com", - "author_name": "Administrator", - }, - "coverage": None, - "allow_failure": False, - "created_at": "2015-12-24T15:51:21.880Z", - "started_at": "2015-12-24T17:54:30.733Z", - "finished_at": "2015-12-24T17:54:31.198Z", - "duration": 0.465, - "queued_duration": 0.010, - "artifacts_expire_at": "2016-01-23T17:54:31.198Z", - "tag_list": ["docker runner", "macos-10.15"], - "id": 1, - "name": "rubocop", - "pipeline": { - "id": 1, - "project_id": 1, - }, - "ref": "master", - "artifacts": [], - "runner": None, - "stage": "test", - "status": "failed", - "tag": False, - "web_url": "https://example.com/foo/bar/-/jobs/1", - "user": {"id": 1}, -} - - -@pytest.fixture -def resp_get_job(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/jobs/1", - json=job_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_cancel_job(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/jobs/1/cancel", - json=job_content, - content_type="application/json", - status=201, - ) - yield rsps - - -@pytest.fixture -def resp_retry_job(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/jobs/1/retry", - json=job_content, - content_type="application/json", - status=201, - ) - yield rsps - - -def test_get_project_job(project, resp_get_job): - job = project.jobs.get(1) - assert isinstance(job, ProjectJob) - assert job.ref == "master" - - -def test_cancel_project_job(project, resp_cancel_job): - job = project.jobs.get(1, lazy=True) - - output = job.cancel() - assert output["ref"] == "master" - - -def test_retry_project_job(project, resp_retry_job): - job = project.jobs.get(1, lazy=True) - - output = job.retry() - assert output["ref"] == "master" diff --git a/tests/unit/objects/test_keys.py b/tests/unit/objects/test_keys.py deleted file mode 100644 index 187a309..0000000 --- a/tests/unit/objects/test_keys.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/keys.html -""" -import pytest -import responses - -from gitlab.v4.objects import Key - -key_content = {"id": 1, "title": "title", "key": "ssh-keytype AAAAC3Nza/key comment"} - - -@pytest.fixture -def resp_get_key_by_id(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/keys/1", - json=key_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_key_by_fingerprint(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/keys?fingerprint=foo", - json=key_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_get_key_by_id(gl, resp_get_key_by_id): - key = gl.keys.get(1) - assert isinstance(key, Key) - assert key.id == 1 - assert key.title == "title" - - -def test_get_key_by_fingerprint(gl, resp_get_key_by_fingerprint): - key = gl.keys.get(fingerprint="foo") - assert isinstance(key, Key) - assert key.id == 1 - assert key.title == "title" - - -def test_get_key_missing_attrs(gl): - with pytest.raises(AttributeError): - gl.keys.get() diff --git a/tests/unit/objects/test_members.py b/tests/unit/objects/test_members.py deleted file mode 100644 index 6a39369..0000000 --- a/tests/unit/objects/test_members.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/members.html -""" -import pytest -import responses - -from gitlab.v4.objects import GroupBillableMember - -billable_members_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", - "last_activity_on": "2021-01-27", - "membership_type": "group_member", - "removable": True, - } -] - - -@pytest.fixture -def resp_list_billable_group_members(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/groups/1/billable_members", - json=billable_members_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_delete_billable_group_member(no_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.DELETE, - url="http://localhost/api/v4/groups/1/billable_members/1", - json=no_content, - content_type="application/json", - status=204, - ) - yield rsps - - -def test_list_group_billable_members(group, resp_list_billable_group_members): - billable_members = group.billable_members.list() - assert isinstance(billable_members, list) - assert isinstance(billable_members[0], GroupBillableMember) - assert billable_members[0].removable is True - - -def test_delete_group_billable_member(group, resp_delete_billable_group_member): - group.billable_members.delete(1) diff --git a/tests/unit/objects/test_merge_request_pipelines.py b/tests/unit/objects/test_merge_request_pipelines.py deleted file mode 100644 index 04b04a8..0000000 --- a/tests/unit/objects/test_merge_request_pipelines.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/merge_requests.html#list-mr-pipelines -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectMergeRequestPipeline - -pipeline_content = { - "id": 1, - "sha": "959e04d7c7a30600c894bd3c0cd0e1ce7f42c11d", - "ref": "master", - "status": "success", -} - - -@pytest.fixture() -def resp_list_merge_request_pipelines(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/pipelines", - json=[pipeline_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_create_merge_request_pipeline(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/merge_requests/1/pipelines", - json=pipeline_content, - content_type="application/json", - status=201, - ) - yield rsps - - -def test_list_merge_requests_pipelines(project, resp_list_merge_request_pipelines): - pipelines = project.mergerequests.get(1, lazy=True).pipelines.list() - assert len(pipelines) == 1 - assert isinstance(pipelines[0], ProjectMergeRequestPipeline) - assert pipelines[0].sha == pipeline_content["sha"] - - -def test_create_merge_requests_pipelines(project, resp_create_merge_request_pipeline): - pipeline = project.mergerequests.get(1, lazy=True).pipelines.create() - assert isinstance(pipeline, ProjectMergeRequestPipeline) - assert pipeline.sha == pipeline_content["sha"] diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py deleted file mode 100644 index ee11f8a..0000000 --- a/tests/unit/objects/test_merge_requests.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ce/api/merge_requests.html -https://docs.gitlab.com/ee/api/deployments.html#list-of-merge-requests-associated-with-a-deployment -""" -import re - -import pytest -import responses - -from gitlab.v4.objects import ProjectDeploymentMergeRequest, ProjectMergeRequest - -mr_content = { - "id": 1, - "iid": 1, - "project_id": 3, - "title": "test1", - "description": "fixed login page css paddings", - "state": "merged", - "merged_by": { - "id": 87854, - "name": "Douwe Maan", - "username": "DouweM", - "state": "active", - "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", - "web_url": "https://gitlab.com/DouweM", - }, -} - - -@pytest.fixture -def resp_list_merge_requests(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile( - r"http://localhost/api/v4/projects/1/(deployments/1/)?merge_requests" - ), - json=[mr_content], - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_project_merge_requests(project, resp_list_merge_requests): - mrs = project.mergerequests.list() - assert isinstance(mrs[0], ProjectMergeRequest) - assert mrs[0].iid == mr_content["iid"] - - -def test_list_deployment_merge_requests(project, resp_list_merge_requests): - deployment = project.deployments.get(1, lazy=True) - mrs = deployment.mergerequests.list() - assert isinstance(mrs[0], ProjectDeploymentMergeRequest) - assert mrs[0].iid == mr_content["iid"] diff --git a/tests/unit/objects/test_mro.py b/tests/unit/objects/test_mro.py deleted file mode 100644 index 8f67b77..0000000 --- a/tests/unit/objects/test_mro.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Ensure objects defined in gitlab.v4.objects have REST* as last item in class -definition - -Original notes by John L. Villalovos - -An example of an incorrect definition: - class ProjectPipeline(RESTObject, RefreshMixin, ObjectDeleteMixin): - ^^^^^^^^^^ This should be at the end. - -Correct way would be: - class ProjectPipeline(RefreshMixin, ObjectDeleteMixin, RESTObject): - Correctly at the end ^^^^^^^^^^ - - -Why this is an issue: - - When we do type-checking for gitlab/mixins.py we make RESTObject or - RESTManager the base class for the mixins - - Here is how our classes look when type-checking: - - class RESTObject(object): - def __init__(self, manager: "RESTManager", attrs: Dict[str, Any]) -> None: - ... - - class Mixin(RESTObject): - ... - - # Wrong ordering here - class Wrongv4Object(RESTObject, RefreshMixin): - ... - - If we actually ran this in Python we would get the following error: - class Wrongv4Object(RESTObject, Mixin): - TypeError: Cannot create a consistent method resolution - order (MRO) for bases RESTObject, Mixin - - When we are type-checking it fails to understand the class Wrongv4Object - and thus we can't type check it correctly. - -Almost all classes in gitlab/v4/objects/*py were already correct before this -check was added. -""" -import inspect - -import pytest - -import gitlab.v4.objects - - -def test_show_issue(): - """Test case to demonstrate the TypeError that occurs""" - - class RESTObject(object): - def __init__(self, manager: str, attrs: int) -> None: - ... - - class Mixin(RESTObject): - ... - - with pytest.raises(TypeError) as exc_info: - # Wrong ordering here - class Wrongv4Object(RESTObject, Mixin): - ... - - # The error message in the exception should be: - # TypeError: Cannot create a consistent method resolution - # order (MRO) for bases RESTObject, Mixin - - # Make sure the exception string contains "MRO" - assert "MRO" in exc_info.exconly() - - # Correctly ordered class, no exception - class Correctv4Object(Mixin, RESTObject): - ... - - -def test_mros(): - """Ensure objects defined in gitlab.v4.objects have REST* as last item in - class definition. - - We do this as we need to ensure the MRO (Method Resolution Order) is - correct. - """ - - failed_messages = [] - for module_name, module_value in inspect.getmembers(gitlab.v4.objects): - if not inspect.ismodule(module_value): - # We only care about the modules - continue - # Iterate through all the classes in our module - for class_name, class_value in inspect.getmembers(module_value): - if not inspect.isclass(class_value): - continue - - # Ignore imported classes from gitlab.base - if class_value.__module__ == "gitlab.base": - continue - - mro = class_value.mro() - - # We only check classes which have a 'gitlab.base' class in their MRO - has_base = False - for count, obj in enumerate(mro, start=1): - if obj.__module__ == "gitlab.base": - has_base = True - base_classname = obj.__name__ - if has_base: - filename = inspect.getfile(class_value) - # NOTE(jlvillal): The very last item 'mro[-1]' is always going - # to be 'object'. That is why we are checking 'mro[-2]'. - if mro[-2].__module__ != "gitlab.base": - failed_messages.append( - ( - f"class definition for {class_name!r} in file {filename!r} " - f"must have {base_classname!r} as the last class in the " - f"class definition" - ) - ) - failed_msg = "\n".join(failed_messages) - assert not failed_messages, failed_msg diff --git a/tests/unit/objects/test_packages.py b/tests/unit/objects/test_packages.py deleted file mode 100644 index 687054f..0000000 --- a/tests/unit/objects/test_packages.py +++ /dev/null @@ -1,252 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/packages.html -""" -import re -from urllib.parse import quote_plus - -import pytest -import responses - -from gitlab.v4.objects import ( - GenericPackage, - GroupPackage, - ProjectPackage, - ProjectPackageFile, -) - -package_content = { - "id": 1, - "name": "com/mycompany/my-app", - "version": "1.0-SNAPSHOT", - "package_type": "maven", - "_links": { - "web_path": "/namespace1/project1/-/packages/1", - "delete_api_path": "/namespace1/project1/-/packages/1", - }, - "created_at": "2019-11-27T03:37:38.711Z", - "pipeline": { - "id": 123, - "status": "pending", - "ref": "new-pipeline", - "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", - "web_url": "https://example.com/foo/bar/pipelines/47", - "created_at": "2016-08-11T11:28:34.085Z", - "updated_at": "2016-08-11T11:32:35.169Z", - "user": { - "name": "Administrator", - "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - }, - }, - "versions": [ - { - "id": 2, - "version": "2.0-SNAPSHOT", - "created_at": "2020-04-28T04:42:11.573Z", - "pipeline": { - "id": 234, - "status": "pending", - "ref": "new-pipeline", - "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", - "web_url": "https://example.com/foo/bar/pipelines/58", - "created_at": "2016-08-11T11:28:34.085Z", - "updated_at": "2016-08-11T11:32:35.169Z", - "user": { - "name": "Administrator", - "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - }, - }, - } - ], -} - -package_file_content = [ - { - "id": 25, - "package_id": 1, - "created_at": "2018-11-07T15:25:52.199Z", - "file_name": "my-app-1.5-20181107.152550-1.jar", - "size": 2421, - "file_md5": "58e6a45a629910c6ff99145a688971ac", - "file_sha1": "ebd193463d3915d7e22219f52740056dfd26cbfe", - "pipelines": [ - { - "id": 123, - "status": "pending", - "ref": "new-pipeline", - "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", - "web_url": "https://example.com/foo/bar/pipelines/47", - "created_at": "2016-08-11T11:28:34.085Z", - "updated_at": "2016-08-11T11:32:35.169Z", - "user": { - "name": "Administrator", - "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - }, - } - ], - }, - { - "id": 26, - "package_id": 1, - "created_at": "2018-11-07T15:25:56.776Z", - "file_name": "my-app-1.5-20181107.152550-1.pom", - "size": 1122, - "file_md5": "d90f11d851e17c5513586b4a7e98f1b2", - "file_sha1": "9608d068fe88aff85781811a42f32d97feb440b5", - }, - { - "id": 27, - "package_id": 1, - "created_at": "2018-11-07T15:26:00.556Z", - "file_name": "maven-metadata.xml", - "size": 767, - "file_md5": "6dfd0cce1203145a927fef5e3a1c650c", - "file_sha1": "d25932de56052d320a8ac156f745ece73f6a8cd2", - }, -] - -package_name = "hello-world" -package_version = "v1.0.0" -file_name = "hello.tar.gz" -file_content = "package content" -package_url = "http://localhost/api/v4/projects/1/packages/generic/{}/{}/{}".format( - # https://datatracker.ietf.org/doc/html/rfc3986.html#section-2.3 :( - quote_plus(package_name).replace(".", "%2E"), - quote_plus(package_version).replace(".", "%2E"), - quote_plus(file_name).replace(".", "%2E"), -) - - -@pytest.fixture -def resp_list_packages(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile(r"http://localhost/api/v4/(groups|projects)/1/packages"), - json=[package_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_package(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/packages/1", - json=package_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_delete_package(no_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.DELETE, - url="http://localhost/api/v4/projects/1/packages/1", - json=no_content, - content_type="application/json", - status=204, - ) - yield rsps - - -@pytest.fixture -def resp_list_package_files(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile( - r"http://localhost/api/v4/projects/1/packages/1/package_files" - ), - json=package_file_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_upload_generic_package(created_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.PUT, - url=package_url, - json=created_content, - content_type="application/json", - status=201, - ) - yield rsps - - -@pytest.fixture -def resp_download_generic_package(created_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=package_url, - body=file_content, - content_type="application/octet-stream", - status=200, - ) - yield rsps - - -def test_list_project_packages(project, resp_list_packages): - packages = project.packages.list() - assert isinstance(packages, list) - assert isinstance(packages[0], ProjectPackage) - assert packages[0].version == "1.0-SNAPSHOT" - - -def test_list_group_packages(group, resp_list_packages): - packages = group.packages.list() - assert isinstance(packages, list) - assert isinstance(packages[0], GroupPackage) - assert packages[0].version == "1.0-SNAPSHOT" - - -def test_get_project_package(project, resp_get_package): - package = project.packages.get(1) - assert isinstance(package, ProjectPackage) - assert package.version == "1.0-SNAPSHOT" - - -def test_delete_project_package(project, resp_delete_package): - package = project.packages.get(1, lazy=True) - package.delete() - - -def test_list_project_package_files(project, resp_list_package_files): - package = project.packages.get(1, lazy=True) - package_files = package.package_files.list() - assert isinstance(package_files, list) - assert isinstance(package_files[0], ProjectPackageFile) - assert package_files[0].id == 25 - - -def test_upload_generic_package(tmp_path, project, resp_upload_generic_package): - path = tmp_path / file_name - path.write_text(file_content) - package = project.generic_packages.upload( - package_name=package_name, - package_version=package_version, - file_name=file_name, - path=path, - ) - - assert isinstance(package, GenericPackage) - - -def test_download_generic_package(project, resp_download_generic_package): - package = project.generic_packages.download( - package_name=package_name, - package_version=package_version, - file_name=file_name, - ) - - assert isinstance(package, bytes) diff --git a/tests/unit/objects/test_personal_access_tokens.py b/tests/unit/objects/test_personal_access_tokens.py deleted file mode 100644 index 065b5c8..0000000 --- a/tests/unit/objects/test_personal_access_tokens.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/personal_access_tokens.html -https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token -""" - -import pytest -import responses - -user_id = 1 -token_id = 1 -token_name = "Test Token" - -token_url = "http://localhost/api/v4/personal_access_tokens" -single_token_url = f"{token_url}/{token_id}" -user_token_url = f"http://localhost/api/v4/users/{user_id}/personal_access_tokens" - -content = { - "id": token_id, - "name": token_name, - "revoked": False, - "created_at": "2020-07-23T14:31:47.729Z", - "scopes": ["api"], - "active": True, - "user_id": user_id, - "expires_at": None, -} - - -@pytest.fixture -def resp_create_user_personal_access_token(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url=user_token_url, - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_personal_access_token(no_content): - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url=token_url, - json=[content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.DELETE, - url=single_token_url, - json=no_content, - content_type="application/json", - status=204, - ) - yield rsps - - -def test_create_personal_access_token(gl, resp_create_user_personal_access_token): - user = gl.users.get(1, lazy=True) - access_token = user.personal_access_tokens.create( - {"name": token_name, "scopes": "api"} - ) - assert access_token.revoked is False - assert access_token.name == token_name - - -def test_list_personal_access_tokens(gl, resp_personal_access_token): - access_tokens = gl.personal_access_tokens.list() - assert len(access_tokens) == 1 - assert access_tokens[0].revoked is False - assert access_tokens[0].name == token_name - - -def test_list_personal_access_tokens_filter(gl, resp_personal_access_token): - access_tokens = gl.personal_access_tokens.list(user_id=user_id) - assert len(access_tokens) == 1 - assert access_tokens[0].revoked is False - assert access_tokens[0].user_id == user_id - - -def test_revoke_personal_access_token(gl, resp_personal_access_token): - access_token = gl.personal_access_tokens.list(user_id=user_id)[0] - access_token.delete() - assert resp_personal_access_token.assert_call_count(single_token_url, 1) - - -def test_revoke_personal_access_token_by_id(gl, resp_personal_access_token): - gl.personal_access_tokens.delete(token_id) - assert resp_personal_access_token.assert_call_count(single_token_url, 1) diff --git a/tests/unit/objects/test_pipeline_schedules.py b/tests/unit/objects/test_pipeline_schedules.py deleted file mode 100644 index c5dcc76..0000000 --- a/tests/unit/objects/test_pipeline_schedules.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/pipeline_schedules.html -""" -import pytest -import responses - - -@pytest.fixture -def resp_project_pipeline_schedule(created_content): - content = { - "id": 14, - "description": "Build packages", - "ref": "master", - "cron": "0 1 * * 5", - "cron_timezone": "UTC", - "next_run_at": "2017-05-26T01:00:00.000Z", - "active": True, - "created_at": "2017-05-19T13:43:08.169Z", - "updated_at": "2017-05-19T13:43:08.169Z", - "last_pipeline": None, - "owner": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - "web_url": "https://gitlab.example.com/root", - }, - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/pipeline_schedules", - json=content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/pipeline_schedules/14/play", - json=created_content, - content_type="application/json", - status=201, - ) - yield rsps - - -def test_project_pipeline_schedule_play(project, resp_project_pipeline_schedule): - description = "Build packages" - cronline = "0 1 * * 5" - sched = project.pipelineschedules.create( - {"ref": "master", "description": description, "cron": cronline} - ) - assert sched is not None - assert description == sched.description - assert cronline == sched.cron - - play_result = sched.play() - assert play_result is not None - assert "message" in play_result - assert play_result["message"] == "201 Created" diff --git a/tests/unit/objects/test_pipelines.py b/tests/unit/objects/test_pipelines.py deleted file mode 100644 index c0b87f2..0000000 --- a/tests/unit/objects/test_pipelines.py +++ /dev/null @@ -1,146 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/pipelines.html -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectPipeline, ProjectPipelineTestReport - -pipeline_content = { - "id": 46, - "project_id": 1, - "status": "pending", - "ref": "master", - "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", - "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", - "tag": False, - "yaml_errors": None, - "user": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - "web_url": "http://localhost:3000/root", - }, - "created_at": "2016-08-11T11:28:34.085Z", - "updated_at": "2016-08-11T11:32:35.169Z", - "started_at": None, - "finished_at": "2016-08-11T11:32:35.145Z", - "committed_at": None, - "duration": None, - "queued_duration": 0.010, - "coverage": None, - "web_url": "https://example.com/foo/bar/pipelines/46", -} - - -test_report_content = { - "total_time": 5, - "total_count": 1, - "success_count": 1, - "failed_count": 0, - "skipped_count": 0, - "error_count": 0, - "test_suites": [ - { - "name": "Secure", - "total_time": 5, - "total_count": 1, - "success_count": 1, - "failed_count": 0, - "skipped_count": 0, - "error_count": 0, - "test_cases": [ - { - "status": "success", - "name": "Security Reports can create an auto-remediation MR", - "classname": "vulnerability_management_spec", - "execution_time": 5, - "system_output": None, - "stack_trace": None, - } - ], - } - ], -} - - -@pytest.fixture -def resp_get_pipeline(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/pipelines/1", - json=pipeline_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_cancel_pipeline(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/pipelines/1/cancel", - json=pipeline_content, - content_type="application/json", - status=201, - ) - yield rsps - - -@pytest.fixture -def resp_retry_pipeline(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/pipelines/1/retry", - json=pipeline_content, - content_type="application/json", - status=201, - ) - yield rsps - - -@pytest.fixture -def resp_get_pipeline_test_report(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/pipelines/1/test_report", - json=test_report_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_get_project_pipeline(project, resp_get_pipeline): - pipeline = project.pipelines.get(1) - assert isinstance(pipeline, ProjectPipeline) - assert pipeline.ref == "master" - - -def test_cancel_project_pipeline(project, resp_cancel_pipeline): - pipeline = project.pipelines.get(1, lazy=True) - - output = pipeline.cancel() - assert output["ref"] == "master" - - -def test_retry_project_pipeline(project, resp_retry_pipeline): - pipeline = project.pipelines.get(1, lazy=True) - - output = pipeline.retry() - assert output["ref"] == "master" - - -def test_get_project_pipeline_test_report(project, resp_get_pipeline_test_report): - pipeline = project.pipelines.get(1, lazy=True) - test_report = pipeline.test_report.get() - assert isinstance(test_report, ProjectPipelineTestReport) - assert test_report.total_time == 5 - assert test_report.test_suites[0]["name"] == "Secure" diff --git a/tests/unit/objects/test_project_access_tokens.py b/tests/unit/objects/test_project_access_tokens.py deleted file mode 100644 index 4d4788d..0000000 --- a/tests/unit/objects/test_project_access_tokens.py +++ /dev/null @@ -1,113 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/resource_access_tokens.html -""" - -import pytest -import responses - - -@pytest.fixture -def resp_list_project_access_token(): - content = [ - { - "user_id": 141, - "scopes": ["api"], - "name": "token", - "expires_at": "2021-01-31", - "id": 42, - "active": True, - "created_at": "2021-01-20T22:11:48.151Z", - "revoked": False, - } - ] - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/access_tokens", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_create_project_access_token(): - content = { - "user_id": 141, - "scopes": ["api"], - "name": "token", - "expires_at": "2021-01-31", - "id": 42, - "active": True, - "created_at": "2021-01-20T22:11:48.151Z", - "revoked": False, - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/access_tokens", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_revoke_project_access_token(): - content = [ - { - "user_id": 141, - "scopes": ["api"], - "name": "token", - "expires_at": "2021-01-31", - "id": 42, - "active": True, - "created_at": "2021-01-20T22:11:48.151Z", - "revoked": False, - } - ] - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.DELETE, - url="http://localhost/api/v4/projects/1/access_tokens/42", - json=content, - content_type="application/json", - status=204, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/access_tokens", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_project_access_tokens(gl, resp_list_project_access_token): - access_tokens = gl.projects.get(1, lazy=True).access_tokens.list() - assert len(access_tokens) == 1 - assert access_tokens[0].revoked is False - assert access_tokens[0].name == "token" - - -def test_create_project_access_token(gl, resp_create_project_access_token): - access_tokens = gl.projects.get(1, lazy=True).access_tokens.create( - {"name": "test", "scopes": ["api"]} - ) - assert access_tokens.revoked is False - assert access_tokens.user_id == 141 - assert access_tokens.expires_at == "2021-01-31" - - -def test_revoke_project_access_token( - gl, resp_list_project_access_token, resp_revoke_project_access_token -): - gl.projects.get(1, lazy=True).access_tokens.delete(42) - access_token = gl.projects.get(1, lazy=True).access_tokens.list()[0] - access_token.delete() diff --git a/tests/unit/objects/test_project_import_export.py b/tests/unit/objects/test_project_import_export.py deleted file mode 100644 index 78e51b1..0000000 --- a/tests/unit/objects/test_project_import_export.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/project_import_export.html -""" -import pytest -import responses - - -@pytest.fixture -def resp_import_project(): - content = { - "id": 1, - "description": None, - "name": "api-project", - "name_with_namespace": "Administrator / api-project", - "path": "api-project", - "path_with_namespace": "root/api-project", - "created_at": "2018-02-13T09:05:58.023Z", - "import_status": "scheduled", - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/import", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_import_status(): - content = { - "id": 1, - "description": "Itaque perspiciatis minima aspernatur corporis consequatur.", - "name": "Gitlab Test", - "name_with_namespace": "Gitlab Org / Gitlab Test", - "path": "gitlab-test", - "path_with_namespace": "gitlab-org/gitlab-test", - "created_at": "2017-08-29T04:36:44.383Z", - "import_status": "finished", - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/import", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_import_github(): - content = { - "id": 27, - "name": "my-repo", - "full_path": "/root/my-repo", - "full_name": "Administrator / my-repo", - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/import/github", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_import_project(gl, resp_import_project): - project_import = gl.projects.import_project("file", "api-project") - assert project_import["import_status"] == "scheduled" - - -def test_refresh_project_import_status(project, resp_import_status): - project_import = project.imports.get() - project_import.refresh() - assert project_import.import_status == "finished" - - -def test_import_github(gl, resp_import_github): - base_path = "/root" - name = "my-repo" - ret = gl.projects.import_github("githubkey", 1234, base_path, name) - assert isinstance(ret, dict) - assert ret["name"] == name - assert ret["full_path"] == "/".join((base_path, name)) - assert ret["full_name"].endswith(name) - - -def test_create_project_export(project, resp_export): - export = project.exports.create() - assert export.message == "202 Accepted" - - -def test_refresh_project_export_status(project, resp_export): - export = project.exports.create() - export.refresh() - assert export.export_status == "finished" - - -def test_download_project_export(project, resp_export, binary_content): - export = project.exports.create() - download = export.download() - assert isinstance(download, bytes) - assert download == binary_content diff --git a/tests/unit/objects/test_project_merge_request_approvals.py b/tests/unit/objects/test_project_merge_request_approvals.py deleted file mode 100644 index 16d58bd..0000000 --- a/tests/unit/objects/test_project_merge_request_approvals.py +++ /dev/null @@ -1,317 +0,0 @@ -""" -Gitlab API: https://docs.gitlab.com/ee/api/merge_request_approvals.html -""" - -import copy - -import pytest -import responses - -import gitlab - -approval_rule_id = 1 -approval_rule_name = "security" -approvals_required = 3 -user_ids = [5, 50] -group_ids = [5] - -new_approval_rule_name = "new approval rule" -new_approval_rule_user_ids = user_ids -new_approval_rule_approvals_required = 2 - -updated_approval_rule_user_ids = [5] -updated_approval_rule_approvals_required = 1 - - -@pytest.fixture -def resp_snippet(): - merge_request_content = [ - { - "id": 1, - "iid": 1, - "project_id": 1, - "title": "test1", - "description": "fixed login page css paddings", - "state": "merged", - "merged_by": { - "id": 87854, - "name": "Douwe Maan", - "username": "DouweM", - "state": "active", - "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", - "web_url": "https://gitlab.com/DouweM", - }, - "merged_at": "2018-09-07T11:16:17.520Z", - "closed_by": None, - "closed_at": None, - "created_at": "2017-04-29T08:46:00Z", - "updated_at": "2017-04-29T08:46:00Z", - "target_branch": "master", - "source_branch": "test1", - "upvotes": 0, - "downvotes": 0, - "author": { - "id": 1, - "name": "Administrator", - "username": "admin", - "state": "active", - "avatar_url": None, - "web_url": "https://gitlab.example.com/admin", - }, - "assignee": { - "id": 1, - "name": "Administrator", - "username": "admin", - "state": "active", - "avatar_url": None, - "web_url": "https://gitlab.example.com/admin", - }, - "assignees": [ - { - "name": "Miss Monserrate Beier", - "username": "axel.block", - "id": 12, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon", - "web_url": "https://gitlab.example.com/axel.block", - } - ], - "source_project_id": 2, - "target_project_id": 3, - "labels": ["Community contribution", "Manage"], - "work_in_progress": None, - "milestone": { - "id": 5, - "iid": 1, - "project_id": 3, - "title": "v2.0", - "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.", - "state": "closed", - "created_at": "2015-02-02T19:49:26.013Z", - "updated_at": "2015-02-02T19:49:26.013Z", - "due_date": "2018-09-22", - "start_date": "2018-08-08", - "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1", - }, - "merge_when_pipeline_succeeds": None, - "merge_status": "can_be_merged", - "sha": "8888888888888888888888888888888888888888", - "merge_commit_sha": None, - "squash_commit_sha": None, - "user_notes_count": 1, - "discussion_locked": None, - "should_remove_source_branch": True, - "force_remove_source_branch": False, - "allow_collaboration": False, - "allow_maintainer_to_push": False, - "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1", - "references": { - "short": "!1", - "relative": "my-group/my-project!1", - "full": "my-group/my-project!1", - }, - "time_stats": { - "time_estimate": 0, - "total_time_spent": 0, - "human_time_estimate": None, - "human_total_time_spent": None, - }, - "squash": False, - "task_completion_status": {"count": 0, "completed_count": 0}, - } - ] - mr_ars_content = [ - { - "id": approval_rule_id, - "name": approval_rule_name, - "rule_type": "regular", - "eligible_approvers": [ - { - "id": user_ids[0], - "name": "John Doe", - "username": "jdoe", - "state": "active", - "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", - "web_url": "http://localhost/jdoe", - }, - { - "id": user_ids[1], - "name": "Group Member 1", - "username": "group_member_1", - "state": "active", - "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", - "web_url": "http://localhost/group_member_1", - }, - ], - "approvals_required": approvals_required, - "source_rule": None, - "users": [ - { - "id": 5, - "name": "John Doe", - "username": "jdoe", - "state": "active", - "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", - "web_url": "http://localhost/jdoe", - } - ], - "groups": [ - { - "id": 5, - "name": "group1", - "path": "group1", - "description": "", - "visibility": "public", - "lfs_enabled": False, - "avatar_url": None, - "web_url": "http://localhost/groups/group1", - "request_access_enabled": False, - "full_name": "group1", - "full_path": "group1", - "parent_id": None, - "ldap_cn": None, - "ldap_access": None, - } - ], - "contains_hidden_groups": False, - "overridden": False, - } - ] - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests", - json=merge_request_content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1", - json=merge_request_content[0], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/approval_rules", - json=mr_ars_content, - content_type="application/json", - status=200, - ) - - new_mr_ars_content = dict(mr_ars_content[0]) - new_mr_ars_content["name"] = new_approval_rule_name - new_mr_ars_content["approvals_required"] = new_approval_rule_approvals_required - - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/merge_requests/1/approval_rules", - json=new_mr_ars_content, - content_type="application/json", - status=200, - ) - - updated_mr_ars_content = copy.deepcopy(mr_ars_content[0]) - updated_mr_ars_content["eligible_approvers"] = [ - mr_ars_content[0]["eligible_approvers"][0] - ] - - updated_mr_ars_content[ - "approvals_required" - ] = updated_approval_rule_approvals_required - - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/projects/1/merge_requests/1/approval_rules/1", - json=updated_mr_ars_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_project_approval_manager_update_uses_post(project, resp_snippet): - """Ensure the - gitlab.v4.objects.merge_request_approvals.ProjectApprovalManager object has - _update_uses_post set to True""" - approvals = project.approvals - assert isinstance( - approvals, gitlab.v4.objects.merge_request_approvals.ProjectApprovalManager - ) - assert approvals._update_uses_post is True - - -def test_list_merge_request_approval_rules(project, resp_snippet): - approval_rules = project.mergerequests.get(1).approval_rules.list() - assert len(approval_rules) == 1 - assert approval_rules[0].name == approval_rule_name - assert approval_rules[0].id == approval_rule_id - - -def test_update_merge_request_approvals_set_approvers(project, resp_snippet): - approvals = project.mergerequests.get(1).approvals - assert isinstance( - approvals, - gitlab.v4.objects.merge_request_approvals.ProjectMergeRequestApprovalManager, - ) - assert approvals._update_uses_post is True - response = approvals.set_approvers( - updated_approval_rule_approvals_required, - approver_ids=updated_approval_rule_user_ids, - approver_group_ids=group_ids, - approval_rule_name=approval_rule_name, - ) - - assert response.approvals_required == updated_approval_rule_approvals_required - assert len(response.eligible_approvers) == len(updated_approval_rule_user_ids) - assert response.eligible_approvers[0]["id"] == updated_approval_rule_user_ids[0] - assert response.name == approval_rule_name - - -def test_create_merge_request_approvals_set_approvers(project, resp_snippet): - approvals = project.mergerequests.get(1).approvals - assert isinstance( - approvals, - gitlab.v4.objects.merge_request_approvals.ProjectMergeRequestApprovalManager, - ) - assert approvals._update_uses_post is True - response = approvals.set_approvers( - new_approval_rule_approvals_required, - approver_ids=new_approval_rule_user_ids, - approver_group_ids=group_ids, - approval_rule_name=new_approval_rule_name, - ) - assert response.approvals_required == new_approval_rule_approvals_required - assert len(response.eligible_approvers) == len(new_approval_rule_user_ids) - assert response.eligible_approvers[0]["id"] == new_approval_rule_user_ids[0] - assert response.name == new_approval_rule_name - - -def test_create_merge_request_approval_rule(project, resp_snippet): - approval_rules = project.mergerequests.get(1).approval_rules - data = { - "name": new_approval_rule_name, - "approvals_required": new_approval_rule_approvals_required, - "rule_type": "regular", - "user_ids": new_approval_rule_user_ids, - "group_ids": group_ids, - } - response = approval_rules.create(data) - assert response.approvals_required == new_approval_rule_approvals_required - assert len(response.eligible_approvers) == len(new_approval_rule_user_ids) - assert response.eligible_approvers[0]["id"] == new_approval_rule_user_ids[0] - assert response.name == new_approval_rule_name - - -def test_update_merge_request_approval_rule(project, resp_snippet): - approval_rules = project.mergerequests.get(1).approval_rules - ar_1 = approval_rules.list()[0] - ar_1.user_ids = updated_approval_rule_user_ids - ar_1.approvals_required = updated_approval_rule_approvals_required - ar_1.save() - - assert ar_1.approvals_required == updated_approval_rule_approvals_required - assert len(ar_1.eligible_approvers) == len(updated_approval_rule_user_ids) - assert ar_1.eligible_approvers[0]["id"] == updated_approval_rule_user_ids[0] diff --git a/tests/unit/objects/test_project_statistics.py b/tests/unit/objects/test_project_statistics.py deleted file mode 100644 index 50d9a6d..0000000 --- a/tests/unit/objects/test_project_statistics.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/project_statistics.html -""" -import pytest -import responses - -from gitlab.v4.objects import ProjectAdditionalStatistics - - -@pytest.fixture -def resp_project_statistics(): - content = {"fetches": {"total": 50, "days": [{"count": 10, "date": "2018-01-10"}]}} - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/statistics", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_project_additional_statistics(project, resp_project_statistics): - statistics = project.additionalstatistics.get() - assert isinstance(statistics, ProjectAdditionalStatistics) - assert statistics.fetches["total"] == 50 diff --git a/tests/unit/objects/test_projects.py b/tests/unit/objects/test_projects.py deleted file mode 100644 index 039d5ec..0000000 --- a/tests/unit/objects/test_projects.py +++ /dev/null @@ -1,237 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/projects.html -""" - -import pytest -import responses - -from gitlab.v4.objects import Project - -project_content = {"name": "name", "id": 1} -import_content = { - "id": 1, - "name": "project", - "import_status": "scheduled", -} - - -@pytest.fixture -def resp_get_project(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1", - json=project_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_list_projects(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects", - json=[project_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_import_bitbucket_server(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/import/bitbucket_server", - json=import_content, - content_type="application/json", - status=201, - ) - yield rsps - - -def test_get_project(gl, resp_get_project): - data = gl.projects.get(1) - assert isinstance(data, Project) - assert data.name == "name" - assert data.id == 1 - - -def test_list_projects(gl, resp_list_projects): - projects = gl.projects.list() - assert isinstance(projects[0], Project) - assert projects[0].name == "name" - - -def test_import_bitbucket_server(gl, resp_import_bitbucket_server): - res = gl.projects.import_bitbucket_server( - bitbucket_server_project="project", - bitbucket_server_repo="repo", - bitbucket_server_url="url", - bitbucket_server_username="username", - personal_access_token="token", - new_name="new_name", - target_namespace="namespace", - ) - assert res["id"] == 1 - assert res["name"] == "project" - assert res["import_status"] == "scheduled" - - -@pytest.mark.skip(reason="missing test") -def test_list_user_projects(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_list_user_starred_projects(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_list_project_users(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_create_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_create_user_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_update_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_fork_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_list_project_forks(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_star_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_unstar_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_list_project_starrers(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_get_project_languages(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_archive_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_unarchive_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_remove_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_restore_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_upload_file(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_share_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_delete_shared_project_link(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_create_forked_from_relationship(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_delete_forked_from_relationship(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_search_projects_by_name(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_project_housekeeping(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_get_project_push_rules(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_create_project_push_rule(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_update_project_push_rule(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_delete_project_push_rule(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_transfer_project(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_project_pull_mirror(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_project_snapshot(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_import_github(gl): - pass diff --git a/tests/unit/objects/test_releases.py b/tests/unit/objects/test_releases.py deleted file mode 100644 index 58ab5d0..0000000 --- a/tests/unit/objects/test_releases.py +++ /dev/null @@ -1,170 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/releases/index.html -https://docs.gitlab.com/ee/api/releases/links.html -""" -import re - -import pytest -import responses - -from gitlab.v4.objects import ProjectReleaseLink - -tag_name = "v1.0.0" -encoded_tag_name = "v1%2E0%2E0" -release_name = "demo-release" -release_description = "my-rel-desc" -released_at = "2019-03-15T08:00:00Z" -link_name = "hello-world" -link_url = "https://gitlab.example.com/group/hello/-/jobs/688/artifacts/raw/bin/hello-darwin-amd64" -direct_url = f"https://gitlab.example.com/group/hello/-/releases/{encoded_tag_name}/downloads/hello-world" -new_link_type = "package" -link_content = { - "id": 2, - "name": link_name, - "url": link_url, - "direct_asset_url": direct_url, - "external": False, - "link_type": "other", -} - -release_content = { - "id": 3, - "tag_name": tag_name, - "name": release_name, - "description": release_description, - "milestones": [], - "released_at": released_at, -} - -release_url = re.compile( - rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}" -) -links_url = re.compile( - rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}/assets/links" -) -link_id_url = re.compile( - rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}/assets/links/1" -) - - -@pytest.fixture -def resp_list_links(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=links_url, - json=[link_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_link(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=link_id_url, - json=link_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_create_link(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url=links_url, - json=link_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_update_link(): - updated_content = dict(link_content) - updated_content["link_type"] = new_link_type - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.PUT, - url=link_id_url, - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_delete_link(no_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.DELETE, - url=link_id_url, - json=link_content, - content_type="application/json", - status=204, - ) - yield rsps - - -@pytest.fixture -def resp_update_release(): - updated_content = dict(release_content) - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.PUT, - url=release_url, - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_release_links(release, resp_list_links): - links = release.links.list() - assert isinstance(links, list) - assert isinstance(links[0], ProjectReleaseLink) - assert links[0].url == link_url - - -def test_get_release_link(release, resp_get_link): - link = release.links.get(1) - assert isinstance(link, ProjectReleaseLink) - assert link.url == link_url - - -def test_create_release_link(release, resp_create_link): - link = release.links.create({"url": link_url, "name": link_name}) - assert isinstance(link, ProjectReleaseLink) - assert link.url == link_url - - -def test_update_release_link(release, resp_update_link): - link = release.links.get(1, lazy=True) - link.link_type = new_link_type - link.save() - assert link.link_type == new_link_type - - -def test_delete_release_link(release, resp_delete_link): - link = release.links.get(1, lazy=True) - link.delete() - - -def test_update_release(release, resp_update_release): - release.name = release_name - release.description = release_description - release.save() - assert release.name == release_name - assert release.description == release_description diff --git a/tests/unit/objects/test_remote_mirrors.py b/tests/unit/objects/test_remote_mirrors.py deleted file mode 100644 index 1ac35a2..0000000 --- a/tests/unit/objects/test_remote_mirrors.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/remote_mirrors.html -""" - -import pytest -import responses - -from gitlab.v4.objects import ProjectRemoteMirror - - -@pytest.fixture -def resp_remote_mirrors(): - content = { - "enabled": True, - "id": 1, - "last_error": None, - "last_successful_update_at": "2020-01-06T17:32:02.823Z", - "last_update_at": "2020-01-06T17:32:02.823Z", - "last_update_started_at": "2020-01-06T17:31:55.864Z", - "only_protected_branches": True, - "update_status": "none", - "url": "https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git", - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/remote_mirrors", - json=[content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/remote_mirrors", - json=content, - content_type="application/json", - status=200, - ) - - updated_content = dict(content) - updated_content["update_status"] = "finished" - - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/projects/1/remote_mirrors/1", - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_project_remote_mirrors(project, resp_remote_mirrors): - mirrors = project.remote_mirrors.list() - assert isinstance(mirrors, list) - assert isinstance(mirrors[0], ProjectRemoteMirror) - assert mirrors[0].enabled - - -def test_create_project_remote_mirror(project, resp_remote_mirrors): - mirror = project.remote_mirrors.create({"url": "https://example.com"}) - assert isinstance(mirror, ProjectRemoteMirror) - assert mirror.update_status == "none" - - -def test_update_project_remote_mirror(project, resp_remote_mirrors): - mirror = project.remote_mirrors.create({"url": "https://example.com"}) - mirror.only_protected_branches = True - mirror.save() - assert mirror.update_status == "finished" - assert mirror.only_protected_branches diff --git a/tests/unit/objects/test_repositories.py b/tests/unit/objects/test_repositories.py deleted file mode 100644 index 7c4d77d..0000000 --- a/tests/unit/objects/test_repositories.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/repositories.html -https://docs.gitlab.com/ee/api/repository_files.html -""" -from urllib.parse import quote - -import pytest -import responses - -from gitlab.v4.objects import ProjectFile - -file_path = "app/models/key.rb" -ref = "main" - - -@pytest.fixture -def resp_get_repository_file(): - file_response = { - "file_name": "key.rb", - "file_path": file_path, - "size": 1476, - "encoding": "base64", - "content": "IyA9PSBTY2hlbWEgSW5mb3...", - "content_sha256": "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481", - "ref": ref, - "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", - "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50", - "last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", - } - - # requests also encodes `.` - encoded_path = quote(file_path, safe="").replace(".", "%2E") - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=f"http://localhost/api/v4/projects/1/repository/files/{encoded_path}", - json=file_response, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_get_repository_file(project, resp_get_repository_file): - file = project.files.get(file_path, ref=ref) - assert isinstance(file, ProjectFile) - assert file.file_path == file_path diff --git a/tests/unit/objects/test_resource_label_events.py b/tests/unit/objects/test_resource_label_events.py deleted file mode 100644 index deea8a0..0000000 --- a/tests/unit/objects/test_resource_label_events.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/resource_label_events.html -""" - -import pytest -import responses - -from gitlab.v4.objects import ( - GroupEpicResourceLabelEvent, - ProjectIssueResourceLabelEvent, - ProjectMergeRequestResourceLabelEvent, -) - - -@pytest.fixture() -def resp_group_epic_request_label_events(): - epic_content = {"id": 1} - events_content = {"id": 1, "resource_type": "Epic"} - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/groups/1/epics", - json=[epic_content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/groups/1/epics/1/resource_label_events", - json=[events_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_merge_request_label_events(): - mr_content = {"iid": 1} - events_content = {"id": 1, "resource_type": "MergeRequest"} - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests", - json=[mr_content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/resource_label_events", - json=[events_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_project_issue_label_events(): - issue_content = {"iid": 1} - events_content = {"id": 1, "resource_type": "Issue"} - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/issues", - json=[issue_content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/issues/1/resource_label_events", - json=[events_content], - content_type="application/json", - status=200, - ) - yield rsps - - -def test_project_issue_label_events(project, resp_project_issue_label_events): - issue = project.issues.list()[0] - label_events = issue.resourcelabelevents.list() - assert isinstance(label_events, list) - label_event = label_events[0] - assert isinstance(label_event, ProjectIssueResourceLabelEvent) - assert label_event.resource_type == "Issue" - - -def test_merge_request_label_events(project, resp_merge_request_label_events): - mr = project.mergerequests.list()[0] - label_events = mr.resourcelabelevents.list() - assert isinstance(label_events, list) - label_event = label_events[0] - assert isinstance(label_event, ProjectMergeRequestResourceLabelEvent) - assert label_event.resource_type == "MergeRequest" - - -def test_group_epic_request_label_events(group, resp_group_epic_request_label_events): - epic = group.epics.list()[0] - label_events = epic.resourcelabelevents.list() - assert isinstance(label_events, list) - label_event = label_events[0] - assert isinstance(label_event, GroupEpicResourceLabelEvent) - assert label_event.resource_type == "Epic" diff --git a/tests/unit/objects/test_resource_milestone_events.py b/tests/unit/objects/test_resource_milestone_events.py deleted file mode 100644 index 99faeaa..0000000 --- a/tests/unit/objects/test_resource_milestone_events.py +++ /dev/null @@ -1,73 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/resource_milestone_events.html -""" - -import pytest -import responses - -from gitlab.v4.objects import ( - ProjectIssueResourceMilestoneEvent, - ProjectMergeRequestResourceMilestoneEvent, -) - - -@pytest.fixture() -def resp_merge_request_milestone_events(): - mr_content = {"iid": 1} - events_content = {"id": 1, "resource_type": "MergeRequest"} - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests", - json=[mr_content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/resource_milestone_events", - json=[events_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_project_issue_milestone_events(): - issue_content = {"iid": 1} - events_content = {"id": 1, "resource_type": "Issue"} - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/issues", - json=[issue_content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/issues/1/resource_milestone_events", - json=[events_content], - content_type="application/json", - status=200, - ) - yield rsps - - -def test_project_issue_milestone_events(project, resp_project_issue_milestone_events): - issue = project.issues.list()[0] - milestone_events = issue.resourcemilestoneevents.list() - assert isinstance(milestone_events, list) - milestone_event = milestone_events[0] - assert isinstance(milestone_event, ProjectIssueResourceMilestoneEvent) - assert milestone_event.resource_type == "Issue" - - -def test_merge_request_milestone_events(project, resp_merge_request_milestone_events): - mr = project.mergerequests.list()[0] - milestone_events = mr.resourcemilestoneevents.list() - assert isinstance(milestone_events, list) - milestone_event = milestone_events[0] - assert isinstance(milestone_event, ProjectMergeRequestResourceMilestoneEvent) - assert milestone_event.resource_type == "MergeRequest" diff --git a/tests/unit/objects/test_resource_state_events.py b/tests/unit/objects/test_resource_state_events.py deleted file mode 100644 index bf18193..0000000 --- a/tests/unit/objects/test_resource_state_events.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/resource_state_events.html -""" - -import pytest -import responses - -from gitlab.v4.objects import ( - ProjectIssueResourceStateEvent, - ProjectMergeRequestResourceStateEvent, -) - -issue_event_content = {"id": 1, "resource_type": "Issue"} -mr_event_content = {"id": 1, "resource_type": "MergeRequest"} - - -@pytest.fixture() -def resp_list_project_issue_state_events(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/issues/1/resource_state_events", - json=[issue_event_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_get_project_issue_state_event(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/issues/1/resource_state_events/1", - json=issue_event_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_list_merge_request_state_events(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/resource_state_events", - json=[mr_event_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture() -def resp_get_merge_request_state_event(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/resource_state_events/1", - json=mr_event_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_project_issue_state_events( - project_issue, resp_list_project_issue_state_events -): - state_events = project_issue.resourcestateevents.list() - assert isinstance(state_events, list) - - state_event = state_events[0] - assert isinstance(state_event, ProjectIssueResourceStateEvent) - assert state_event.resource_type == "Issue" - - -def test_get_project_issue_state_event( - project_issue, resp_get_project_issue_state_event -): - state_event = project_issue.resourcestateevents.get(1) - assert isinstance(state_event, ProjectIssueResourceStateEvent) - assert state_event.resource_type == "Issue" - - -def test_list_merge_request_state_events( - project_merge_request, resp_list_merge_request_state_events -): - state_events = project_merge_request.resourcestateevents.list() - assert isinstance(state_events, list) - - state_event = state_events[0] - assert isinstance(state_event, ProjectMergeRequestResourceStateEvent) - assert state_event.resource_type == "MergeRequest" - - -def test_get_merge_request_state_event( - project_merge_request, resp_get_merge_request_state_event -): - state_event = project_merge_request.resourcestateevents.get(1) - assert isinstance(state_event, ProjectMergeRequestResourceStateEvent) - assert state_event.resource_type == "MergeRequest" diff --git a/tests/unit/objects/test_runners.py b/tests/unit/objects/test_runners.py deleted file mode 100644 index 686eec2..0000000 --- a/tests/unit/objects/test_runners.py +++ /dev/null @@ -1,282 +0,0 @@ -import re - -import pytest -import responses - -import gitlab - -runner_detail = { - "active": True, - "architecture": "amd64", - "description": "test-1-20150125", - "id": 6, - "ip_address": "127.0.0.1", - "is_shared": False, - "contacted_at": "2016-01-25T16:39:48.066Z", - "name": "test-runner", - "online": True, - "status": "online", - "platform": "linux", - "projects": [ - { - "id": 1, - "name": "GitLab Community Edition", - "name_with_namespace": "GitLab.org / GitLab Community Edition", - "path": "gitlab-foss", - "path_with_namespace": "gitlab-org/gitlab-foss", - } - ], - "revision": "5nj35", - "tag_list": ["ruby", "mysql"], - "version": "v13.0.0", - "access_level": "ref_protected", - "maximum_timeout": 3600, -} - -runner_shortinfo = { - "active": True, - "description": "test-1-20150125", - "id": 6, - "is_shared": False, - "ip_address": "127.0.0.1", - "name": "test-name", - "online": True, - "status": "online", -} - -runner_jobs = [ - { - "id": 6, - "ip_address": "127.0.0.1", - "status": "running", - "stage": "test", - "name": "test", - "ref": "master", - "tag": False, - "coverage": "99%", - "created_at": "2017-11-16T08:50:29.000Z", - "started_at": "2017-11-16T08:51:29.000Z", - "finished_at": "2017-11-16T08:53:29.000Z", - "duration": 120, - "user": { - "id": 1, - "name": "John Doe2", - "username": "user2", - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", - "web_url": "http://localhost/user2", - "created_at": "2017-11-16T18:38:46.000Z", - "bio": None, - "location": None, - "public_email": "", - "skype": "", - "linkedin": "", - "twitter": "", - "website_url": "", - "organization": None, - }, - } -] - - -@pytest.fixture -def resp_get_runners_jobs(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/runners/6/jobs", - json=runner_jobs, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_runners_list(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=re.compile(r".*?(/runners(/all)?|/(groups|projects)/1/runners)"), - json=[runner_shortinfo], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_runner_detail(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r".*?/runners/6") - rsps.add( - method=responses.GET, - url=pattern, - json=runner_detail, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.PUT, - url=pattern, - json=runner_detail, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_runner_register(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r".*?/runners") - rsps.add( - method=responses.POST, - url=pattern, - json={"id": "6", "token": "6337ff461c94fd3fa32ba3b1ff4125"}, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_runner_enable(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r".*?(projects|groups)/1/runners") - rsps.add( - method=responses.POST, - url=pattern, - json=runner_shortinfo, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_runner_delete(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r".*?/runners/6") - rsps.add( - method=responses.GET, - url=pattern, - json=runner_detail, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.DELETE, - url=pattern, - status=204, - ) - yield rsps - - -@pytest.fixture -def resp_runner_disable(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r".*?/(groups|projects)/1/runners/6") - rsps.add( - method=responses.DELETE, - url=pattern, - status=204, - ) - yield rsps - - -@pytest.fixture -def resp_runner_verify(): - with responses.RequestsMock() as rsps: - pattern = re.compile(r".*?/runners/verify") - rsps.add( - method=responses.POST, - url=pattern, - status=200, - ) - yield rsps - - -def test_owned_runners_list(gl: gitlab.Gitlab, resp_get_runners_list): - runners = gl.runners.list() - assert runners[0].active is True - assert runners[0].id == 6 - assert runners[0].name == "test-name" - assert len(runners) == 1 - - -def test_project_runners_list(gl: gitlab.Gitlab, resp_get_runners_list): - runners = gl.projects.get(1, lazy=True).runners.list() - assert runners[0].active is True - assert runners[0].id == 6 - assert runners[0].name == "test-name" - assert len(runners) == 1 - - -def test_group_runners_list(gl: gitlab.Gitlab, resp_get_runners_list): - runners = gl.groups.get(1, lazy=True).runners.list() - assert runners[0].active is True - assert runners[0].id == 6 - assert runners[0].name == "test-name" - assert len(runners) == 1 - - -def test_all_runners_list(gl: gitlab.Gitlab, resp_get_runners_list): - runners = gl.runners.all() - assert runners[0].active is True - assert runners[0].id == 6 - assert runners[0].name == "test-name" - assert len(runners) == 1 - - -def test_create_runner(gl: gitlab.Gitlab, resp_runner_register): - runner = gl.runners.create({"token": "token"}) - assert runner.id == "6" - assert runner.token == "6337ff461c94fd3fa32ba3b1ff4125" - - -def test_get_update_runner(gl: gitlab.Gitlab, resp_runner_detail): - runner = gl.runners.get(6) - assert runner.active is True - runner.tag_list.append("new") - runner.save() - - -def test_remove_runner(gl: gitlab.Gitlab, resp_runner_delete): - runner = gl.runners.get(6) - runner.delete() - gl.runners.delete(6) - - -def test_disable_project_runner(gl: gitlab.Gitlab, resp_runner_disable): - gl.projects.get(1, lazy=True).runners.delete(6) - - -def test_disable_group_runner(gl: gitlab.Gitlab, resp_runner_disable): - gl.groups.get(1, lazy=True).runners.delete(6) - - -def test_enable_project_runner(gl: gitlab.Gitlab, resp_runner_enable): - runner = gl.projects.get(1, lazy=True).runners.create({"runner_id": 6}) - assert runner.active is True - assert runner.id == 6 - assert runner.name == "test-name" - - -def test_enable_group_runner(gl: gitlab.Gitlab, resp_runner_enable): - runner = gl.groups.get(1, lazy=True).runners.create({"runner_id": 6}) - assert runner.active is True - assert runner.id == 6 - assert runner.name == "test-name" - - -def test_verify_runner(gl: gitlab.Gitlab, resp_runner_verify): - gl.runners.verify("token") - - -def test_runner_jobs(gl: gitlab.Gitlab, resp_get_runners_jobs): - jobs = gl.runners.get(6, lazy=True).jobs.list() - assert jobs[0].duration == 120 - assert jobs[0].name == "test" - assert jobs[0].user.get("name") == "John Doe2" - assert len(jobs) == 1 diff --git a/tests/unit/objects/test_services.py b/tests/unit/objects/test_services.py deleted file mode 100644 index 5b2bcb8..0000000 --- a/tests/unit/objects/test_services.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/services.html -""" - -import pytest -import responses - -from gitlab.v4.objects import ProjectService - - -@pytest.fixture -def resp_service(): - content = { - "id": 100152, - "title": "Pipelines emails", - "slug": "pipelines-email", - "created_at": "2019-01-14T08:46:43.637+01:00", - "updated_at": "2019-07-01T14:10:36.156+02:00", - "active": True, - "commit_events": True, - "push_events": True, - "issues_events": True, - "confidential_issues_events": True, - "merge_requests_events": True, - "tag_push_events": True, - "note_events": True, - "confidential_note_events": True, - "pipeline_events": True, - "wiki_page_events": True, - "job_events": True, - "comment_on_event_enabled": True, - "project_id": 1, - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/services", - json=[content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/services", - json=content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/services/pipelines-email", - json=content, - content_type="application/json", - status=200, - ) - updated_content = dict(content) - updated_content["issues_events"] = False - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/projects/1/services/pipelines-email", - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_active_services(project, resp_service): - services = project.services.list() - assert isinstance(services, list) - assert isinstance(services[0], ProjectService) - assert services[0].active - assert services[0].push_events - - -def test_list_available_services(project, resp_service): - services = project.services.available() - assert isinstance(services, list) - assert isinstance(services[0], str) - - -def test_get_service(project, resp_service): - service = project.services.get("pipelines-email") - assert isinstance(service, ProjectService) - assert service.push_events is True - - -def test_update_service(project, resp_service): - service = project.services.get("pipelines-email") - service.issues_events = False - service.save() - assert service.issues_events is False diff --git a/tests/unit/objects/test_snippets.py b/tests/unit/objects/test_snippets.py deleted file mode 100644 index 2540fc3..0000000 --- a/tests/unit/objects/test_snippets.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/project_snippets.html - https://docs.gitlab.com/ee/api/snippets.html (todo) -""" - -import pytest -import responses - -title = "Example Snippet Title" -visibility = "private" -new_title = "new-title" - - -@pytest.fixture -def resp_snippet(): - content = { - "title": title, - "description": "More verbose snippet description", - "file_name": "example.txt", - "content": "source code with multiple lines", - "visibility": visibility, - } - - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/snippets", - json=[content], - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/snippets/1", - json=content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/snippets", - json=content, - content_type="application/json", - status=200, - ) - - updated_content = dict(content) - updated_content["title"] = new_title - updated_content["visibility"] = visibility - - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/projects/1/snippets", - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_list_project_snippets(project, resp_snippet): - snippets = project.snippets.list() - assert len(snippets) == 1 - assert snippets[0].title == title - assert snippets[0].visibility == visibility - - -def test_get_project_snippet(project, resp_snippet): - snippet = project.snippets.get(1) - assert snippet.title == title - assert snippet.visibility == visibility - - -def test_create_update_project_snippets(project, resp_snippet): - snippet = project.snippets.create( - { - "title": title, - "file_name": title, - "content": title, - "visibility": visibility, - } - ) - assert snippet.title == title - assert snippet.visibility == visibility - - snippet.title = new_title - snippet.save() - assert snippet.title == new_title - assert snippet.visibility == visibility diff --git a/tests/unit/objects/test_submodules.py b/tests/unit/objects/test_submodules.py deleted file mode 100644 index 69c1cd7..0000000 --- a/tests/unit/objects/test_submodules.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/repository_submodules.html -""" -import pytest -import responses - - -@pytest.fixture -def resp_update_submodule(): - content = { - "id": "ed899a2f4b50b4370feeea94676502b42383c746", - "short_id": "ed899a2f4b5", - "title": "Message", - "author_name": "Author", - "author_email": "author@example.com", - "committer_name": "Author", - "committer_email": "author@example.com", - "created_at": "2018-09-20T09:26:24.000-07:00", - "message": "Message", - "parent_ids": ["ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"], - "committed_date": "2018-09-20T09:26:24.000-07:00", - "authored_date": "2018-09-20T09:26:24.000-07:00", - "status": None, - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.PUT, - url="http://localhost/api/v4/projects/1/repository/submodules/foo%2Fbar", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_update_submodule(project, resp_update_submodule): - ret = project.update_submodule( - submodule="foo/bar", - branch="master", - commit_sha="4c3674f66071e30b3311dac9b9ccc90502a72664", - commit_message="Message", - ) - assert isinstance(ret, dict) - assert ret["message"] == "Message" - assert ret["id"] == "ed899a2f4b50b4370feeea94676502b42383c746" diff --git a/tests/unit/objects/test_todos.py b/tests/unit/objects/test_todos.py deleted file mode 100644 index 058fe33..0000000 --- a/tests/unit/objects/test_todos.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/todos.html -""" - -import json -import os - -import pytest -import responses - -from gitlab.v4.objects import Todo - -with open(os.path.dirname(__file__) + "/../data/todo.json", "r") as json_file: - todo_content = json_file.read() - json_content = json.loads(todo_content) - - -@pytest.fixture -def resp_todo(): - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/todos", - json=json_content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/todos/102/mark_as_done", - json=json_content[0], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_mark_all_as_done(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/todos/mark_as_done", - json={}, - content_type="application/json", - status=204, - ) - yield rsps - - -def test_todo(gl, resp_todo): - todo = gl.todos.list()[0] - assert isinstance(todo, Todo) - assert todo.id == 102 - assert todo.target_type == "MergeRequest" - assert todo.target["assignee"]["username"] == "root" - - todo.mark_as_done() - - -def test_todo_mark_all_as_done(gl, resp_mark_all_as_done): - gl.todos.mark_all_as_done() diff --git a/tests/unit/objects/test_users.py b/tests/unit/objects/test_users.py deleted file mode 100644 index e46a315..0000000 --- a/tests/unit/objects/test_users.py +++ /dev/null @@ -1,217 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ce/api/users.html -""" -import pytest -import responses - -from gitlab.v4.objects import User, UserMembership, UserStatus - - -@pytest.fixture -def resp_get_user(): - content = { - "name": "name", - "id": 1, - "password": "password", - "username": "username", - "email": "email", - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/users/1", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_user_memberships(): - content = [ - { - "source_id": 1, - "source_name": "Project one", - "source_type": "Project", - "access_level": "20", - }, - { - "source_id": 3, - "source_name": "Group three", - "source_type": "Namespace", - "access_level": "20", - }, - ] - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/users/1/memberships", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_activate(): - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/users/1/activate", - json={}, - content_type="application/json", - status=201, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/users/1/deactivate", - json={}, - content_type="application/json", - status=201, - ) - yield rsps - - -@pytest.fixture -def resp_get_user_status(): - content = { - "message": "test", - "message_html": "<h1>Message</h1>", - "emoji": "thumbsup", - } - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/users/1/status", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_delete_user_identity(no_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.DELETE, - url="http://localhost/api/v4/users/1/identities/test_provider", - json=no_content, - content_type="application/json", - status=204, - ) - yield rsps - - -@pytest.fixture -def resp_follow_unfollow(): - user = { - "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", - } - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/users/1/follow", - json=user, - content_type="application/json", - status=201, - ) - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/users/1/unfollow", - json=user, - content_type="application/json", - status=201, - ) - yield rsps - - -@pytest.fixture -def resp_followers_following(): - content = [ - { - "id": 2, - "name": "Lennie Donnelly", - "username": "evette.kilback", - "state": "active", - "avatar_url": "https://www.gravatar.com/avatar/7955171a55ac4997ed81e5976287890a?s=80&d=identicon", - "web_url": "http://127.0.0.1:3000/evette.kilback", - }, - { - "id": 4, - "name": "Serena Bradtke", - "username": "cammy", - "state": "active", - "avatar_url": "https://www.gravatar.com/avatar/a2daad869a7b60d3090b7b9bef4baf57?s=80&d=identicon", - "web_url": "http://127.0.0.1:3000/cammy", - }, - ] - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/users/1/followers", - json=content, - content_type="application/json", - status=200, - ) - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/users/1/following", - json=content, - content_type="application/json", - status=200, - ) - yield rsps - - -def test_get_user(gl, resp_get_user): - user = gl.users.get(1) - assert isinstance(user, User) - assert user.name == "name" - assert user.id == 1 - - -def test_user_memberships(user, resp_get_user_memberships): - memberships = user.memberships.list() - assert isinstance(memberships[0], UserMembership) - assert memberships[0].source_type == "Project" - - -def test_user_status(user, resp_get_user_status): - status = user.status.get() - assert isinstance(status, UserStatus) - assert status.message == "test" - assert status.emoji == "thumbsup" - - -def test_user_activate_deactivate(user, resp_activate): - user.activate() - user.deactivate() - - -def test_delete_user_identity(user, resp_delete_user_identity): - user.identityproviders.delete("test_provider") - - -def test_user_follow_unfollow(user, resp_follow_unfollow): - user.follow() - user.unfollow() - - -def test_list_followers(user, resp_followers_following): - followers = user.followers_users.list() - followings = user.following_users.list() - assert isinstance(followers[0], User) - assert followers[0].id == 2 - assert isinstance(followings[0], User) - assert followings[1].id == 4 diff --git a/tests/unit/objects/test_variables.py b/tests/unit/objects/test_variables.py deleted file mode 100644 index fae37a8..0000000 --- a/tests/unit/objects/test_variables.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/instance_level_ci_variables.html -https://docs.gitlab.com/ee/api/project_level_variables.html -https://docs.gitlab.com/ee/api/group_level_variables.html -""" - -import re - -import pytest -import responses - -from gitlab.v4.objects import GroupVariable, ProjectVariable, Variable - -key = "TEST_VARIABLE_1" -value = "TEST_1" -new_value = "TEST_2" - -variable_content = { - "key": key, - "variable_type": "env_var", - "value": value, - "protected": False, - "masked": True, -} -variables_url = re.compile( - r"http://localhost/api/v4/(((groups|projects)/1)|(admin/ci))/variables" -) -variables_key_url = re.compile( - rf"http://localhost/api/v4/(((groups|projects)/1)|(admin/ci))/variables/{key}" -) - - -@pytest.fixture -def resp_list_variables(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=variables_url, - json=[variable_content], - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_get_variable(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url=variables_key_url, - json=variable_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_create_variable(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url=variables_url, - json=variable_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_update_variable(): - updated_content = dict(variable_content) - updated_content["value"] = new_value - - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.PUT, - url=variables_key_url, - json=updated_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_delete_variable(no_content): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.DELETE, - url=variables_key_url, - json=no_content, - content_type="application/json", - status=204, - ) - yield rsps - - -def test_list_instance_variables(gl, resp_list_variables): - variables = gl.variables.list() - assert isinstance(variables, list) - assert isinstance(variables[0], Variable) - assert variables[0].value == value - - -def test_get_instance_variable(gl, resp_get_variable): - variable = gl.variables.get(key) - assert isinstance(variable, Variable) - assert variable.value == value - - -def test_create_instance_variable(gl, resp_create_variable): - variable = gl.variables.create({"key": key, "value": value}) - assert isinstance(variable, Variable) - assert variable.value == value - - -def test_update_instance_variable(gl, resp_update_variable): - variable = gl.variables.get(key, lazy=True) - variable.value = new_value - variable.save() - assert variable.value == new_value - - -def test_delete_instance_variable(gl, resp_delete_variable): - variable = gl.variables.get(key, lazy=True) - variable.delete() - - -def test_list_project_variables(project, resp_list_variables): - variables = project.variables.list() - assert isinstance(variables, list) - assert isinstance(variables[0], ProjectVariable) - assert variables[0].value == value - - -def test_get_project_variable(project, resp_get_variable): - variable = project.variables.get(key) - assert isinstance(variable, ProjectVariable) - assert variable.value == value - - -def test_create_project_variable(project, resp_create_variable): - variable = project.variables.create({"key": key, "value": value}) - assert isinstance(variable, ProjectVariable) - assert variable.value == value - - -def test_update_project_variable(project, resp_update_variable): - variable = project.variables.get(key, lazy=True) - variable.value = new_value - variable.save() - assert variable.value == new_value - - -def test_delete_project_variable(project, resp_delete_variable): - variable = project.variables.get(key, lazy=True) - variable.delete() - - -def test_list_group_variables(group, resp_list_variables): - variables = group.variables.list() - assert isinstance(variables, list) - assert isinstance(variables[0], GroupVariable) - assert variables[0].value == value - - -def test_get_group_variable(group, resp_get_variable): - variable = group.variables.get(key) - assert isinstance(variable, GroupVariable) - assert variable.value == value - - -def test_create_group_variable(group, resp_create_variable): - variable = group.variables.create({"key": key, "value": value}) - assert isinstance(variable, GroupVariable) - assert variable.value == value - - -def test_update_group_variable(group, resp_update_variable): - variable = group.variables.get(key, lazy=True) - variable.value = new_value - variable.save() - assert variable.value == new_value - - -def test_delete_group_variable(group, resp_delete_variable): - variable = group.variables.get(key, lazy=True) - variable.delete() diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py deleted file mode 100644 index cccdfad..0000000 --- a/tests/unit/test_base.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2017 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import pickle - -import pytest - -import gitlab -from gitlab import base - - -class FakeGitlab(object): - pass - - -class FakeObject(base.RESTObject): - pass - - -class FakeManager(base.RESTManager): - _obj_cls = FakeObject - _path = "/tests" - - -@pytest.fixture -def fake_gitlab(): - return FakeGitlab() - - -@pytest.fixture -def fake_manager(fake_gitlab): - return FakeManager(fake_gitlab) - - -class TestRESTManager: - def test_computed_path_simple(self): - class MGR(base.RESTManager): - _path = "/tests" - _obj_cls = object - - mgr = MGR(FakeGitlab()) - assert mgr._computed_path == "/tests" - - def test_computed_path_with_parent(self): - class MGR(base.RESTManager): - _path = "/tests/%(test_id)s/cases" - _obj_cls = object - _from_parent_attrs = {"test_id": "id"} - - class Parent(object): - id = 42 - - mgr = MGR(FakeGitlab(), parent=Parent()) - assert mgr._computed_path == "/tests/42/cases" - - def test_path_property(self): - class MGR(base.RESTManager): - _path = "/tests" - _obj_cls = object - - mgr = MGR(FakeGitlab()) - assert mgr.path == "/tests" - - -class TestRESTObject: - def test_instantiate(self, fake_gitlab, fake_manager): - obj = FakeObject(fake_manager, {"foo": "bar"}) - - assert {"foo": "bar"} == obj._attrs - assert {} == obj._updated_attrs - assert obj._create_managers() is None - assert fake_manager == obj.manager - assert fake_gitlab == obj.manager.gitlab - - def test_instantiate_non_dict(self, fake_gitlab, fake_manager): - with pytest.raises(gitlab.exceptions.GitlabParsingError): - FakeObject(fake_manager, ["a", "list", "fails"]) - - def test_picklability(self, fake_manager): - obj = FakeObject(fake_manager, {"foo": "bar"}) - original_obj_module = obj._module - pickled = pickle.dumps(obj) - unpickled = pickle.loads(pickled) - assert isinstance(unpickled, FakeObject) - assert hasattr(unpickled, "_module") - assert unpickled._module == original_obj_module - pickle.dumps(unpickled) - - def test_attrs(self, fake_manager): - obj = FakeObject(fake_manager, {"foo": "bar"}) - - assert "bar" == obj.foo - with pytest.raises(AttributeError): - getattr(obj, "bar") - - obj.bar = "baz" - assert "baz" == obj.bar - assert {"foo": "bar"} == obj._attrs - assert {"bar": "baz"} == obj._updated_attrs - - def test_get_id(self, fake_manager): - obj = FakeObject(fake_manager, {"foo": "bar"}) - obj.id = 42 - assert 42 == obj.get_id() - - obj.id = None - assert obj.get_id() is None - - def test_custom_id_attr(self, fake_manager): - class OtherFakeObject(FakeObject): - _id_attr = "foo" - - obj = OtherFakeObject(fake_manager, {"foo": "bar"}) - assert "bar" == obj.get_id() - - def test_update_attrs(self, fake_manager): - obj = FakeObject(fake_manager, {"foo": "bar"}) - obj.bar = "baz" - obj._update_attrs({"foo": "foo", "bar": "bar"}) - assert {"foo": "foo", "bar": "bar"} == obj._attrs - assert {} == obj._updated_attrs - - def test_update_attrs_deleted(self, fake_manager): - obj = FakeObject(fake_manager, {"foo": "foo", "bar": "bar"}) - obj.bar = "baz" - obj._update_attrs({"foo": "foo"}) - assert {"foo": "foo"} == obj._attrs - assert {} == obj._updated_attrs - - def test_dir_unique(self, fake_manager): - obj = FakeObject(fake_manager, {"manager": "foo"}) - assert len(dir(obj)) == len(set(dir(obj))) - - def test_create_managers(self, fake_gitlab, fake_manager): - class ObjectWithManager(FakeObject): - fakes: "FakeManager" - - obj = ObjectWithManager(fake_manager, {"foo": "bar"}) - obj.id = 42 - assert isinstance(obj.fakes, FakeManager) - assert obj.fakes.gitlab == fake_gitlab - assert obj.fakes._parent == obj - - def test_equality(self, fake_manager): - obj1 = FakeObject(fake_manager, {"id": "foo"}) - obj2 = FakeObject(fake_manager, {"id": "foo", "other_attr": "bar"}) - assert obj1 == obj2 - - def test_equality_custom_id(self, fake_manager): - class OtherFakeObject(FakeObject): - _id_attr = "foo" - - obj1 = OtherFakeObject(fake_manager, {"foo": "bar"}) - obj2 = OtherFakeObject(fake_manager, {"foo": "bar", "other_attr": "baz"}) - assert obj1 == obj2 - - def test_inequality(self, fake_manager): - obj1 = FakeObject(fake_manager, {"id": "foo"}) - obj2 = FakeObject(fake_manager, {"id": "bar"}) - assert obj1 != obj2 - - def test_inequality_no_id(self, fake_manager): - obj1 = FakeObject(fake_manager, {"attr1": "foo"}) - obj2 = FakeObject(fake_manager, {"attr1": "bar"}) - assert obj1 != obj2 diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py deleted file mode 100644 index a9ca958..0000000 --- a/tests/unit/test_cli.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2016-2017 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import argparse -import io -import os -import tempfile -from contextlib import redirect_stderr # noqa: H302 - -import pytest - -from gitlab import cli - - -@pytest.mark.parametrize( - "what,expected_class", - [ - ("class", "Class"), - ("test-class", "TestClass"), - ("test-longer-class", "TestLongerClass"), - ("current-user-gpg-key", "CurrentUserGPGKey"), - ("user-gpg-key", "UserGPGKey"), - ("ldap-group", "LDAPGroup"), - ], -) -def test_what_to_cls(what, expected_class): - def _namespace(): - pass - - ExpectedClass = type(expected_class, (), {}) - _namespace.__dict__[expected_class] = ExpectedClass - - assert cli.what_to_cls(what, _namespace) == ExpectedClass - - -@pytest.mark.parametrize( - "class_name,expected_what", - [ - ("Class", "class"), - ("TestClass", "test-class"), - ("TestUPPERCASEClass", "test-uppercase-class"), - ("UPPERCASETestClass", "uppercase-test-class"), - ("CurrentUserGPGKey", "current-user-gpg-key"), - ("UserGPGKey", "user-gpg-key"), - ("LDAPGroup", "ldap-group"), - ], -) -def test_cls_to_what(class_name, expected_what): - TestClass = type(class_name, (), {}) - - assert cli.cls_to_what(TestClass) == expected_what - - -def test_die(): - fl = io.StringIO() - with redirect_stderr(fl): - with pytest.raises(SystemExit) as test: - cli.die("foobar") - assert fl.getvalue() == "foobar\n" - assert test.value.code == 1 - - -def test_parse_value(): - ret = cli._parse_value("foobar") - assert ret == "foobar" - - ret = cli._parse_value(True) - assert ret is True - - ret = cli._parse_value(1) - assert ret == 1 - - ret = cli._parse_value(None) - assert ret is None - - fd, temp_path = tempfile.mkstemp() - os.write(fd, b"content") - os.close(fd) - ret = cli._parse_value("@%s" % temp_path) - assert ret == "content" - os.unlink(temp_path) - - fl = io.StringIO() - with redirect_stderr(fl): - with pytest.raises(SystemExit) as exc: - cli._parse_value("@/thisfileprobablydoesntexist") - assert ( - fl.getvalue() == "[Errno 2] No such file or directory:" - " '/thisfileprobablydoesntexist'\n" - ) - assert exc.value.code == 1 - - -def test_base_parser(): - parser = cli._get_base_parser() - args = parser.parse_args(["-v", "-g", "gl_id", "-c", "foo.cfg", "-c", "bar.cfg"]) - assert args.verbose - assert args.gitlab == "gl_id" - assert args.config_file == ["foo.cfg", "bar.cfg"] - - -def test_v4_parse_args(): - parser = cli._get_parser() - args = parser.parse_args(["project", "list"]) - assert args.what == "project" - assert args.whaction == "list" - - -def test_v4_parser(): - parser = cli._get_parser() - subparsers = next( - action - for action in parser._actions - if isinstance(action, argparse._SubParsersAction) - ) - assert subparsers is not None - assert "project" in subparsers.choices - - user_subparsers = next( - action - for action in subparsers.choices["project"]._actions - if isinstance(action, argparse._SubParsersAction) - ) - assert user_subparsers is not None - assert "list" in user_subparsers.choices - assert "get" in user_subparsers.choices - assert "delete" in user_subparsers.choices - assert "update" in user_subparsers.choices - assert "create" in user_subparsers.choices - assert "archive" in user_subparsers.choices - assert "unarchive" in user_subparsers.choices - - actions = user_subparsers.choices["create"]._option_string_actions - assert not actions["--description"].required - - user_subparsers = next( - action - for action in subparsers.choices["group"]._actions - if isinstance(action, argparse._SubParsersAction) - ) - actions = user_subparsers.choices["create"]._option_string_actions - assert actions["--name"].required diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py deleted file mode 100644 index a62106b..0000000 --- a/tests/unit/test_config.py +++ /dev/null @@ -1,317 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2016-2017 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import io -import os -from textwrap import dedent - -import mock -import pytest - -from gitlab import config, USER_AGENT - -custom_user_agent = "my-package/1.0.0" - -valid_config = u"""[global] -default = one -ssl_verify = true -timeout = 2 - -[one] -url = http://one.url -private_token = ABCDEF - -[two] -url = https://two.url -private_token = GHIJKL -ssl_verify = false -timeout = 10 - -[three] -url = https://three.url -private_token = MNOPQR -ssl_verify = /path/to/CA/bundle.crt -per_page = 50 - -[four] -url = https://four.url -oauth_token = STUV -""" - -custom_user_agent_config = """[global] -default = one -user_agent = {} - -[one] -url = http://one.url -private_token = ABCDEF -""".format( - custom_user_agent -) - -no_default_config = u"""[global] -[there] -url = http://there.url -private_token = ABCDEF -""" - -missing_attr_config = u"""[global] -[one] -url = http://one.url - -[two] -private_token = ABCDEF - -[three] -meh = hem - -[four] -url = http://four.url -private_token = ABCDEF -per_page = 200 -""" - - -def global_retry_transient_errors(value: bool) -> str: - return u"""[global] -default = one -retry_transient_errors={} -[one] -url = http://one.url -private_token = ABCDEF""".format( - value - ) - - -def global_and_gitlab_retry_transient_errors( - global_value: bool, gitlab_value: bool -) -> str: - return u"""[global] - default = one - retry_transient_errors={global_value} - [one] - url = http://one.url - private_token = ABCDEF - retry_transient_errors={gitlab_value}""".format( - global_value=global_value, gitlab_value=gitlab_value - ) - - -@mock.patch.dict(os.environ, {"PYTHON_GITLAB_CFG": "/some/path"}) -def test_env_config_present(): - assert ["/some/path"] == config._env_config() - - -@mock.patch.dict(os.environ, {}, clear=True) -def test_env_config_missing(): - assert [] == config._env_config() - - -@mock.patch("os.path.exists") -def test_missing_config(path_exists): - path_exists.return_value = False - with pytest.raises(config.GitlabConfigMissingError): - config.GitlabConfigParser("test") - - -@mock.patch("os.path.exists") -@mock.patch("builtins.open") -def test_invalid_id(m_open, path_exists): - fd = io.StringIO(no_default_config) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - path_exists.return_value = True - config.GitlabConfigParser("there") - with pytest.raises(config.GitlabIDError): - config.GitlabConfigParser() - - fd = io.StringIO(valid_config) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - with pytest.raises(config.GitlabDataError): - config.GitlabConfigParser(gitlab_id="not_there") - - -@mock.patch("os.path.exists") -@mock.patch("builtins.open") -def test_invalid_data(m_open, path_exists): - fd = io.StringIO(missing_attr_config) - fd.close = mock.Mock(return_value=None, side_effect=lambda: fd.seek(0)) - m_open.return_value = fd - path_exists.return_value = True - - config.GitlabConfigParser("one") - config.GitlabConfigParser("one") - with pytest.raises(config.GitlabDataError): - config.GitlabConfigParser(gitlab_id="two") - with pytest.raises(config.GitlabDataError): - config.GitlabConfigParser(gitlab_id="three") - with pytest.raises(config.GitlabDataError) as emgr: - config.GitlabConfigParser("four") - assert "Unsupported per_page number: 200" == emgr.value.args[0] - - -@mock.patch("os.path.exists") -@mock.patch("builtins.open") -def test_valid_data(m_open, path_exists): - fd = io.StringIO(valid_config) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - path_exists.return_value = True - - cp = config.GitlabConfigParser() - assert "one" == cp.gitlab_id - assert "http://one.url" == cp.url - assert "ABCDEF" == cp.private_token - assert cp.oauth_token is None - assert 2 == cp.timeout - assert cp.ssl_verify is True - assert cp.per_page is None - - fd = io.StringIO(valid_config) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - cp = config.GitlabConfigParser(gitlab_id="two") - assert "two" == cp.gitlab_id - assert "https://two.url" == cp.url - assert "GHIJKL" == cp.private_token - assert cp.oauth_token is None - assert 10 == cp.timeout - assert cp.ssl_verify is False - - fd = io.StringIO(valid_config) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - cp = config.GitlabConfigParser(gitlab_id="three") - assert "three" == cp.gitlab_id - assert "https://three.url" == cp.url - assert "MNOPQR" == cp.private_token - assert cp.oauth_token is None - assert 2 == cp.timeout - assert "/path/to/CA/bundle.crt" == cp.ssl_verify - assert 50 == cp.per_page - - fd = io.StringIO(valid_config) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - cp = config.GitlabConfigParser(gitlab_id="four") - assert "four" == cp.gitlab_id - assert "https://four.url" == cp.url - assert cp.private_token is None - assert "STUV" == cp.oauth_token - assert 2 == cp.timeout - assert cp.ssl_verify is True - - -@mock.patch("os.path.exists") -@mock.patch("builtins.open") -def test_data_from_helper(m_open, path_exists, tmp_path): - helper = tmp_path / "helper.sh" - helper.write_text( - dedent( - """\ - #!/bin/sh - echo "secret" - """ - ) - ) - helper.chmod(0o755) - - fd = io.StringIO( - dedent( - """\ - [global] - default = helper - - [helper] - url = https://helper.url - oauth_token = helper: %s - """ - ) - % helper - ) - - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - cp = config.GitlabConfigParser(gitlab_id="helper") - assert "helper" == cp.gitlab_id - assert "https://helper.url" == cp.url - assert cp.private_token is None - assert "secret" == cp.oauth_token - - -@mock.patch("os.path.exists") -@mock.patch("builtins.open") -@pytest.mark.parametrize( - "config_string,expected_agent", - [ - (valid_config, USER_AGENT), - (custom_user_agent_config, custom_user_agent), - ], -) -def test_config_user_agent(m_open, path_exists, config_string, expected_agent): - fd = io.StringIO(config_string) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - - cp = config.GitlabConfigParser() - assert cp.user_agent == expected_agent - - -@mock.patch("os.path.exists") -@mock.patch("builtins.open") -@pytest.mark.parametrize( - "config_string,expected", - [ - pytest.param(valid_config, False, id="default_value"), - pytest.param( - global_retry_transient_errors(True), True, id="global_config_true" - ), - pytest.param( - global_retry_transient_errors(False), False, id="global_config_false" - ), - pytest.param( - global_and_gitlab_retry_transient_errors(False, True), - True, - id="gitlab_overrides_global_true", - ), - pytest.param( - global_and_gitlab_retry_transient_errors(True, False), - False, - id="gitlab_overrides_global_false", - ), - pytest.param( - global_and_gitlab_retry_transient_errors(True, True), - True, - id="gitlab_equals_global_true", - ), - pytest.param( - global_and_gitlab_retry_transient_errors(False, False), - False, - id="gitlab_equals_global_false", - ), - ], -) -def test_config_retry_transient_errors_when_global_config_is_set( - m_open, path_exists, config_string, expected -): - fd = io.StringIO(config_string) - fd.close = mock.Mock(return_value=None) - m_open.return_value = fd - - cp = config.GitlabConfigParser() - assert cp.retry_transient_errors == expected diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py deleted file mode 100644 index 57b394b..0000000 --- a/tests/unit/test_exceptions.py +++ /dev/null @@ -1,18 +0,0 @@ -import pytest - -from gitlab import exceptions - - -def test_error_raises_from_http_error(): - """Methods decorated with @on_http_error should raise from GitlabHttpError.""" - - class TestError(Exception): - pass - - @exceptions.on_http_error(TestError) - def raise_error_from_http_error(): - raise exceptions.GitlabHttpError - - with pytest.raises(TestError) as context: - raise_error_from_http_error() - assert isinstance(context.value.__cause__, exceptions.GitlabHttpError) diff --git a/tests/unit/test_gitlab.py b/tests/unit/test_gitlab.py deleted file mode 100644 index 2bd7d4d..0000000 --- a/tests/unit/test_gitlab.py +++ /dev/null @@ -1,196 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 Mika Mäenpää <mika.j.maenpaa@tut.fi>, -# Tampere University of Technology -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or` -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import pickle - -import pytest -from httmock import HTTMock, response, urlmatch, with_httmock # noqa - -from gitlab import DEFAULT_URL, Gitlab, GitlabList, USER_AGENT -from gitlab.v4.objects import CurrentUser - -localhost = "http://localhost" -username = "username" -user_id = 1 -token = "abc123" - - -@urlmatch(scheme="http", netloc="localhost", path="/api/v4/user", method="get") -def resp_get_user(url, request): - headers = {"content-type": "application/json"} - content = '{{"id": {0:d}, "username": "{1:s}"}}'.format(user_id, username).encode( - "utf-8" - ) - return response(200, content, headers, None, 5, request) - - -@urlmatch(scheme="http", netloc="localhost", path="/api/v4/tests", method="get") -def resp_page_1(url, request): - headers = { - "content-type": "application/json", - "X-Page": 1, - "X-Next-Page": 2, - "X-Per-Page": 1, - "X-Total-Pages": 2, - "X-Total": 2, - "Link": ("<http://localhost/api/v4/tests?per_page=1&page=2>;" ' rel="next"'), - } - content = '[{"a": "b"}]' - return response(200, content, headers, None, 5, request) - - -@urlmatch( - scheme="http", - netloc="localhost", - path="/api/v4/tests", - method="get", - query=r".*page=2", -) -def resp_page_2(url, request): - headers = { - "content-type": "application/json", - "X-Page": 2, - "X-Next-Page": 2, - "X-Per-Page": 1, - "X-Total-Pages": 2, - "X-Total": 2, - } - content = '[{"c": "d"}]' - return response(200, content, headers, None, 5, request) - - -def test_gitlab_build_list(gl): - with HTTMock(resp_page_1): - obj = gl.http_list("/tests", as_list=False) - assert len(obj) == 2 - assert obj._next_url == "http://localhost/api/v4/tests?per_page=1&page=2" - assert obj.current_page == 1 - assert obj.prev_page is None - assert obj.next_page == 2 - assert obj.per_page == 1 - assert obj.total_pages == 2 - assert obj.total == 2 - - with HTTMock(resp_page_2): - test_list = list(obj) - assert len(test_list) == 2 - assert test_list[0]["a"] == "b" - assert test_list[1]["c"] == "d" - - -@with_httmock(resp_page_1, resp_page_2) -def test_gitlab_all_omitted_when_as_list(gl): - result = gl.http_list("/tests", as_list=False, all=True) - assert isinstance(result, GitlabList) - - -def test_gitlab_strip_base_url(gl_trailing): - assert gl_trailing.url == "http://localhost" - - -def test_gitlab_strip_api_url(gl_trailing): - assert gl_trailing.api_url == "http://localhost/api/v4" - - -def test_gitlab_build_url(gl_trailing): - r = gl_trailing._build_url("/projects") - assert r == "http://localhost/api/v4/projects" - - -def test_gitlab_pickability(gl): - original_gl_objects = gl._objects - pickled = pickle.dumps(gl) - unpickled = pickle.loads(pickled) - assert isinstance(unpickled, Gitlab) - assert hasattr(unpickled, "_objects") - assert unpickled._objects == original_gl_objects - - -@with_httmock(resp_get_user) -def test_gitlab_token_auth(gl, callback=None): - gl.auth() - assert gl.user.username == username - assert gl.user.id == user_id - assert isinstance(gl.user, CurrentUser) - - -def test_gitlab_default_url(): - gl = Gitlab() - assert gl.url == DEFAULT_URL - - -@pytest.mark.parametrize( - "args, kwargs, expected_url, expected_private_token, expected_oauth_token", - [ - ([], {}, DEFAULT_URL, None, None), - ([None, token], {}, DEFAULT_URL, token, None), - ([localhost], {}, localhost, None, None), - ([localhost, token], {}, localhost, token, None), - ([localhost, None, token], {}, localhost, None, token), - ([], {"private_token": token}, DEFAULT_URL, token, None), - ([], {"oauth_token": token}, DEFAULT_URL, None, token), - ([], {"url": localhost}, localhost, None, None), - ([], {"url": localhost, "private_token": token}, localhost, token, None), - ([], {"url": localhost, "oauth_token": token}, localhost, None, token), - ], - ids=[ - "no_args", - "args_private_token", - "args_url", - "args_url_private_token", - "args_url_oauth_token", - "kwargs_private_token", - "kwargs_oauth_token", - "kwargs_url", - "kwargs_url_private_token", - "kwargs_url_oauth_token", - ], -) -def test_gitlab_args_kwargs( - args, kwargs, expected_url, expected_private_token, expected_oauth_token -): - gl = Gitlab(*args, **kwargs) - assert gl.url == expected_url - assert gl.private_token == expected_private_token - assert gl.oauth_token == expected_oauth_token - - -def test_gitlab_from_config(default_config): - config_path = default_config - Gitlab.from_config("one", [config_path]) - - -def test_gitlab_subclass_from_config(default_config): - class MyGitlab(Gitlab): - pass - - config_path = default_config - gl = MyGitlab.from_config("one", [config_path]) - assert isinstance(gl, MyGitlab) - - -@pytest.mark.parametrize( - "kwargs,expected_agent", - [ - ({}, USER_AGENT), - ({"user_agent": "my-package/1.0.0"}, "my-package/1.0.0"), - ], -) -def test_gitlab_user_agent(kwargs, expected_agent): - gl = Gitlab("http://localhost", **kwargs) - assert gl.headers["User-Agent"] == expected_agent diff --git a/tests/unit/test_gitlab_auth.py b/tests/unit/test_gitlab_auth.py deleted file mode 100644 index 314fbed..0000000 --- a/tests/unit/test_gitlab_auth.py +++ /dev/null @@ -1,85 +0,0 @@ -import pytest -import requests - -from gitlab import Gitlab - - -def test_invalid_auth_args(): - with pytest.raises(ValueError): - Gitlab( - "http://localhost", - api_version="4", - private_token="private_token", - oauth_token="bearer", - ) - with pytest.raises(ValueError): - Gitlab( - "http://localhost", - api_version="4", - oauth_token="bearer", - http_username="foo", - http_password="bar", - ) - with pytest.raises(ValueError): - Gitlab( - "http://localhost", - api_version="4", - private_token="private_token", - http_password="bar", - ) - with pytest.raises(ValueError): - Gitlab( - "http://localhost", - api_version="4", - private_token="private_token", - http_username="foo", - ) - - -def test_private_token_auth(): - gl = Gitlab("http://localhost", private_token="private_token", api_version="4") - assert gl.private_token == "private_token" - assert gl.oauth_token is None - assert gl.job_token is None - assert gl._http_auth is None - assert "Authorization" not in gl.headers - assert gl.headers["PRIVATE-TOKEN"] == "private_token" - assert "JOB-TOKEN" not in gl.headers - - -def test_oauth_token_auth(): - gl = Gitlab("http://localhost", oauth_token="oauth_token", api_version="4") - assert gl.private_token is None - assert gl.oauth_token == "oauth_token" - assert gl.job_token is None - assert gl._http_auth is None - assert gl.headers["Authorization"] == "Bearer oauth_token" - assert "PRIVATE-TOKEN" not in gl.headers - assert "JOB-TOKEN" not in gl.headers - - -def test_job_token_auth(): - gl = Gitlab("http://localhost", job_token="CI_JOB_TOKEN", api_version="4") - assert gl.private_token is None - assert gl.oauth_token is None - assert gl.job_token == "CI_JOB_TOKEN" - assert gl._http_auth is None - assert "Authorization" not in gl.headers - assert "PRIVATE-TOKEN" not in gl.headers - assert gl.headers["JOB-TOKEN"] == "CI_JOB_TOKEN" - - -def test_http_auth(): - gl = Gitlab( - "http://localhost", - private_token="private_token", - http_username="foo", - http_password="bar", - api_version="4", - ) - assert gl.private_token == "private_token" - assert gl.oauth_token is None - assert gl.job_token is None - assert isinstance(gl._http_auth, requests.auth.HTTPBasicAuth) - assert gl.headers["PRIVATE-TOKEN"] == "private_token" - assert "Authorization" not in gl.headers diff --git a/tests/unit/test_gitlab_http_methods.py b/tests/unit/test_gitlab_http_methods.py deleted file mode 100644 index ba57c31..0000000 --- a/tests/unit/test_gitlab_http_methods.py +++ /dev/null @@ -1,406 +0,0 @@ -import pytest -import requests -from httmock import HTTMock, response, urlmatch - -from gitlab import GitlabHttpError, GitlabList, GitlabParsingError, RedirectError - - -def test_build_url(gl): - r = gl._build_url("http://localhost/api/v4") - assert r == "http://localhost/api/v4" - r = gl._build_url("https://localhost/api/v4") - assert r == "https://localhost/api/v4" - r = gl._build_url("/projects") - assert r == "http://localhost/api/v4/projects" - - -def test_http_request(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '[{"name": "project1"}]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - http_r = gl.http_request("get", "/projects") - http_r.json() - assert http_r.status_code == 200 - - -def test_http_request_404(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="get") - def resp_cont(url, request): - content = {"Here is why it failed"} - return response(404, content, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_request("get", "/not_there") - - -@pytest.mark.parametrize("status_code", [500, 502, 503, 504]) -def test_http_request_with_only_failures(gl, status_code): - call_count = 0 - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - nonlocal call_count - call_count += 1 - return response(status_code, {"Here is why it failed"}, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_request("get", "/projects") - - assert call_count == 1 - - -def test_http_request_with_retry_on_method_for_transient_failures(gl): - call_count = 0 - calls_before_success = 3 - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - nonlocal call_count - call_count += 1 - status_code = 200 if call_count == calls_before_success else 500 - return response( - status_code, - {"Failure is the stepping stone to success"}, - {}, - None, - 5, - request, - ) - - with HTTMock(resp_cont): - http_r = gl.http_request("get", "/projects", retry_transient_errors=True) - - assert http_r.status_code == 200 - assert call_count == calls_before_success - - -def test_http_request_with_retry_on_class_for_transient_failures(gl_retry): - call_count = 0 - calls_before_success = 3 - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - nonlocal call_count - call_count += 1 - status_code = 200 if call_count == calls_before_success else 500 - return response( - status_code, - {"Failure is the stepping stone to success"}, - {}, - None, - 5, - request, - ) - - with HTTMock(resp_cont): - http_r = gl_retry.http_request("get", "/projects") - - assert http_r.status_code == 200 - assert call_count == calls_before_success - - -def test_http_request_with_retry_on_class_and_method_for_transient_failures(gl_retry): - call_count = 0 - calls_before_success = 3 - - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - nonlocal call_count - call_count += 1 - status_code = 200 if call_count == calls_before_success else 500 - return response(status_code, {"Here is why it failed"}, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl_retry.http_request("get", "/projects", retry_transient_errors=False) - - assert call_count == 1 - - -def create_redirect_response( - *, request: requests.models.PreparedRequest, http_method: str, api_path: str -) -> requests.models.Response: - """Create a Requests response object that has a redirect in it""" - - assert api_path.startswith("/") - http_method = http_method.upper() - - # Create a history which contains our original request which is redirected - history = [ - response( - status_code=302, - content="", - headers={"Location": f"http://example.com/api/v4{api_path}"}, - reason="Moved Temporarily", - request=request, - ) - ] - - # Create a "prepped" Request object to be the final redirect. The redirect - # will be a "GET" method as Requests changes the method to "GET" when there - # is a 301/302 redirect code. - req = requests.Request( - method="GET", - url=f"http://example.com/api/v4{api_path}", - ) - prepped = req.prepare() - - resp_obj = response( - status_code=200, - content="", - headers={}, - reason="OK", - elapsed=5, - request=prepped, - ) - resp_obj.history = history - return resp_obj - - -def test_http_request_302_get_does_not_raise(gl): - """Test to show that a redirect of a GET will not cause an error""" - - method = "get" - api_path = "/user/status" - - @urlmatch( - scheme="http", netloc="localhost", path=f"/api/v4{api_path}", method=method - ) - def resp_cont( - url: str, request: requests.models.PreparedRequest - ) -> requests.models.Response: - resp_obj = create_redirect_response( - request=request, http_method=method, api_path=api_path - ) - return resp_obj - - with HTTMock(resp_cont): - gl.http_request(verb=method, path=api_path) - - -def test_http_request_302_put_raises_redirect_error(gl): - """Test to show that a redirect of a PUT will cause an error""" - - method = "put" - api_path = "/user/status" - - @urlmatch( - scheme="http", netloc="localhost", path=f"/api/v4{api_path}", method=method - ) - def resp_cont( - url: str, request: requests.models.PreparedRequest - ) -> requests.models.Response: - resp_obj = create_redirect_response( - request=request, http_method=method, api_path=api_path - ) - return resp_obj - - with HTTMock(resp_cont): - with pytest.raises(RedirectError) as exc: - gl.http_request(verb=method, path=api_path) - error_message = exc.value.error_message - assert "Moved Temporarily" in error_message - assert "http://localhost/api/v4/user/status" in error_message - assert "http://example.com/api/v4/user/status" in error_message - - -def test_get_request(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url: str, request: requests.models.PreparedRequest): - headers = {"content-type": "application/json"} - content = '{"name": "project1"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - result = gl.http_get("/projects") - assert isinstance(result, dict) - assert result["name"] == "project1" - - -def test_get_request_raw(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - headers = {"content-type": "application/octet-stream"} - content = "content" - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - result = gl.http_get("/projects") - assert result.content.decode("utf-8") == "content" - - -def test_get_request_404(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="get") - def resp_cont(url, request): - content = {"Here is why it failed"} - return response(404, content, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_get("/not_there") - - -def test_get_request_invalid_data(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '["name": "project1"]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabParsingError): - gl.http_get("/projects") - - -def test_list_request(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - headers = {"content-type": "application/json", "X-Total": 1} - content = '[{"name": "project1"}]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - result = gl.http_list("/projects", as_list=True) - assert isinstance(result, list) - assert len(result) == 1 - - with HTTMock(resp_cont): - result = gl.http_list("/projects", as_list=False) - assert isinstance(result, GitlabList) - assert len(result) == 1 - - with HTTMock(resp_cont): - result = gl.http_list("/projects", all=True) - assert isinstance(result, list) - assert len(result) == 1 - - -def test_list_request_404(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="get") - def resp_cont(url, request): - content = {"Here is why it failed"} - return response(404, content, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_list("/not_there") - - -def test_list_request_invalid_data(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="get") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '["name": "project1"]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabParsingError): - gl.http_list("/projects") - - -def test_post_request(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="post") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '{"name": "project1"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - result = gl.http_post("/projects") - assert isinstance(result, dict) - assert result["name"] == "project1" - - -def test_post_request_404(gl): - @urlmatch( - scheme="http", netloc="localhost", path="/api/v4/not_there", method="post" - ) - def resp_cont(url, request): - content = {"Here is why it failed"} - return response(404, content, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_post("/not_there") - - -def test_post_request_invalid_data(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="post") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '["name": "project1"]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabParsingError): - gl.http_post("/projects") - - -def test_put_request(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="put") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '{"name": "project1"}' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - result = gl.http_put("/projects") - assert isinstance(result, dict) - assert result["name"] == "project1" - - -def test_put_request_404(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/not_there", method="put") - def resp_cont(url, request): - content = {"Here is why it failed"} - return response(404, content, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_put("/not_there") - - -def test_put_request_invalid_data(gl): - @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", method="put") - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = '["name": "project1"]' - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabParsingError): - gl.http_put("/projects") - - -def test_delete_request(gl): - @urlmatch( - scheme="http", netloc="localhost", path="/api/v4/projects", method="delete" - ) - def resp_cont(url, request): - headers = {"content-type": "application/json"} - content = "true" - return response(200, content, headers, None, 5, request) - - with HTTMock(resp_cont): - result = gl.http_delete("/projects") - assert isinstance(result, requests.Response) - assert result.json() is True - - -def test_delete_request_404(gl): - @urlmatch( - scheme="http", netloc="localhost", path="/api/v4/not_there", method="delete" - ) - def resp_cont(url, request): - content = {"Here is why it failed"} - return response(404, content, {}, None, 5, request) - - with HTTMock(resp_cont): - with pytest.raises(GitlabHttpError): - gl.http_delete("/not_there") diff --git a/tests/unit/test_types.py b/tests/unit/test_types.py deleted file mode 100644 index a2e5ff5..0000000 --- a/tests/unit/test_types.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2018 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from gitlab import types - - -def test_gitlab_attribute_get(): - o = types.GitlabAttribute("whatever") - assert o.get() == "whatever" - - o.set_from_cli("whatever2") - assert o.get() == "whatever2" - assert o.get_for_api() == "whatever2" - - o = types.GitlabAttribute() - assert o._value is None - - -def test_list_attribute_input(): - o = types.ListAttribute() - o.set_from_cli("foo,bar,baz") - assert o.get() == ["foo", "bar", "baz"] - - o.set_from_cli("foo") - assert o.get() == ["foo"] - - -def test_list_attribute_empty_input(): - o = types.ListAttribute() - o.set_from_cli("") - assert o.get() == [] - - o.set_from_cli(" ") - assert o.get() == [] - - -def test_list_attribute_get_for_api_from_cli(): - o = types.ListAttribute() - o.set_from_cli("foo,bar,baz") - assert o.get_for_api() == "foo,bar,baz" - - -def test_list_attribute_get_for_api_from_list(): - o = types.ListAttribute(["foo", "bar", "baz"]) - assert o.get_for_api() == "foo,bar,baz" - - -def test_list_attribute_get_for_api_from_int_list(): - o = types.ListAttribute([1, 9, 7]) - assert o.get_for_api() == "1,9,7" - - -def test_list_attribute_does_not_split_string(): - o = types.ListAttribute("foo") - assert o.get_for_api() == "foo" - - -def test_lowercase_string_attribute_get_for_api(): - o = types.LowercaseStringAttribute("FOO") - assert o.get_for_api() == "foo" diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py deleted file mode 100644 index dbe0838..0000000 --- a/tests/unit/test_utils.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2019 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from gitlab import utils - - -def test_clean_str_id(): - src = "nothing_special" - dest = "nothing_special" - assert dest == utils.clean_str_id(src) - - src = "foo#bar/baz/" - dest = "foo%23bar%2Fbaz%2F" - assert dest == utils.clean_str_id(src) - - src = "foo%bar/baz/" - dest = "foo%25bar%2Fbaz%2F" - assert dest == utils.clean_str_id(src) - - -def test_sanitized_url(): - src = "http://localhost/foo/bar" - dest = "http://localhost/foo/bar" - assert dest == utils.sanitized_url(src) - - src = "http://localhost/foo.bar.baz" - dest = "http://localhost/foo%2Ebar%2Ebaz" - assert dest == utils.sanitized_url(src) |