diff options
Diffstat (limited to 'tests')
93 files changed, 0 insertions, 10113 deletions
diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/__init__.py +++ /dev/null diff --git a/tests/functional/__init__.py b/tests/functional/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/functional/__init__.py +++ /dev/null diff --git a/tests/functional/api/__init__.py b/tests/functional/api/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/functional/api/__init__.py +++ /dev/null diff --git a/tests/functional/api/test_clusters.py b/tests/functional/api/test_clusters.py deleted file mode 100644 index 8930aad..0000000 --- a/tests/functional/api/test_clusters.py +++ /dev/null @@ -1,46 +0,0 @@ -def test_project_clusters(project): - project.clusters.create( - { - "name": "cluster1", - "platform_kubernetes_attributes": { - "api_url": "http://url", - "token": "tokenval", - }, - } - ) - clusters = project.clusters.list() - assert len(clusters) == 1 - - cluster = clusters[0] - cluster.platform_kubernetes_attributes = {"api_url": "http://newurl"} - cluster.save() - - cluster = project.clusters.list()[0] - assert cluster.platform_kubernetes["api_url"] == "http://newurl" - - cluster.delete() - assert len(project.clusters.list()) == 0 - - -def test_group_clusters(group): - group.clusters.create( - { - "name": "cluster1", - "platform_kubernetes_attributes": { - "api_url": "http://url", - "token": "tokenval", - }, - } - ) - clusters = group.clusters.list() - assert len(clusters) == 1 - - cluster = clusters[0] - cluster.platform_kubernetes_attributes = {"api_url": "http://newurl"} - cluster.save() - - cluster = group.clusters.list()[0] - assert cluster.platform_kubernetes["api_url"] == "http://newurl" - - cluster.delete() - assert len(group.clusters.list()) == 0 diff --git a/tests/functional/api/test_current_user.py b/tests/functional/api/test_current_user.py deleted file mode 100644 index 5802457..0000000 --- a/tests/functional/api/test_current_user.py +++ /dev/null @@ -1,42 +0,0 @@ -def test_current_user_email(gl): - gl.auth() - mail = gl.user.emails.create({"email": "current@user.com"}) - assert len(gl.user.emails.list()) == 1 - - mail.delete() - assert len(gl.user.emails.list()) == 0 - - -def test_current_user_gpg_keys(gl, GPG_KEY): - gl.auth() - gkey = gl.user.gpgkeys.create({"key": GPG_KEY}) - assert len(gl.user.gpgkeys.list()) == 1 - - # Seems broken on the gitlab side - gkey = gl.user.gpgkeys.get(gkey.id) - gkey.delete() - assert len(gl.user.gpgkeys.list()) == 0 - - -def test_current_user_ssh_keys(gl, SSH_KEY): - gl.auth() - key = gl.user.keys.create({"title": "testkey", "key": SSH_KEY}) - assert len(gl.user.keys.list()) == 1 - - key.delete() - assert len(gl.user.keys.list()) == 0 - - -def test_current_user_status(gl): - gl.auth() - message = "Test" - emoji = "thumbsup" - status = gl.user.status.get() - - status.message = message - status.emoji = emoji - status.save() - - new_status = gl.user.status.get() - assert new_status.message == message - assert new_status.emoji == emoji diff --git a/tests/functional/api/test_deploy_keys.py b/tests/functional/api/test_deploy_keys.py deleted file mode 100644 index 18828a2..0000000 --- a/tests/functional/api/test_deploy_keys.py +++ /dev/null @@ -1,12 +0,0 @@ -def test_project_deploy_keys(gl, project, DEPLOY_KEY): - deploy_key = project.keys.create({"title": "foo@bar", "key": DEPLOY_KEY}) - project_keys = list(project.keys.list()) - assert len(project_keys) == 1 - - project2 = gl.projects.create({"name": "deploy-key-project"}) - project2.keys.enable(deploy_key.id) - assert len(project2.keys.list()) == 1 - - project2.keys.delete(deploy_key.id) - assert len(project2.keys.list()) == 0 - project2.delete() diff --git a/tests/functional/api/test_deploy_tokens.py b/tests/functional/api/test_deploy_tokens.py deleted file mode 100644 index efcf8b1..0000000 --- a/tests/functional/api/test_deploy_tokens.py +++ /dev/null @@ -1,36 +0,0 @@ -def test_project_deploy_tokens(gl, project): - deploy_token = project.deploytokens.create( - { - "name": "foo", - "username": "bar", - "expires_at": "2022-01-01", - "scopes": ["read_registry"], - } - ) - assert len(project.deploytokens.list()) == 1 - assert gl.deploytokens.list() == project.deploytokens.list() - - assert project.deploytokens.list()[0].name == "foo" - assert project.deploytokens.list()[0].expires_at == "2022-01-01T00:00:00.000Z" - assert project.deploytokens.list()[0].scopes == ["read_registry"] - assert project.deploytokens.list()[0].username == "bar" - - deploy_token.delete() - assert len(project.deploytokens.list()) == 0 - assert len(gl.deploytokens.list()) == 0 - - -def test_group_deploy_tokens(gl, group): - deploy_token = group.deploytokens.create( - { - "name": "foo", - "scopes": ["read_registry"], - } - ) - - assert len(group.deploytokens.list()) == 1 - assert gl.deploytokens.list() == group.deploytokens.list() - - deploy_token.delete() - assert len(group.deploytokens.list()) == 0 - assert len(gl.deploytokens.list()) == 0 diff --git a/tests/functional/api/test_gitlab.py b/tests/functional/api/test_gitlab.py deleted file mode 100644 index 7a70a56..0000000 --- a/tests/functional/api/test_gitlab.py +++ /dev/null @@ -1,183 +0,0 @@ -import pytest - -import gitlab - - -def test_auth_from_config(gl, temp_dir): - """Test token authentication from config file""" - test_gitlab = gitlab.Gitlab.from_config( - config_files=[temp_dir / "python-gitlab.cfg"] - ) - test_gitlab.auth() - assert isinstance(test_gitlab.user, gitlab.v4.objects.CurrentUser) - - -def test_broadcast_messages(gl): - msg = gl.broadcastmessages.create({"message": "this is the message"}) - msg.color = "#444444" - msg.save() - msg_id = msg.id - - msg = gl.broadcastmessages.list(all=True)[0] - assert msg.color == "#444444" - - msg = gl.broadcastmessages.get(msg_id) - assert msg.color == "#444444" - - msg.delete() - assert len(gl.broadcastmessages.list()) == 0 - - -def test_markdown(gl): - html = gl.markdown("foo") - assert "foo" in html - - -def test_lint(gl): - success, errors = gl.lint("Invalid") - assert success is False - assert errors - - -def test_sidekiq_queue_metrics(gl): - out = gl.sidekiq.queue_metrics() - assert isinstance(out, dict) - assert "pages" in out["queues"] - - -def test_sidekiq_process_metrics(gl): - out = gl.sidekiq.process_metrics() - assert isinstance(out, dict) - assert "hostname" in out["processes"][0] - - -def test_sidekiq_job_stats(gl): - out = gl.sidekiq.job_stats() - assert isinstance(out, dict) - assert "processed" in out["jobs"] - - -def test_sidekiq_compound_metrics(gl): - out = gl.sidekiq.compound_metrics() - assert isinstance(out, dict) - assert "jobs" in out - assert "processes" in out - assert "queues" in out - - -def test_gitlab_settings(gl): - settings = gl.settings.get() - settings.default_projects_limit = 42 - settings.save() - settings = gl.settings.get() - assert settings.default_projects_limit == 42 - - -def test_template_dockerfile(gl): - assert gl.dockerfiles.list() - - dockerfile = gl.dockerfiles.get("Node") - assert dockerfile.content is not None - - -def test_template_gitignore(gl): - assert gl.gitignores.list() - gitignore = gl.gitignores.get("Node") - assert gitignore.content is not None - - -def test_template_gitlabciyml(gl): - assert gl.gitlabciymls.list() - gitlabciyml = gl.gitlabciymls.get("Nodejs") - assert gitlabciyml.content is not None - - -def test_template_license(gl): - assert gl.licenses.list() - license = gl.licenses.get( - "bsd-2-clause", project="mytestproject", fullname="mytestfullname" - ) - assert "mytestfullname" in license.content - - -def test_hooks(gl): - hook = gl.hooks.create({"url": "http://whatever.com"}) - assert len(gl.hooks.list()) == 1 - - hook.delete() - assert len(gl.hooks.list()) == 0 - - -def test_namespaces(gl): - namespace = gl.namespaces.list(all=True) - assert namespace - - namespace = gl.namespaces.list(search="root", all=True)[0] - assert namespace.kind == "user" - - -def test_notification_settings(gl): - settings = gl.notificationsettings.get() - settings.level = gitlab.NOTIFICATION_LEVEL_WATCH - settings.save() - - settings = gl.notificationsettings.get() - assert settings.level == gitlab.NOTIFICATION_LEVEL_WATCH - - -def test_user_activities(gl): - activities = gl.user_activities.list(query_parameters={"from": "2019-01-01"}) - assert isinstance(activities, list) - - -def test_events(gl): - events = gl.events.list() - assert isinstance(events, list) - - -@pytest.mark.skip -def test_features(gl): - feat = gl.features.set("foo", 30) - assert feat.name == "foo" - assert len(gl.features.list()) == 1 - - feat.delete() - assert len(gl.features.list()) == 0 - - -def test_pagination(gl, project): - project2 = gl.projects.create({"name": "project-page-2"}) - - list1 = gl.projects.list(per_page=1, page=1) - list2 = gl.projects.list(per_page=1, page=2) - assert len(list1) == 1 - assert len(list2) == 1 - assert list1[0].id != list2[0].id - - project2.delete() - - -def test_rate_limits(gl): - settings = gl.settings.get() - settings.throttle_authenticated_api_enabled = True - settings.throttle_authenticated_api_requests_per_period = 1 - settings.throttle_authenticated_api_period_in_seconds = 3 - settings.save() - - projects = list() - for i in range(0, 20): - projects.append(gl.projects.create({"name": str(i) + "ok"})) - - with pytest.raises(gitlab.GitlabCreateError) as e: - for i in range(20, 40): - projects.append( - gl.projects.create( - {"name": str(i) + "shouldfail"}, obey_rate_limit=False - ) - ) - - assert "Retry later" in str(e.value) - - settings.throttle_authenticated_api_enabled = False - settings.save() - [project.delete() for project in projects] diff --git a/tests/functional/api/test_groups.py b/tests/functional/api/test_groups.py deleted file mode 100644 index 665c933..0000000 --- a/tests/functional/api/test_groups.py +++ /dev/null @@ -1,223 +0,0 @@ -import pytest - -import gitlab - - -def test_groups(gl): - # TODO: This one still needs lots of work - user = gl.users.create( - { - "email": "user@test.com", - "username": "user", - "name": "user", - "password": "user_pass", - } - ) - user2 = gl.users.create( - { - "email": "user2@test.com", - "username": "user2", - "name": "user2", - "password": "user2_pass", - } - ) - group1 = gl.groups.create({"name": "group1", "path": "group1"}) - group2 = gl.groups.create({"name": "group2", "path": "group2"}) - - p_id = gl.groups.list(search="group2")[0].id - group3 = gl.groups.create({"name": "group3", "path": "group3", "parent_id": p_id}) - group4 = gl.groups.create({"name": "group4", "path": "group4"}) - - assert len(gl.groups.list()) == 4 - assert len(gl.groups.list(search="oup1")) == 1 - assert group3.parent_id == p_id - assert group2.subgroups.list()[0].id == group3.id - assert group2.descendant_groups.list()[0].id == group3.id - - filtered_groups = gl.groups.list(skip_groups=[group3.id, group4.id]) - assert group3 not in filtered_groups - assert group3 not in filtered_groups - - group1.members.create( - {"access_level": gitlab.const.OWNER_ACCESS, "user_id": user.id} - ) - group1.members.create( - {"access_level": gitlab.const.GUEST_ACCESS, "user_id": user2.id} - ) - group2.members.create( - {"access_level": gitlab.const.OWNER_ACCESS, "user_id": user2.id} - ) - - group4.share(group1.id, gitlab.const.DEVELOPER_ACCESS) - group4.share(group2.id, gitlab.const.MAINTAINER_ACCESS) - # Reload group4 to have updated shared_with_groups - group4 = gl.groups.get(group4.id) - assert len(group4.shared_with_groups) == 2 - group4.unshare(group1.id) - # Reload group4 to have updated shared_with_groups - group4 = gl.groups.get(group4.id) - assert len(group4.shared_with_groups) == 1 - - # User memberships (admin only) - memberships1 = user.memberships.list() - assert len(memberships1) == 1 - - memberships2 = user2.memberships.list() - assert len(memberships2) == 2 - - membership = memberships1[0] - assert membership.source_type == "Namespace" - assert membership.access_level == gitlab.const.OWNER_ACCESS - - project_memberships = user.memberships.list(type="Project") - assert len(project_memberships) == 0 - - group_memberships = user.memberships.list(type="Namespace") - assert len(group_memberships) == 1 - - with pytest.raises(gitlab.GitlabListError) as e: - membership = user.memberships.list(type="Invalid") - assert "type does not have a valid value" in str(e.value) - - with pytest.raises(gitlab.GitlabListError) as e: - user.memberships.list(sudo=user.name) - assert "403 Forbidden" in str(e.value) - - # Administrator belongs to the groups - assert len(group1.members.list()) == 3 - assert len(group2.members.list()) == 2 - - group1.members.delete(user.id) - assert len(group1.members.list()) == 2 - assert len(group1.members_all.list()) - member = group1.members.get(user2.id) - member.access_level = gitlab.const.OWNER_ACCESS - member.save() - member = group1.members.get(user2.id) - assert member.access_level == gitlab.const.OWNER_ACCESS - - group2.members.delete(gl.user.id) - - -@pytest.mark.skip(reason="Commented out in legacy test") -def test_group_labels(group): - group.labels.create({"name": "foo", "description": "bar", "color": "#112233"}) - label = group.labels.get("foo") - assert label.description == "bar" - - label.description = "baz" - label.save() - label = group.labels.get("foo") - assert label.description == "baz" - assert len(group.labels.list()) == 1 - - label.delete() - assert len(group.labels.list()) == 0 - - -def test_group_notification_settings(group): - settings = group.notificationsettings.get() - settings.level = "disabled" - settings.save() - - settings = group.notificationsettings.get() - assert settings.level == "disabled" - - -def test_group_badges(group): - badge_image = "http://example.com" - badge_link = "http://example/img.svg" - badge = group.badges.create({"link_url": badge_link, "image_url": badge_image}) - assert len(group.badges.list()) == 1 - - badge.image_url = "http://another.example.com" - badge.save() - - badge = group.badges.get(badge.id) - assert badge.image_url == "http://another.example.com" - - badge.delete() - assert len(group.badges.list()) == 0 - - -def test_group_milestones(group): - milestone = group.milestones.create({"title": "groupmilestone1"}) - assert len(group.milestones.list()) == 1 - - milestone.due_date = "2020-01-01T00:00:00Z" - milestone.save() - milestone.state_event = "close" - milestone.save() - - milestone = group.milestones.get(milestone.id) - assert milestone.state == "closed" - assert len(milestone.issues()) == 0 - assert len(milestone.merge_requests()) == 0 - - -def test_group_custom_attributes(gl, group): - attrs = group.customattributes.list() - assert len(attrs) == 0 - - attr = group.customattributes.set("key", "value1") - assert len(gl.groups.list(custom_attributes={"key": "value1"})) == 1 - assert attr.key == "key" - assert attr.value == "value1" - assert len(group.customattributes.list()) == 1 - - attr = group.customattributes.set("key", "value2") - attr = group.customattributes.get("key") - assert attr.value == "value2" - assert len(group.customattributes.list()) == 1 - - attr.delete() - assert len(group.customattributes.list()) == 0 - - -def test_group_subgroups_projects(gl, user): - # TODO: fixture factories - group1 = gl.groups.list(search="group1")[0] - group2 = gl.groups.list(search="group2")[0] - - group3 = gl.groups.create( - {"name": "subgroup1", "path": "subgroup1", "parent_id": group1.id} - ) - group4 = gl.groups.create( - {"name": "subgroup2", "path": "subgroup2", "parent_id": group2.id} - ) - - gr1_project = gl.projects.create({"name": "gr1_project", "namespace_id": group1.id}) - gr2_project = gl.projects.create({"name": "gr2_project", "namespace_id": group3.id}) - - assert group3.parent_id == group1.id - assert group4.parent_id == group2.id - assert gr1_project.namespace["id"] == group1.id - assert gr2_project.namespace["parent_id"] == group1.id - - -@pytest.mark.skip -def test_group_wiki(group): - content = "Group Wiki page content" - wiki = group.wikis.create({"title": "groupwikipage", "content": content}) - assert len(group.wikis.list()) == 1 - - wiki = group.wikis.get(wiki.slug) - assert wiki.content == content - - wiki.content = "new content" - wiki.save() - wiki.delete() - assert len(group.wikis.list()) == 0 - - -@pytest.mark.skip(reason="EE feature") -def test_group_hooks(group): - hook = group.hooks.create({"url": "http://hook.url"}) - assert len(group.hooks.list()) == 1 - - hook.note_events = True - hook.save() - - hook = group.hooks.get(hook.id) - assert hook.note_events is True - hook.delete() diff --git a/tests/functional/api/test_import_export.py b/tests/functional/api/test_import_export.py deleted file mode 100644 index d4bdd19..0000000 --- a/tests/functional/api/test_import_export.py +++ /dev/null @@ -1,66 +0,0 @@ -import time - -import gitlab - - -def test_group_import_export(gl, group, temp_dir): - export = group.exports.create() - assert export.message == "202 Accepted" - - # We cannot check for export_status with group export API - time.sleep(10) - - import_archive = temp_dir / "gitlab-group-export.tgz" - import_path = "imported_group" - import_name = "Imported Group" - - with open(import_archive, "wb") as f: - export.download(streamed=True, action=f.write) - - with open(import_archive, "rb") as f: - output = gl.groups.import_group(f, import_path, import_name) - assert output["message"] == "202 Accepted" - - # We cannot check for returned ID with group import API - time.sleep(10) - group_import = gl.groups.get(import_path) - - assert group_import.path == import_path - assert group_import.name == import_name - - -def test_project_import_export(gl, project, temp_dir): - export = project.exports.create() - assert export.message == "202 Accepted" - - export = project.exports.get() - assert isinstance(export, gitlab.v4.objects.ProjectExport) - - count = 0 - while export.export_status != "finished": - time.sleep(1) - export.refresh() - count += 1 - if count == 15: - raise Exception("Project export taking too much time") - - with open(temp_dir / "gitlab-export.tgz", "wb") as f: - export.download(streamed=True, action=f.write) - - output = gl.projects.import_project( - open(temp_dir / "gitlab-export.tgz", "rb"), - "imported_project", - name="Imported Project", - ) - project_import = gl.projects.get(output["id"], lazy=True).imports.get() - - assert project_import.path == "imported_project" - assert project_import.name == "Imported Project" - - count = 0 - while project_import.import_status != "finished": - time.sleep(1) - project_import.refresh() - count += 1 - if count == 15: - raise Exception("Project import taking too much time") diff --git a/tests/functional/api/test_issues.py b/tests/functional/api/test_issues.py deleted file mode 100644 index 64db46e..0000000 --- a/tests/functional/api/test_issues.py +++ /dev/null @@ -1,93 +0,0 @@ -import gitlab - - -def test_create_issue(project): - issue = project.issues.create({"title": "my issue 1"}) - issue2 = project.issues.create({"title": "my issue 2"}) - issue_iids = [issue.iid for issue in project.issues.list()] - assert len(issue_iids) == 2 - - # Test 'iids' as a list - assert len(project.issues.list(iids=issue_iids)) == 2 - - issue2.state_event = "close" - issue2.save() - assert len(project.issues.list(state="closed")) == 1 - assert len(project.issues.list(state="opened")) == 1 - - assert isinstance(issue.user_agent_detail(), dict) - assert issue.user_agent_detail()["user_agent"] - assert issue.participants() - assert type(issue.closed_by()) == list - assert type(issue.related_merge_requests()) == list - - -def test_issue_notes(issue): - size = len(issue.notes.list()) - - note = issue.notes.create({"body": "This is an issue note"}) - assert len(issue.notes.list()) == size + 1 - - emoji = note.awardemojis.create({"name": "tractor"}) - assert len(note.awardemojis.list()) == 1 - - emoji.delete() - assert len(note.awardemojis.list()) == 0 - - note.delete() - assert len(issue.notes.list()) == size - - -def test_issue_labels(project, issue): - project.labels.create({"name": "label2", "color": "#aabbcc"}) - issue.labels = ["label2"] - issue.save() - - assert issue in project.issues.list(labels=["label2"]) - assert issue in project.issues.list(labels="label2") - assert issue in project.issues.list(labels="Any") - assert issue not in project.issues.list(labels="None") - - -def test_issue_events(issue): - events = issue.resourcelabelevents.list() - assert isinstance(events, list) - - event = issue.resourcelabelevents.get(events[0].id) - assert isinstance(event, gitlab.v4.objects.ProjectIssueResourceLabelEvent) - - -def test_issue_milestones(project, milestone): - data = {"title": "my issue 1", "milestone_id": milestone.id} - issue = project.issues.create(data) - assert milestone.issues().next().title == "my issue 1" - - milestone_events = issue.resourcemilestoneevents.list() - assert isinstance(milestone_events, list) - - milestone_event = issue.resourcemilestoneevents.get(milestone_events[0].id) - assert isinstance( - milestone_event, gitlab.v4.objects.ProjectIssueResourceMilestoneEvent - ) - - milestone_issues = project.issues.list(milestone=milestone.title) - assert len(milestone_issues) == 1 - - -def test_issue_discussions(issue): - size = len(issue.discussions.list()) - - discussion = issue.discussions.create({"body": "Discussion body"}) - assert len(issue.discussions.list()) == size + 1 - - d_note = discussion.notes.create({"body": "first note"}) - d_note_from_get = discussion.notes.get(d_note.id) - d_note_from_get.body = "updated body" - d_note_from_get.save() - - discussion = issue.discussions.get(discussion.id) - assert discussion.attributes["notes"][-1]["body"] == "updated body" - - d_note_from_get.delete() - discussion = issue.discussions.get(discussion.id) - assert len(discussion.attributes["notes"]) == 1 diff --git a/tests/functional/api/test_keys.py b/tests/functional/api/test_keys.py deleted file mode 100644 index 82a75e5..0000000 --- a/tests/functional/api/test_keys.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ce/api/keys.html -""" -import base64 -import hashlib - - -def key_fingerprint(key): - key_part = key.split()[1] - decoded = base64.b64decode(key_part.encode("ascii")) - digest = hashlib.sha256(decoded).digest() - return "SHA256:" + base64.b64encode(digest).rstrip(b"=").decode("utf-8") - - -def test_keys_ssh(gl, user, SSH_KEY): - key = user.keys.create({"title": "foo@bar", "key": SSH_KEY}) - - # Get key by ID (admin only). - key_by_id = gl.keys.get(key.id) - assert key_by_id.title == key.title - assert key_by_id.key == key.key - - fingerprint = key_fingerprint(SSH_KEY) - # Get key by fingerprint (admin only). - key_by_fingerprint = gl.keys.get(fingerprint=fingerprint) - assert key_by_fingerprint.title == key.title - assert key_by_fingerprint.key == key.key - - key.delete() - - -def test_keys_deploy(gl, project, DEPLOY_KEY): - key = project.keys.create({"title": "foo@bar", "key": DEPLOY_KEY}) - - fingerprint = key_fingerprint(DEPLOY_KEY) - key_by_fingerprint = gl.keys.get(fingerprint=fingerprint) - assert key_by_fingerprint.title == key.title - assert key_by_fingerprint.key == key.key - assert len(key_by_fingerprint.deploy_keys_projects) == 1 - - key.delete() diff --git a/tests/functional/api/test_merge_requests.py b/tests/functional/api/test_merge_requests.py deleted file mode 100644 index b20b66a..0000000 --- a/tests/functional/api/test_merge_requests.py +++ /dev/null @@ -1,205 +0,0 @@ -import time - -import pytest - -import gitlab -import gitlab.v4.objects - - -def test_merge_requests(project): - project.files.create( - { - "file_path": "README.rst", - "branch": "master", - "content": "Initial content", - "commit_message": "Initial commit", - } - ) - - source_branch = "branch1" - project.branches.create({"branch": source_branch, "ref": "master"}) - - project.files.create( - { - "file_path": "README2.rst", - "branch": source_branch, - "content": "Initial content", - "commit_message": "New commit in new branch", - } - ) - project.mergerequests.create( - {"source_branch": "branch1", "target_branch": "master", "title": "MR readme2"} - ) - - -def test_merge_request_discussion(project): - mr = project.mergerequests.list()[0] - size = len(mr.discussions.list()) - - discussion = mr.discussions.create({"body": "Discussion body"}) - assert len(mr.discussions.list()) == size + 1 - - note = discussion.notes.create({"body": "first note"}) - note_from_get = discussion.notes.get(note.id) - note_from_get.body = "updated body" - note_from_get.save() - - discussion = mr.discussions.get(discussion.id) - assert discussion.attributes["notes"][-1]["body"] == "updated body" - - note_from_get.delete() - discussion = mr.discussions.get(discussion.id) - assert len(discussion.attributes["notes"]) == 1 - - -def test_merge_request_labels(project): - mr = project.mergerequests.list()[0] - mr.labels = ["label2"] - mr.save() - - events = mr.resourcelabelevents.list() - assert events - - event = mr.resourcelabelevents.get(events[0].id) - assert event - - -def test_merge_request_milestone_events(project, milestone): - mr = project.mergerequests.list()[0] - mr.milestone_id = milestone.id - mr.save() - - milestones = mr.resourcemilestoneevents.list() - assert milestones - - milestone = mr.resourcemilestoneevents.get(milestones[0].id) - assert milestone - - -def test_merge_request_basic(project): - mr = project.mergerequests.list()[0] - # basic testing: only make sure that the methods exist - mr.commits() - mr.changes() - assert mr.participants() - - -def test_merge_request_rebase(project): - mr = project.mergerequests.list()[0] - assert mr.rebase() - - -@pytest.mark.skip(reason="flaky test") -def test_merge_request_merge(project): - mr = project.mergerequests.list()[0] - mr.merge() - project.branches.delete(mr.source_branch) - - with pytest.raises(gitlab.GitlabMRClosedError): - # Two merge attempts should raise GitlabMRClosedError - mr.merge() - - -def test_merge_request_should_remove_source_branch( - project, merge_request, wait_for_sidekiq -) -> None: - """Test to ensure - https://github.com/python-gitlab/python-gitlab/issues/1120 is fixed. - Bug reported that they could not use 'should_remove_source_branch' in - mr.merge() call""" - - source_branch = "remove_source_branch" - mr = merge_request(source_branch=source_branch) - - mr.merge(should_remove_source_branch=True) - - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - # Wait until it is merged - mr_iid = mr.iid - for _ in range(60): - mr = project.mergerequests.get(mr_iid) - if mr.merged_at is not None: - break - time.sleep(0.5) - assert mr.merged_at is not None - time.sleep(0.5) - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - # Ensure we can NOT get the MR branch - with pytest.raises(gitlab.exceptions.GitlabGetError): - result = project.branches.get(source_branch) - # Help to debug in case the expected exception doesn't happen. - import pprint - - print("mr:", pprint.pformat(mr)) - print("mr.merged_at:", pprint.pformat(mr.merged_at)) - print("result:", pprint.pformat(result)) - - -def test_merge_request_large_commit_message( - project, merge_request, wait_for_sidekiq -) -> None: - """Test to ensure https://github.com/python-gitlab/python-gitlab/issues/1452 - is fixed. - Bug reported that very long 'merge_commit_message' in mr.merge() would - cause an error: 414 Request too large - """ - - source_branch = "large_commit_message" - mr = merge_request(source_branch=source_branch) - - merge_commit_message = "large_message\r\n" * 1_000 - assert len(merge_commit_message) > 10_000 - - mr.merge(merge_commit_message=merge_commit_message) - - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - # Wait until it is merged - mr_iid = mr.iid - for _ in range(60): - mr = project.mergerequests.get(mr_iid) - if mr.merged_at is not None: - break - time.sleep(0.5) - assert mr.merged_at is not None - time.sleep(0.5) - - # Ensure we can get the MR branch - project.branches.get(source_branch) - - -def test_merge_request_merge_ref(merge_request) -> None: - source_branch = "merge_ref_test" - mr = merge_request(source_branch=source_branch) - - response = mr.merge_ref() - assert response and "commit_id" in response - - -def test_merge_request_merge_ref_should_fail( - project, merge_request, wait_for_sidekiq -) -> None: - source_branch = "merge_ref_test2" - mr = merge_request(source_branch=source_branch) - - # Create conflict - project.files.create( - { - "file_path": f"README.{source_branch}", - "branch": project.default_branch, - "content": "Different initial content", - "commit_message": "Another commit in main branch", - } - ) - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - # Check for non-existing merge_ref for MR with conflicts - with pytest.raises(gitlab.exceptions.GitlabGetError): - response = mr.merge_ref() - assert "commit_id" not in response diff --git a/tests/functional/api/test_packages.py b/tests/functional/api/test_packages.py deleted file mode 100644 index 64b57b8..0000000 --- a/tests/functional/api/test_packages.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ce/api/packages.html -https://docs.gitlab.com/ee/user/packages/generic_packages -""" -from gitlab.v4.objects import GenericPackage - -package_name = "hello-world" -package_version = "v1.0.0" -file_name = "hello.tar.gz" -file_content = "package content" - - -def test_list_project_packages(project): - packages = project.packages.list() - assert isinstance(packages, list) - - -def test_list_group_packages(group): - packages = group.packages.list() - assert isinstance(packages, list) - - -def test_upload_generic_package(tmp_path, project): - 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) - assert package.message == "201 Created" - - -def test_download_generic_package(project): - package = project.generic_packages.download( - package_name=package_name, - package_version=package_version, - file_name=file_name, - ) - - assert isinstance(package, bytes) - assert package.decode("utf-8") == file_content - - -def test_download_generic_package_to_file(tmp_path, project): - path = tmp_path / file_name - - with open(path, "wb") as f: - project.generic_packages.download( - package_name=package_name, - package_version=package_version, - file_name=file_name, - streamed=True, - action=f.write, - ) - - with open(path, "r") as f: - assert f.read() == file_content diff --git a/tests/functional/api/test_projects.py b/tests/functional/api/test_projects.py deleted file mode 100644 index 88b274c..0000000 --- a/tests/functional/api/test_projects.py +++ /dev/null @@ -1,268 +0,0 @@ -import pytest - -import gitlab - - -def test_create_project(gl, user): - # Moved from group tests chunk in legacy tests, TODO cleanup - admin_project = gl.projects.create({"name": "admin_project"}) - assert isinstance(admin_project, gitlab.v4.objects.Project) - assert len(gl.projects.list(search="admin")) == 1 - - sudo_project = gl.projects.create({"name": "sudo_project"}, sudo=user.id) - - created = gl.projects.list() - created_gen = gl.projects.list(as_list=False) - owned = gl.projects.list(owned=True) - - assert admin_project in created and sudo_project in created - assert admin_project in owned and sudo_project not in owned - assert len(created) == len(list(created_gen)) - - admin_project.delete() - sudo_project.delete() - - -def test_project_badges(project): - badge_image = "http://example.com" - badge_link = "http://example/img.svg" - - badge = project.badges.create({"link_url": badge_link, "image_url": badge_image}) - assert len(project.badges.list()) == 1 - - badge.image_url = "http://another.example.com" - badge.save() - - badge = project.badges.get(badge.id) - assert badge.image_url == "http://another.example.com" - - badge.delete() - assert len(project.badges.list()) == 0 - - -@pytest.mark.skip(reason="Commented out in legacy test") -def test_project_boards(project): - boards = project.boards.list() - assert len(boards) - - board = boards[0] - lists = board.lists.list() - begin_size = len(lists) - last_list = lists[-1] - last_list.position = 0 - last_list.save() - last_list.delete() - lists = board.lists.list() - assert len(lists) == begin_size - 1 - - -def test_project_custom_attributes(gl, project): - attrs = project.customattributes.list() - assert len(attrs) == 0 - - attr = project.customattributes.set("key", "value1") - assert attr.key == "key" - assert attr.value == "value1" - assert len(project.customattributes.list()) == 1 - assert len(gl.projects.list(custom_attributes={"key": "value1"})) == 1 - - attr = project.customattributes.set("key", "value2") - attr = project.customattributes.get("key") - assert attr.value == "value2" - assert len(project.customattributes.list()) == 1 - - attr.delete() - assert len(project.customattributes.list()) == 0 - - -def test_project_environments(project): - project.environments.create( - {"name": "env1", "external_url": "http://fake.env/whatever"} - ) - environments = project.environments.list() - assert len(environments) == 1 - - environment = environments[0] - environment.external_url = "http://new.env/whatever" - environment.save() - - environment = project.environments.list()[0] - assert environment.external_url == "http://new.env/whatever" - - environment.stop() - environment.delete() - assert len(project.environments.list()) == 0 - - -def test_project_events(project): - events = project.events.list() - assert isinstance(events, list) - - -def test_project_file_uploads(project): - filename = "test.txt" - file_contents = "testing contents" - - uploaded_file = project.upload(filename, file_contents) - assert uploaded_file["alt"] == filename - assert uploaded_file["url"].startswith("/uploads/") - assert uploaded_file["url"].endswith("/" + filename) - assert uploaded_file["markdown"] == "[{}]({})".format( - uploaded_file["alt"], uploaded_file["url"] - ) - - -def test_project_forks(gl, project, user): - fork = project.forks.create({"namespace": user.username}) - fork_project = gl.projects.get(fork.id) - assert fork_project.forked_from_project["id"] == project.id - - forks = project.forks.list() - assert fork.id in map(lambda fork_project: fork_project.id, forks) - - -def test_project_hooks(project): - hook = project.hooks.create({"url": "http://hook.url"}) - assert len(project.hooks.list()) == 1 - - hook.note_events = True - hook.save() - - hook = project.hooks.get(hook.id) - assert hook.note_events is True - hook.delete() - - -def test_project_housekeeping(project): - project.housekeeping() - - -def test_project_labels(project): - label = project.labels.create({"name": "label", "color": "#778899"}) - labels = project.labels.list() - assert len(labels) == 1 - - label = project.labels.get("label") - assert label == labels[0] - - label.new_name = "labelupdated" - label.save() - assert label.name == "labelupdated" - - label.subscribe() - assert label.subscribed is True - - label.unsubscribe() - assert label.subscribed is False - - label.delete() - assert len(project.labels.list()) == 0 - - -def test_project_milestones(project): - milestone = project.milestones.create({"title": "milestone1"}) - assert len(project.milestones.list()) == 1 - - milestone.due_date = "2020-01-01T00:00:00Z" - milestone.save() - - milestone.state_event = "close" - milestone.save() - - milestone = project.milestones.get(milestone.id) - assert milestone.state == "closed" - assert len(milestone.issues()) == 0 - assert len(milestone.merge_requests()) == 0 - - -def test_project_pages_domains(gl, project): - domain = project.pagesdomains.create({"domain": "foo.domain.com"}) - assert len(project.pagesdomains.list()) == 1 - assert len(gl.pagesdomains.list()) == 1 - - domain = project.pagesdomains.get("foo.domain.com") - assert domain.domain == "foo.domain.com" - - domain.delete() - assert len(project.pagesdomains.list()) == 0 - - -def test_project_protected_branches(project): - p_b = project.protectedbranches.create({"name": "*-stable"}) - assert p_b.name == "*-stable" - assert len(project.protectedbranches.list()) == 1 - - p_b = project.protectedbranches.get("*-stable") - p_b.delete() - assert len(project.protectedbranches.list()) == 0 - - -def test_project_remote_mirrors(project): - mirror_url = "http://gitlab.test/root/mirror.git" - - mirror = project.remote_mirrors.create({"url": mirror_url}) - assert mirror.url == mirror_url - - mirror.enabled = True - mirror.save() - - mirror = project.remote_mirrors.list()[0] - assert isinstance(mirror, gitlab.v4.objects.ProjectRemoteMirror) - assert mirror.url == mirror_url - assert mirror.enabled is True - - -def test_project_services(project): - # Use 'update' to create a service as we don't have a 'create' method and - # to add one is somewhat complicated so it hasn't been done yet. - project.services.update("asana", api_key="foo") - - service = project.services.get("asana") - assert service.active is True - service.api_key = "whatever" - service.save() - - service = project.services.get("asana") - assert service.active is True - - service.delete() - - service = project.services.get("asana") - assert service.active is False - - -def test_project_stars(project): - project.star() - assert project.star_count == 1 - - project.unstar() - assert project.star_count == 0 - - -def test_project_tags(project, project_file): - tag = project.tags.create({"tag_name": "v1.0", "ref": "master"}) - assert len(project.tags.list()) == 1 - - tag.delete() - assert len(project.tags.list()) == 0 - - -def test_project_triggers(project): - trigger = project.triggers.create({"description": "trigger1"}) - assert len(project.triggers.list()) == 1 - trigger.delete() - - -def test_project_wiki(project): - content = "Wiki page content" - wiki = project.wikis.create({"title": "wikipage", "content": content}) - assert len(project.wikis.list()) == 1 - - wiki = project.wikis.get(wiki.slug) - assert wiki.content == content - - # update and delete seem broken - wiki.content = "new content" - wiki.save() - wiki.delete() - assert len(project.wikis.list()) == 0 diff --git a/tests/functional/api/test_releases.py b/tests/functional/api/test_releases.py deleted file mode 100644 index f409c23..0000000 --- a/tests/functional/api/test_releases.py +++ /dev/null @@ -1,63 +0,0 @@ -release_name = "Demo Release" -release_tag_name = "v1.2.3" -release_description = "release notes go here" - -link_data = {"url": "https://example.com", "name": "link_name"} - - -def test_create_project_release(project, project_file): - project.refresh() # Gets us the current default branch - release = project.releases.create( - { - "name": release_name, - "tag_name": release_tag_name, - "description": release_description, - "ref": project.default_branch, - } - ) - - assert len(project.releases.list()) == 1 - assert project.releases.get(release_tag_name) - assert release.name == release_name - assert release.tag_name == release_tag_name - assert release.description == release_description - - -def test_create_project_release_no_name(project, project_file): - unnamed_release_tag_name = "v2.3.4" - - project.refresh() # Gets us the current default branch - release = project.releases.create( - { - "tag_name": unnamed_release_tag_name, - "description": release_description, - "ref": project.default_branch, - } - ) - - assert len(project.releases.list()) >= 1 - assert project.releases.get(unnamed_release_tag_name) - assert release.tag_name == unnamed_release_tag_name - assert release.description == release_description - - -def test_update_save_project_release(project, release): - updated_description = f"{release.description} updated" - release.description = updated_description - release.save() - - release = project.releases.get(release.tag_name) - assert release.description == updated_description - - -def test_delete_project_release(project, release): - project.releases.delete(release.tag_name) - assert release not in project.releases.list() - - -def test_create_project_release_links(project, release): - release.links.create(link_data) - - release = project.releases.get(release.tag_name) - assert release.assets["links"][0]["url"] == link_data["url"] - assert release.assets["links"][0]["name"] == link_data["name"] diff --git a/tests/functional/api/test_repository.py b/tests/functional/api/test_repository.py deleted file mode 100644 index 7ba84ea..0000000 --- a/tests/functional/api/test_repository.py +++ /dev/null @@ -1,126 +0,0 @@ -import base64 -import time - -import pytest - -import gitlab - - -def test_repository_files(project): - project.files.create( - { - "file_path": "README", - "branch": "master", - "content": "Initial content", - "commit_message": "Initial commit", - } - ) - readme = project.files.get(file_path="README", ref="master") - readme.content = base64.b64encode(b"Improved README").decode() - - time.sleep(2) - readme.save(branch="master", commit_message="new commit") - readme.delete(commit_message="Removing README", branch="master") - - project.files.create( - { - "file_path": "README.rst", - "branch": "master", - "content": "Initial content", - "commit_message": "New commit", - } - ) - readme = project.files.get(file_path="README.rst", ref="master") - # The first decode() is the ProjectFile method, the second one is the bytes - # object method - assert readme.decode().decode() == "Initial content" - - blame = project.files.blame(file_path="README.rst", ref="master") - assert blame - - -def test_repository_tree(project): - tree = project.repository_tree() - assert tree - assert tree[0]["name"] == "README.rst" - - blob_id = tree[0]["id"] - blob = project.repository_raw_blob(blob_id) - assert blob.decode() == "Initial content" - - archive = project.repository_archive() - assert isinstance(archive, bytes) - - archive2 = project.repository_archive("master") - assert archive == archive2 - - snapshot = project.snapshot() - assert isinstance(snapshot, bytes) - - -def test_create_commit(project): - data = { - "branch": "master", - "commit_message": "blah blah blah", - "actions": [{"action": "create", "file_path": "blah", "content": "blah"}], - } - commit = project.commits.create(data) - - assert "@@" in project.commits.list()[0].diff()[0]["diff"] - assert isinstance(commit.refs(), list) - assert isinstance(commit.merge_requests(), list) - - -def test_create_commit_status(project): - commit = project.commits.list()[0] - size = len(commit.statuses.list()) - commit.statuses.create({"state": "success", "sha": commit.id}) - assert len(commit.statuses.list()) == size + 1 - - -def test_commit_signature(project): - commit = project.commits.list()[0] - - with pytest.raises(gitlab.GitlabGetError) as e: - commit.signature() - - assert "404 Signature Not Found" in str(e.value) - - -def test_commit_comment(project): - commit = project.commits.list()[0] - - commit.comments.create({"note": "This is a commit comment"}) - assert len(commit.comments.list()) == 1 - - -def test_commit_discussion(project): - commit = project.commits.list()[0] - count = len(commit.discussions.list()) - - discussion = commit.discussions.create({"body": "Discussion body"}) - assert len(commit.discussions.list()) == (count + 1) - - note = discussion.notes.create({"body": "first note"}) - note_from_get = discussion.notes.get(note.id) - note_from_get.body = "updated body" - note_from_get.save() - discussion = commit.discussions.get(discussion.id) - # assert discussion.attributes["notes"][-1]["body"] == "updated body" - note_from_get.delete() - discussion = commit.discussions.get(discussion.id) - # assert len(discussion.attributes["notes"]) == 1 - - -def test_revert_commit(project): - commit = project.commits.list()[0] - revert_commit = commit.revert(branch="master") - - expected_message = 'Revert "{}"\n\nThis reverts commit {}'.format( - commit.message, commit.id - ) - assert revert_commit["message"] == expected_message - - with pytest.raises(gitlab.GitlabRevertError): - # Two revert attempts should raise GitlabRevertError - commit.revert(branch="master") diff --git a/tests/functional/api/test_snippets.py b/tests/functional/api/test_snippets.py deleted file mode 100644 index 9e0f833..0000000 --- a/tests/functional/api/test_snippets.py +++ /dev/null @@ -1,74 +0,0 @@ -import gitlab - - -def test_snippets(gl): - snippets = gl.snippets.list(all=True) - assert len(snippets) == 0 - - snippet = gl.snippets.create( - {"title": "snippet1", "file_name": "snippet1.py", "content": "import gitlab"} - ) - snippet = gl.snippets.get(snippet.id) - snippet.title = "updated_title" - snippet.save() - - snippet = gl.snippets.get(snippet.id) - assert snippet.title == "updated_title" - - content = snippet.content() - assert content.decode() == "import gitlab" - assert snippet.user_agent_detail()["user_agent"] - - snippet.delete() - snippets = gl.snippets.list(all=True) - assert len(snippets) == 0 - - -def test_project_snippets(project): - project.snippets_enabled = True - project.save() - - snippet = project.snippets.create( - { - "title": "snip1", - "file_name": "foo.py", - "content": "initial content", - "visibility": gitlab.VISIBILITY_PRIVATE, - } - ) - - assert snippet.user_agent_detail()["user_agent"] - - -def test_project_snippet_discussion(project): - snippet = project.snippets.list()[0] - size = len(snippet.discussions.list()) - - discussion = snippet.discussions.create({"body": "Discussion body"}) - assert len(snippet.discussions.list()) == size + 1 - - note = discussion.notes.create({"body": "first note"}) - note_from_get = discussion.notes.get(note.id) - note_from_get.body = "updated body" - note_from_get.save() - - discussion = snippet.discussions.get(discussion.id) - assert discussion.attributes["notes"][-1]["body"] == "updated body" - - note_from_get.delete() - discussion = snippet.discussions.get(discussion.id) - assert len(discussion.attributes["notes"]) == 1 - - -def test_project_snippet_file(project): - snippet = project.snippets.list()[0] - snippet.file_name = "bar.py" - snippet.save() - - snippet = project.snippets.get(snippet.id) - assert snippet.content().decode() == "initial content" - assert snippet.file_name == "bar.py" - - size = len(project.snippets.list()) - snippet.delete() - assert len(project.snippets.list()) == (size - 1) diff --git a/tests/functional/api/test_users.py b/tests/functional/api/test_users.py deleted file mode 100644 index 1ef237c..0000000 --- a/tests/functional/api/test_users.py +++ /dev/null @@ -1,170 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/users.html -https://docs.gitlab.com/ee/api/users.html#delete-authentication-identity-from-user -""" -import pytest -import requests - - -@pytest.fixture(scope="session") -def avatar_path(test_dir): - return test_dir / "fixtures" / "avatar.png" - - -def test_create_user(gl, avatar_path): - user = gl.users.create( - { - "email": "foo@bar.com", - "username": "foo", - "name": "foo", - "password": "foo_password", - "avatar": open(avatar_path, "rb"), - } - ) - - created_user = gl.users.list(username="foo")[0] - assert created_user.username == user.username - assert created_user.email == user.email - - avatar_url = user.avatar_url.replace("gitlab.test", "localhost:8080") - uploaded_avatar = requests.get(avatar_url).content - assert uploaded_avatar == open(avatar_path, "rb").read() - - -def test_block_user(gl, user): - user.block() - users = gl.users.list(blocked=True) - assert user in users - - user.unblock() - users = gl.users.list(blocked=False) - assert user in users - - -def test_delete_user(gl, wait_for_sidekiq): - new_user = gl.users.create( - { - "email": "delete-user@test.com", - "username": "delete-user", - "name": "delete-user", - "password": "delete-user-pass", - } - ) - - new_user.delete() - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - assert new_user.id not in [user.id for user in gl.users.list()] - - -def test_user_projects_list(gl, user): - projects = user.projects.list() - assert isinstance(projects, list) - assert not projects - - -def test_user_events_list(gl, user): - events = user.events.list() - assert isinstance(events, list) - assert not events - - -def test_user_bio(gl, user): - user.bio = "This is the user bio" - user.save() - - -def test_list_multiple_users(gl, user): - second_email = f"{user.email}.2" - second_username = f"{user.username}_2" - second_user = gl.users.create( - { - "email": second_email, - "username": second_username, - "name": "Foo Bar", - "password": "foobar_password", - } - ) - assert gl.users.list(search=second_user.username)[0].id == second_user.id - - expected = [user, second_user] - actual = list(gl.users.list(search=user.username)) - - assert len(expected) == len(actual) - assert len(gl.users.list(search="asdf")) == 0 - - -def test_user_gpg_keys(gl, user, GPG_KEY): - gkey = user.gpgkeys.create({"key": GPG_KEY}) - assert len(user.gpgkeys.list()) == 1 - - # Seems broken on the gitlab side - # gkey = user.gpgkeys.get(gkey.id) - - gkey.delete() - assert len(user.gpgkeys.list()) == 0 - - -def test_user_ssh_keys(gl, user, SSH_KEY): - key = user.keys.create({"title": "testkey", "key": SSH_KEY}) - assert len(user.keys.list()) == 1 - - key.delete() - assert len(user.keys.list()) == 0 - - -def test_user_email(gl, user): - email = user.emails.create({"email": "foo2@bar.com"}) - assert len(user.emails.list()) == 1 - - email.delete() - assert len(user.emails.list()) == 0 - - -def test_user_custom_attributes(gl, user): - attrs = user.customattributes.list() - assert len(attrs) == 0 - - attr = user.customattributes.set("key", "value1") - assert len(gl.users.list(custom_attributes={"key": "value1"})) == 1 - assert attr.key == "key" - assert attr.value == "value1" - assert len(user.customattributes.list()) == 1 - - attr = user.customattributes.set("key", "value2") - attr = user.customattributes.get("key") - assert attr.value == "value2" - assert len(user.customattributes.list()) == 1 - - attr.delete() - assert len(user.customattributes.list()) == 0 - - -def test_user_impersonation_tokens(gl, user): - token = user.impersonationtokens.create( - {"name": "token1", "scopes": ["api", "read_user"]} - ) - - tokens = user.impersonationtokens.list(state="active") - assert len(tokens) == 1 - - token.delete() - tokens = user.impersonationtokens.list(state="active") - assert len(tokens) == 0 - tokens = user.impersonationtokens.list(state="inactive") - assert len(tokens) == 1 - - -def test_user_identities(gl, user): - provider = "test_provider" - - user.provider = provider - user.extern_uid = "1" - user.save() - assert provider in [item["provider"] for item in user.identities] - - user.identityproviders.delete(provider) - user = gl.users.get(user.id) - assert provider not in [item["provider"] for item in user.identities] diff --git a/tests/functional/api/test_variables.py b/tests/functional/api/test_variables.py deleted file mode 100644 index d20ebba..0000000 --- a/tests/functional/api/test_variables.py +++ /dev/null @@ -1,48 +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 -""" - - -def test_instance_variables(gl): - variable = gl.variables.create({"key": "key1", "value": "value1"}) - assert variable.value == "value1" - assert len(gl.variables.list()) == 1 - - variable.value = "new_value1" - variable.save() - variable = gl.variables.get(variable.key) - assert variable.value == "new_value1" - - variable.delete() - assert len(gl.variables.list()) == 0 - - -def test_group_variables(group): - variable = group.variables.create({"key": "key1", "value": "value1"}) - assert variable.value == "value1" - assert len(group.variables.list()) == 1 - - variable.value = "new_value1" - variable.save() - variable = group.variables.get(variable.key) - assert variable.value == "new_value1" - - variable.delete() - assert len(group.variables.list()) == 0 - - -def test_project_variables(project): - variable = project.variables.create({"key": "key1", "value": "value1"}) - assert variable.value == "value1" - assert len(project.variables.list()) == 1 - - variable.value = "new_value1" - variable.save() - variable = project.variables.get(variable.key) - assert variable.value == "new_value1" - - variable.delete() - assert len(project.variables.list()) == 0 diff --git a/tests/functional/cli/__init__.py b/tests/functional/cli/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/functional/cli/__init__.py +++ /dev/null diff --git a/tests/functional/cli/conftest.py b/tests/functional/cli/conftest.py deleted file mode 100644 index ba94dcb..0000000 --- a/tests/functional/cli/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - - -@pytest.fixture -def gitlab_cli(script_runner, gitlab_config): - """Wrapper fixture to help make test cases less verbose.""" - - def _gitlab_cli(subcommands): - """ - Return a script_runner.run method that takes a default gitlab - command, and subcommands passed as arguments inside test cases. - """ - command = ["gitlab", "--config-file", gitlab_config] - - for subcommand in subcommands: - # ensure we get strings (e.g from IDs) - command.append(str(subcommand)) - - return script_runner.run(*command) - - return _gitlab_cli diff --git a/tests/functional/cli/test_cli_artifacts.py b/tests/functional/cli/test_cli_artifacts.py deleted file mode 100644 index aab0546..0000000 --- a/tests/functional/cli/test_cli_artifacts.py +++ /dev/null @@ -1,49 +0,0 @@ -import subprocess -import textwrap -import time -from io import BytesIO -from zipfile import is_zipfile - -content = textwrap.dedent( - """\ - test-artifact: - script: echo "test" > artifact.txt - artifacts: - untracked: true - """ -) -data = { - "file_path": ".gitlab-ci.yml", - "branch": "master", - "content": content, - "commit_message": "Initial commit", -} - - -def test_cli_artifacts(capsysbinary, gitlab_config, gitlab_runner, project): - project.files.create(data) - - jobs = None - while not jobs: - jobs = project.jobs.list(scope="success") - time.sleep(0.5) - - job = project.jobs.get(jobs[0].id) - cmd = [ - "gitlab", - "--config-file", - gitlab_config, - "project-job", - "artifacts", - "--id", - str(job.id), - "--project-id", - str(project.id), - ] - - with capsysbinary.disabled(): - artifacts = subprocess.check_output(cmd) - assert isinstance(artifacts, bytes) - - artifacts_zip = BytesIO(artifacts) - assert is_zipfile(artifacts_zip) diff --git a/tests/functional/cli/test_cli_packages.py b/tests/functional/cli/test_cli_packages.py deleted file mode 100644 index d7cdd18..0000000 --- a/tests/functional/cli/test_cli_packages.py +++ /dev/null @@ -1,60 +0,0 @@ -package_name = "hello-world" -package_version = "v1.0.0" -file_name = "hello.tar.gz" -file_content = "package content" - - -def test_list_project_packages(gitlab_cli, project): - cmd = ["project-package", "list", "--project-id", project.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_group_packages(gitlab_cli, group): - cmd = ["group-package", "list", "--group-id", group.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_upload_generic_package(tmp_path, gitlab_cli, project): - path = tmp_path / file_name - path.write_text(file_content) - - cmd = [ - "-v", - "generic-package", - "upload", - "--project-id", - project.id, - "--package-name", - package_name, - "--path", - path, - "--package-version", - package_version, - "--file-name", - file_name, - ] - ret = gitlab_cli(cmd) - - assert "201 Created" in ret.stdout - - -def test_download_generic_package(gitlab_cli, project): - cmd = [ - "generic-package", - "download", - "--project-id", - project.id, - "--package-name", - package_name, - "--package-version", - package_version, - "--file-name", - file_name, - ] - ret = gitlab_cli(cmd) - - assert ret.stdout == file_content diff --git a/tests/functional/cli/test_cli_v4.py b/tests/functional/cli/test_cli_v4.py deleted file mode 100644 index a63c1b1..0000000 --- a/tests/functional/cli/test_cli_v4.py +++ /dev/null @@ -1,715 +0,0 @@ -import os -import time - - -def test_create_project(gitlab_cli): - name = "test-project1" - - cmd = ["project", "create", "--name", name] - ret = gitlab_cli(cmd) - - assert ret.success - assert name in ret.stdout - - -def test_update_project(gitlab_cli, project): - description = "My New Description" - - cmd = ["project", "update", "--id", project.id, "--description", description] - ret = gitlab_cli(cmd) - - assert ret.success - assert description in ret.stdout - - -def test_create_group(gitlab_cli): - name = "test-group1" - path = "group1" - - cmd = ["group", "create", "--name", name, "--path", path] - ret = gitlab_cli(cmd) - - assert ret.success - assert name in ret.stdout - assert path in ret.stdout - - -def test_update_group(gitlab_cli, gl, group): - description = "My New Description" - - cmd = ["group", "update", "--id", group.id, "--description", description] - ret = gitlab_cli(cmd) - - assert ret.success - - group = gl.groups.get(group.id) - assert group.description == description - - -def test_create_user(gitlab_cli, gl): - email = "fake@email.com" - username = "user1" - name = "User One" - password = "fakepassword" - - cmd = [ - "user", - "create", - "--email", - email, - "--username", - username, - "--name", - name, - "--password", - password, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - user = gl.users.list(username=username)[0] - - assert user.email == email - assert user.username == username - assert user.name == name - - -def test_get_user_by_id(gitlab_cli, user): - cmd = ["user", "get", "--id", user.id] - ret = gitlab_cli(cmd) - - assert ret.success - assert str(user.id) in ret.stdout - - -def test_list_users_verbose_output(gitlab_cli): - cmd = ["-v", "user", "list"] - ret = gitlab_cli(cmd) - - assert ret.success - assert "avatar-url" in ret.stdout - - -def test_cli_args_not_in_output(gitlab_cli): - cmd = ["-v", "user", "list"] - ret = gitlab_cli(cmd) - - assert "config-file" not in ret.stdout - - -def test_add_member_to_project(gitlab_cli, project, user): - access_level = "40" - - cmd = [ - "project-member", - "create", - "--project-id", - project.id, - "--user-id", - user.id, - "--access-level", - access_level, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_user_memberships(gitlab_cli, user): - cmd = ["user-membership", "list", "--user-id", user.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_project_create_file(gitlab_cli, project): - file_path = "README" - branch = "master" - content = "CONTENT" - commit_message = "Initial commit" - - cmd = [ - "project-file", - "create", - "--project-id", - project.id, - "--file-path", - file_path, - "--branch", - branch, - "--content", - content, - "--commit-message", - commit_message, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_create_project_issue(gitlab_cli, project): - title = "my issue" - description = "my issue description" - - cmd = [ - "project-issue", - "create", - "--project-id", - project.id, - "--title", - title, - "--description", - description, - ] - ret = gitlab_cli(cmd) - - assert ret.success - assert title in ret.stdout - - -def test_create_issue_note(gitlab_cli, issue): - body = "body" - - cmd = [ - "project-issue-note", - "create", - "--project-id", - issue.project_id, - "--issue-iid", - issue.iid, - "--body", - body, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_create_branch(gitlab_cli, project): - branch = "branch1" - - cmd = [ - "project-branch", - "create", - "--project-id", - project.id, - "--branch", - branch, - "--ref", - "master", - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_create_merge_request(gitlab_cli, project): - branch = "branch1" - - cmd = [ - "project-merge-request", - "create", - "--project-id", - project.id, - "--source-branch", - branch, - "--target-branch", - "master", - "--title", - "Update README", - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_accept_request_merge(gitlab_cli, project): - # MR needs at least 1 commit before we can merge - mr = project.mergerequests.list()[0] - file_data = { - "branch": mr.source_branch, - "file_path": "README2", - "content": "Content", - "commit_message": "Pre-merge commit", - } - project.files.create(file_data) - time.sleep(2) - - cmd = [ - "project-merge-request", - "merge", - "--project-id", - project.id, - "--iid", - mr.iid, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_revert_commit(gitlab_cli, project): - commit = project.commits.list()[0] - - cmd = [ - "project-commit", - "revert", - "--project-id", - project.id, - "--id", - commit.id, - "--branch", - "master", - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_get_commit_signature_not_found(gitlab_cli, project): - commit = project.commits.list()[0] - - cmd = ["project-commit", "signature", "--project-id", project.id, "--id", commit.id] - ret = gitlab_cli(cmd) - - assert not ret.success - assert "404 Signature Not Found" in ret.stderr - - -def test_create_project_label(gitlab_cli, project): - name = "prjlabel1" - description = "prjlabel1 description" - color = "#112233" - - cmd = [ - "-v", - "project-label", - "create", - "--project-id", - project.id, - "--name", - name, - "--description", - description, - "--color", - color, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_project_labels(gitlab_cli, project): - cmd = ["-v", "project-label", "list", "--project-id", project.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_update_project_label(gitlab_cli, label): - new_label = "prjlabel2" - new_description = "prjlabel2 description" - new_color = "#332211" - - cmd = [ - "-v", - "project-label", - "update", - "--project-id", - label.project_id, - "--name", - label.name, - "--new-name", - new_label, - "--description", - new_description, - "--color", - new_color, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_delete_project_label(gitlab_cli, label): - # TODO: due to update above, we'd need a function-scope label fixture - label_name = "prjlabel2" - - cmd = [ - "-v", - "project-label", - "delete", - "--project-id", - label.project_id, - "--name", - label_name, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_create_group_label(gitlab_cli, group): - name = "grouplabel1" - description = "grouplabel1 description" - color = "#112233" - - cmd = [ - "-v", - "group-label", - "create", - "--group-id", - group.id, - "--name", - name, - "--description", - description, - "--color", - color, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_group_labels(gitlab_cli, group): - cmd = ["-v", "group-label", "list", "--group-id", group.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_update_group_label(gitlab_cli, group_label): - new_label = "grouplabel2" - new_description = "grouplabel2 description" - new_color = "#332211" - - cmd = [ - "-v", - "group-label", - "update", - "--group-id", - group_label.group_id, - "--name", - group_label.name, - "--new-name", - new_label, - "--description", - new_description, - "--color", - new_color, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_delete_group_label(gitlab_cli, group_label): - # TODO: due to update above, we'd need a function-scope label fixture - new_label = "grouplabel2" - - cmd = [ - "-v", - "group-label", - "delete", - "--group-id", - group_label.group_id, - "--name", - new_label, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_create_project_variable(gitlab_cli, project): - key = "junk" - value = "car" - - cmd = [ - "-v", - "project-variable", - "create", - "--project-id", - project.id, - "--key", - key, - "--value", - value, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_get_project_variable(gitlab_cli, variable): - cmd = [ - "-v", - "project-variable", - "get", - "--project-id", - variable.project_id, - "--key", - variable.key, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_update_project_variable(gitlab_cli, variable): - new_value = "bus" - - cmd = [ - "-v", - "project-variable", - "update", - "--project-id", - variable.project_id, - "--key", - variable.key, - "--value", - new_value, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_project_variables(gitlab_cli, project): - cmd = ["-v", "project-variable", "list", "--project-id", project.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_delete_project_variable(gitlab_cli, variable): - cmd = [ - "-v", - "project-variable", - "delete", - "--project-id", - variable.project_id, - "--key", - variable.key, - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_delete_branch(gitlab_cli, project): - # TODO: branch fixture - branch = "branch1" - - cmd = ["project-branch", "delete", "--project-id", project.id, "--name", branch] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_project_upload_file(gitlab_cli, project): - cmd = [ - "project", - "upload", - "--id", - project.id, - "--filename", - __file__, - "--filepath", - os.path.realpath(__file__), - ] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_get_application_settings(gitlab_cli): - cmd = ["application-settings", "get"] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_update_application_settings(gitlab_cli): - cmd = ["application-settings", "update", "--signup-enabled", "false"] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_create_project_with_values_from_file(gitlab_cli, tmpdir): - name = "gitlab-project-from-file" - description = "Multiline\n\nData\n" - from_file = tmpdir.join(name) - from_file.write(description) - from_file_path = f"@{str(from_file)}" - - cmd = [ - "-v", - "project", - "create", - "--name", - name, - "--description", - from_file_path, - ] - ret = gitlab_cli(cmd) - - assert ret.success - assert description in ret.stdout - - -def test_create_project_deploy_token(gitlab_cli, project): - name = "project-token" - username = "root" - expires_at = "2021-09-09" - scopes = "read_registry" - - cmd = [ - "-v", - "project-deploy-token", - "create", - "--project-id", - project.id, - "--name", - name, - "--username", - username, - "--expires-at", - expires_at, - "--scopes", - scopes, - ] - ret = gitlab_cli(cmd) - - assert ret.success - assert name in ret.stdout - assert username in ret.stdout - assert expires_at in ret.stdout - assert scopes in ret.stdout - - -def test_list_all_deploy_tokens(gitlab_cli, deploy_token): - cmd = ["-v", "deploy-token", "list"] - ret = gitlab_cli(cmd) - - assert ret.success - assert deploy_token.name in ret.stdout - assert str(deploy_token.id) in ret.stdout - assert deploy_token.username in ret.stdout - assert deploy_token.expires_at in ret.stdout - assert deploy_token.scopes[0] in ret.stdout - - -def test_list_project_deploy_tokens(gitlab_cli, deploy_token): - cmd = [ - "-v", - "project-deploy-token", - "list", - "--project-id", - deploy_token.project_id, - ] - ret = gitlab_cli(cmd) - - assert ret.success - assert deploy_token.name in ret.stdout - assert str(deploy_token.id) in ret.stdout - assert deploy_token.username in ret.stdout - assert deploy_token.expires_at in ret.stdout - assert deploy_token.scopes[0] in ret.stdout - - -def test_delete_project_deploy_token(gitlab_cli, deploy_token): - cmd = [ - "-v", - "project-deploy-token", - "delete", - "--project-id", - deploy_token.project_id, - "--id", - deploy_token.id, - ] - ret = gitlab_cli(cmd) - - assert ret.success - # TODO assert not in list - - -def test_create_group_deploy_token(gitlab_cli, group): - name = "group-token" - username = "root" - expires_at = "2021-09-09" - scopes = "read_registry" - - cmd = [ - "-v", - "group-deploy-token", - "create", - "--group-id", - group.id, - "--name", - name, - "--username", - username, - "--expires-at", - expires_at, - "--scopes", - scopes, - ] - ret = gitlab_cli(cmd) - - assert ret.success - assert name in ret.stdout - assert username in ret.stdout - assert expires_at in ret.stdout - assert scopes in ret.stdout - - -def test_list_group_deploy_tokens(gitlab_cli, group_deploy_token): - cmd = [ - "-v", - "group-deploy-token", - "list", - "--group-id", - group_deploy_token.group_id, - ] - ret = gitlab_cli(cmd) - - assert ret.success - assert group_deploy_token.name in ret.stdout - assert str(group_deploy_token.id) in ret.stdout - assert group_deploy_token.username in ret.stdout - assert group_deploy_token.expires_at in ret.stdout - assert group_deploy_token.scopes[0] in ret.stdout - - -def test_delete_group_deploy_token(gitlab_cli, group_deploy_token): - cmd = [ - "-v", - "group-deploy-token", - "delete", - "--group-id", - group_deploy_token.group_id, - "--id", - group_deploy_token.id, - ] - ret = gitlab_cli(cmd) - - assert ret.success - # TODO assert not in list - - -def test_delete_project(gitlab_cli, project): - cmd = ["project", "delete", "--id", project.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_delete_group(gitlab_cli, group): - cmd = ["group", "delete", "--id", group.id] - ret = gitlab_cli(cmd) - - assert ret.success diff --git a/tests/functional/cli/test_cli_variables.py b/tests/functional/cli/test_cli_variables.py deleted file mode 100644 index 9b1b16d..0000000 --- a/tests/functional/cli/test_cli_variables.py +++ /dev/null @@ -1,19 +0,0 @@ -def test_list_instance_variables(gitlab_cli, gl): - cmd = ["variable", "list"] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_group_variables(gitlab_cli, group): - cmd = ["group-variable", "list", "--group-id", group.id] - ret = gitlab_cli(cmd) - - assert ret.success - - -def test_list_project_variables(gitlab_cli, project): - cmd = ["project-variable", "list", "--project-id", project.id] - ret = gitlab_cli(cmd) - - assert ret.success diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py deleted file mode 100644 index 23aa583..0000000 --- a/tests/functional/conftest.py +++ /dev/null @@ -1,489 +0,0 @@ -import tempfile -import time -import uuid -from pathlib import Path -from subprocess import check_output - -import pytest - -import gitlab - - -def reset_gitlab(gl): - # previously tools/reset_gitlab.py - for project in gl.projects.list(): - for deploy_token in project.deploytokens.list(): - deploy_token.delete() - project.delete() - for group in gl.groups.list(): - for deploy_token in group.deploytokens.list(): - deploy_token.delete() - group.delete() - for variable in gl.variables.list(): - variable.delete() - for user in gl.users.list(): - if user.username != "root": - user.delete(hard_delete=True) - - -def set_token(container, rootdir): - set_token_rb = rootdir / "fixtures" / "set_token.rb" - - with open(set_token_rb, "r") as f: - set_token_command = f.read().strip() - - rails_command = [ - "docker", - "exec", - container, - "gitlab-rails", - "runner", - set_token_command, - ] - output = check_output(rails_command).decode().strip() - - return output - - -def pytest_report_collectionfinish(config, startdir, items): - return [ - "", - "Starting GitLab container.", - "Waiting for GitLab to reconfigure.", - "This may take a few minutes.", - ] - - -def pytest_addoption(parser): - parser.addoption( - "--keep-containers", - action="store_true", - help="Keep containers running after testing", - ) - - -@pytest.fixture(scope="session") -def temp_dir(): - return Path(tempfile.gettempdir()) - - -@pytest.fixture(scope="session") -def test_dir(pytestconfig): - return pytestconfig.rootdir / "tests" / "functional" - - -@pytest.fixture(scope="session") -def docker_compose_file(test_dir): - return test_dir / "fixtures" / "docker-compose.yml" - - -@pytest.fixture(scope="session") -def docker_compose_project_name(): - """Set a consistent project name to enable optional reuse of containers.""" - return "pytest-python-gitlab" - - -@pytest.fixture(scope="session") -def docker_cleanup(request): - """Conditionally keep containers around by overriding the cleanup command.""" - if request.config.getoption("--keep-containers"): - # Print version and exit. - return "-v" - return "down -v" - - -@pytest.fixture(scope="session") -def check_is_alive(): - """ - Return a healthcheck function fixture for the GitLab container spinup. - """ - - def _check(container): - logs = ["docker", "logs", container] - return "gitlab Reconfigured!" in check_output(logs).decode() - - return _check - - -@pytest.fixture -def wait_for_sidekiq(gl): - """ - Return a helper function to wait until there are no busy sidekiq processes. - - Use this with asserts for slow tasks (group/project/user creation/deletion). - """ - - def _wait(timeout=30, step=0.5): - for _ in range(timeout): - time.sleep(step) - busy = False - processes = gl.sidekiq.process_metrics()["processes"] - for process in processes: - if process["busy"]: - busy = True - if not busy: - return True - return False - - return _wait - - -@pytest.fixture(scope="session") -def gitlab_config(check_is_alive, docker_ip, docker_services, temp_dir, test_dir): - config_file = temp_dir / "python-gitlab.cfg" - port = docker_services.port_for("gitlab", 80) - - docker_services.wait_until_responsive( - timeout=200, pause=5, check=lambda: check_is_alive("gitlab-test") - ) - - token = set_token("gitlab-test", rootdir=test_dir) - - config = f"""[global] -default = local -timeout = 60 - -[local] -url = http://{docker_ip}:{port} -private_token = {token} -api_version = 4""" - - with open(config_file, "w") as f: - f.write(config) - - return config_file - - -@pytest.fixture(scope="session") -def gl(gitlab_config): - """Helper instance to make fixtures and asserts directly via the API.""" - - instance = gitlab.Gitlab.from_config("local", [gitlab_config]) - reset_gitlab(instance) - - return instance - - -@pytest.fixture(scope="session") -def gitlab_runner(gl): - container = "gitlab-runner-test" - runner_name = "python-gitlab-runner" - token = "registration-token" - url = "http://gitlab" - - docker_exec = ["docker", "exec", container, "gitlab-runner"] - register = [ - "register", - "--run-untagged", - "--non-interactive", - "--registration-token", - token, - "--name", - runner_name, - "--url", - url, - "--clone-url", - url, - "--executor", - "shell", - ] - unregister = ["unregister", "--name", runner_name] - - yield check_output(docker_exec + register).decode() - - check_output(docker_exec + unregister).decode() - - -@pytest.fixture(scope="module") -def group(gl): - """Group fixture for group API resource tests.""" - _id = uuid.uuid4().hex - data = { - "name": f"test-group-{_id}", - "path": f"group-{_id}", - } - group = gl.groups.create(data) - - yield group - - try: - group.delete() - except gitlab.exceptions.GitlabDeleteError as e: - print(f"Group already deleted: {e}") - - -@pytest.fixture(scope="module") -def project(gl): - """Project fixture for project API resource tests.""" - _id = uuid.uuid4().hex - name = f"test-project-{_id}" - - project = gl.projects.create(name=name) - - yield project - - try: - project.delete() - except gitlab.exceptions.GitlabDeleteError as e: - print(f"Project already deleted: {e}") - - -@pytest.fixture(scope="function") -def merge_request(project, wait_for_sidekiq): - """Fixture used to create a merge_request. - - It will create a branch, add a commit to the branch, and then create a - merge request against project.default_branch. The MR will be returned. - - When finished any created merge requests and branches will be deleted. - - NOTE: No attempt is made to restore project.default_branch to its previous - state. So if the merge request is merged then its content will be in the - project.default_branch branch. - """ - - to_delete = [] - - def _merge_request(*, source_branch: str): - # Wait for processes to be done before we start... - # NOTE(jlvillal): Sometimes the CI would give a "500 Internal Server - # Error". Hoping that waiting until all other processes are done will - # help with that. - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - project.refresh() # Gets us the current default branch - project.branches.create( - {"branch": source_branch, "ref": project.default_branch} - ) - # NOTE(jlvillal): Must create a commit in the new branch before we can - # create an MR that will work. - project.files.create( - { - "file_path": f"README.{source_branch}", - "branch": source_branch, - "content": "Initial content", - "commit_message": "New commit in new branch", - } - ) - mr = project.mergerequests.create( - { - "source_branch": source_branch, - "target_branch": project.default_branch, - "title": "Should remove source branch", - "remove_source_branch": True, - } - ) - result = wait_for_sidekiq(timeout=60) - assert result is True, "sidekiq process should have terminated but did not" - - mr_iid = mr.iid - for _ in range(60): - mr = project.mergerequests.get(mr_iid) - if mr.merge_status != "checking": - break - time.sleep(0.5) - assert mr.merge_status != "checking" - - to_delete.append((mr.iid, source_branch)) - return mr - - yield _merge_request - - for mr_iid, source_branch in to_delete: - project.mergerequests.delete(mr_iid) - try: - project.branches.delete(source_branch) - except gitlab.exceptions.GitlabDeleteError: - # Ignore if branch was already deleted - pass - - -@pytest.fixture(scope="module") -def project_file(project): - """File fixture for tests requiring a project with files and branches.""" - project_file = project.files.create( - { - "file_path": "README", - "branch": "master", - "content": "Initial content", - "commit_message": "Initial commit", - } - ) - - return project_file - - -@pytest.fixture(scope="function") -def release(project, project_file): - _id = uuid.uuid4().hex - name = f"test-release-{_id}" - - project.refresh() # Gets us the current default branch - release = project.releases.create( - { - "name": name, - "tag_name": _id, - "description": "description", - "ref": project.default_branch, - } - ) - - return release - - -@pytest.fixture(scope="module") -def user(gl): - """User fixture for user API resource tests.""" - _id = uuid.uuid4().hex - email = f"user{_id}@email.com" - username = f"user{_id}" - name = f"User {_id}" - password = "fakepassword" - - user = gl.users.create(email=email, username=username, name=name, password=password) - - yield user - - try: - user.delete() - except gitlab.exceptions.GitlabDeleteError as e: - print(f"User already deleted: {e}") - - -@pytest.fixture(scope="module") -def issue(project): - """Issue fixture for issue API resource tests.""" - _id = uuid.uuid4().hex - data = {"title": f"Issue {_id}", "description": f"Issue {_id} description"} - - return project.issues.create(data) - - -@pytest.fixture(scope="module") -def milestone(project): - _id = uuid.uuid4().hex - data = {"title": f"milestone{_id}"} - - return project.milestones.create(data) - - -@pytest.fixture(scope="module") -def label(project): - """Label fixture for project label API resource tests.""" - _id = uuid.uuid4().hex - data = { - "name": f"prjlabel{_id}", - "description": f"prjlabel1 {_id} description", - "color": "#112233", - } - - return project.labels.create(data) - - -@pytest.fixture(scope="module") -def group_label(group): - """Label fixture for group label API resource tests.""" - _id = uuid.uuid4().hex - data = { - "name": f"grplabel{_id}", - "description": f"grplabel1 {_id} description", - "color": "#112233", - } - - return group.labels.create(data) - - -@pytest.fixture(scope="module") -def variable(project): - """Variable fixture for project variable API resource tests.""" - _id = uuid.uuid4().hex - data = {"key": f"var{_id}", "value": f"Variable {_id}"} - - return project.variables.create(data) - - -@pytest.fixture(scope="module") -def deploy_token(project): - """Deploy token fixture for project deploy token API resource tests.""" - _id = uuid.uuid4().hex - data = { - "name": f"token-{_id}", - "username": "root", - "expires_at": "2021-09-09", - "scopes": "read_registry", - } - - return project.deploytokens.create(data) - - -@pytest.fixture(scope="module") -def group_deploy_token(group): - """Deploy token fixture for group deploy token API resource tests.""" - _id = uuid.uuid4().hex - data = { - "name": f"group-token-{_id}", - "username": "root", - "expires_at": "2021-09-09", - "scopes": "read_registry", - } - - return group.deploytokens.create(data) - - -@pytest.fixture(scope="session") -def GPG_KEY(): - return """-----BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFn5mzYBCADH6SDVPAp1zh/hxmTi0QplkOfExBACpuY6OhzNdIg+8/528b3g -Y5YFR6T/HLv/PmeHskUj21end1C0PNG2T9dTx+2Vlh9ISsSG1kyF9T5fvMR3bE0x -Dl6S489CXZrjPTS9SHk1kF+7dwjUxLJyxF9hPiSihFefDFu3NeOtG/u8vbC1mewQ -ZyAYue+mqtqcCIFFoBz7wHKMWjIVSJSyTkXExu4OzpVvy3l2EikbvavI3qNz84b+ -Mgkv/kiBlNoCy3CVuPk99RYKZ3lX1vVtqQ0OgNGQvb4DjcpyjmbKyibuZwhDjIOh -au6d1OyEbayTntd+dQ4j9EMSnEvm/0MJ4eXPABEBAAG0G0dpdGxhYlRlc3QxIDxm -YWtlQGZha2UudGxkPokBNwQTAQgAIQUCWfmbNgIbAwULCQgHAgYVCAkKCwIEFgID -AQIeAQIXgAAKCRBgxELHf8f3hF3yB/wNJlWPKY65UsB4Lo0hs1OxdxCDqXogSi0u -6crDEIiyOte62pNZKzWy8TJcGZvznRTZ7t8hXgKFLz3PRMcl+vAiRC6quIDUj+2V -eYfwaItd1lUfzvdCaC7Venf4TQ74f5vvNg/zoGwE6eRoSbjlLv9nqsxeA0rUBUQL -LYikWhVMP3TrlfgfduYvh6mfgh57BDLJ9kJVpyfxxx9YLKZbaas9sPa6LgBtR555 -JziUxHmbEv8XCsUU8uoFeP1pImbNBplqE3wzJwzOMSmmch7iZzrAwfN7N2j3Wj0H -B5kQddJ9dmB4BbU0IXGhWczvdpxboI2wdY8a1JypxOdePoph/43iuQENBFn5mzYB -CADnTPY0Zf3d9zLjBNgIb3yDl94uOcKCq0twNmyjMhHzGqw+UMe9BScy34GL94Al -xFRQoaL+7P8hGsnsNku29A/VDZivcI+uxTx4WQ7OLcn7V0bnHV4d76iky2ufbUt/ -GofthjDs1SonePO2N09sS4V4uK0d5N4BfCzzXgvg8etCLxNmC9BGt7AaKUUzKBO4 -2QvNNaC2C/8XEnOgNWYvR36ylAXAmo0sGFXUsBCTiq1fugS9pwtaS2JmaVpZZ3YT -pMZlS0+SjC5BZYFqSmKCsA58oBRzCxQz57nR4h5VEflgD+Hy0HdW0UHETwz83E6/ -U0LL6YyvhwFr6KPq5GxinSvfABEBAAGJAR8EGAEIAAkFAln5mzYCGwwACgkQYMRC -x3/H94SJgwgAlKQb10/xcL/epdDkR7vbiei7huGLBpRDb/L5fM8B5W77Qi8Xmuqj -cCu1j99ZCA5hs/vwVn8j8iLSBGMC5gxcuaar/wtmiaEvT9fO/h6q4opG7NcuiJ8H -wRj8ccJmRssNqDD913PLz7T40Ts62blhrEAlJozGVG/q7T3RAZcskOUHKeHfc2RI -YzGsC/I9d7k6uxAv1L9Nm5F2HaAQDzhkdd16nKkGaPGR35cT1JLInkfl5cdm7ldN -nxs4TLO3kZjUTgWKdhpgRNF5hwaz51ZjpebaRf/ZqRuNyX4lIRolDxzOn/+O1o8L -qG2ZdhHHmSK2LaQLFiSprUkikStNU9BqSQ== -=5OGa ------END PGP PUBLIC KEY BLOCK-----""" - - -@pytest.fixture(scope="session") -def SSH_KEY(): - return ( - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZAjAX8vTiHD7Yi3/EzuVaDChtih" - "79HyJZ6H9dEqxFfmGA1YnncE0xujQ64TCebhkYJKzmTJCImSVkOu9C4hZgsw6eE76n" - "+Cg3VwEeDUFy+GXlEJWlHaEyc3HWioxgOALbUp3rOezNh+d8BDwwqvENGoePEBsz5l" - "a6WP5lTi/HJIjAl6Hu+zHgdj1XVExeH+S52EwpZf/ylTJub0Bl5gHwf/siVE48mLMI" - "sqrukXTZ6Zg+8EHAIvIQwJ1dKcXe8P5IoLT7VKrbkgAnolS0I8J+uH7KtErZJb5oZh" - "S4OEwsNpaXMAr+6/wWSpircV2/e7sFLlhlKBC4Iq1MpqlZ7G3p foo@bar" - ) - - -@pytest.fixture(scope="session") -def DEPLOY_KEY(): - return ( - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFdRyjJQh+1niBpXqE2I8dzjG" - "MXFHlRjX9yk/UfOn075IdaockdU58sw2Ai1XIWFpZpfJkW7z+P47ZNSqm1gzeXI" - "rtKa9ZUp8A7SZe8vH4XVn7kh7bwWCUirqtn8El9XdqfkzOs/+FuViriUWoJVpA6" - "WZsDNaqINFKIA5fj/q8XQw+BcS92L09QJg9oVUuH0VVwNYbU2M2IRmSpybgC/gu" - "uWTrnCDMmLItksATifLvRZwgdI8dr+q6tbxbZknNcgEPrI2jT0hYN9ZcjNeWuyv" - "rke9IepE7SPBT41C+YtUX4dfDZDmczM1cE0YL/krdUCfuZHMa4ZS2YyNd6slufc" - "vn bar@foo" - ) diff --git a/tests/functional/ee-test.py b/tests/functional/ee-test.py deleted file mode 100755 index 3a99951..0000000 --- a/tests/functional/ee-test.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python - -import gitlab - -P1 = "root/project1" -P2 = "root/project2" -MR_P1 = 1 -I_P1 = 1 -I_P2 = 1 -EPIC_ISSUES = [4, 5] -G1 = "group1" -LDAP_CN = "app1" -LDAP_PROVIDER = "ldapmain" - - -def start_log(message): - print("Testing %s... " % message, end="") - - -def end_log(): - print("OK") - - -gl = gitlab.Gitlab.from_config("ee") -project1 = gl.projects.get(P1) -project2 = gl.projects.get(P2) -issue_p1 = project1.issues.get(I_P1) -issue_p2 = project2.issues.get(I_P2) -group1 = gl.groups.get(G1) -mr = project1.mergerequests.get(1) - -start_log("MR approvals") -approval = project1.approvals.get() -v = approval.reset_approvals_on_push -approval.reset_approvals_on_push = not v -approval.save() -approval = project1.approvals.get() -assert v != approval.reset_approvals_on_push -project1.approvals.set_approvers(1, [1], []) -approval = project1.approvals.get() -assert approval.approvers[0]["user"]["id"] == 1 - -approval = mr.approvals.get() -approval.approvals_required = 2 -approval.save() -approval = mr.approvals.get() -assert approval.approvals_required == 2 -approval.approvals_required = 3 -approval.save() -approval = mr.approvals.get() -assert approval.approvals_required == 3 -mr.approvals.set_approvers(1, [1], []) -approval = mr.approvals.get() -assert approval.approvers[0]["user"]["id"] == 1 - -ars = project1.approvalrules.list(all=True) -assert len(ars) == 0 -project1.approvalrules.create( - {"name": "approval-rule", "approvals_required": 1, "group_ids": [group1.id]} -) -ars = project1.approvalrules.list(all=True) -assert len(ars) == 1 -assert ars[0].approvals_required == 2 -ars[0].save() -ars = project1.approvalrules.list(all=True) -assert len(ars) == 1 -assert ars[0].approvals_required == 2 -ars[0].delete() -ars = project1.approvalrules.list(all=True) -assert len(ars) == 0 -end_log() - -start_log("geo nodes") -# very basic tests because we only have 1 node... -nodes = gl.geonodes.list() -status = gl.geonodes.status() -end_log() - -start_log("issue links") -# bit of cleanup just in case -for link in issue_p1.links.list(): - issue_p1.links.delete(link.issue_link_id) - -src, dst = issue_p1.links.create({"target_project_id": P2, "target_issue_iid": I_P2}) -links = issue_p1.links.list() -link_id = links[0].issue_link_id -issue_p1.links.delete(link_id) -end_log() - -start_log("LDAP links") -# bit of cleanup just in case -if hasattr(group1, "ldap_group_links"): - for link in group1.ldap_group_links: - group1.delete_ldap_group_link(link["cn"], link["provider"]) -assert gl.ldapgroups.list() -group1.add_ldap_group_link(LDAP_CN, 30, LDAP_PROVIDER) -group1.ldap_sync() -group1.delete_ldap_group_link(LDAP_CN) -end_log() - -start_log("boards") -# bit of cleanup just in case -for board in project1.boards.list(): - if board.name == "testboard": - board.delete() -board = project1.boards.create({"name": "testboard"}) -board = project1.boards.get(board.id) -project1.boards.delete(board.id) - -for board in group1.boards.list(): - if board.name == "testboard": - board.delete() -board = group1.boards.create({"name": "testboard"}) -board = group1.boards.get(board.id) -group1.boards.delete(board.id) -end_log() - -start_log("push rules") -pr = project1.pushrules.get() -if pr: - pr.delete() -pr = project1.pushrules.create({"deny_delete_tag": True}) -pr.deny_delete_tag = False -pr.save() -pr = project1.pushrules.get() -assert pr is not None -assert pr.deny_delete_tag is False -pr.delete() -end_log() - -start_log("license") -license = gl.get_license() -assert "user_limit" in license -try: - gl.set_license("dummykey") -except Exception as e: - assert "The license key is invalid." in e.error_message -end_log() - -start_log("epics") -epic = group1.epics.create({"title": "Test epic"}) -epic.title = "Fixed title" -epic.labels = ["label1", "label2"] -epic.save() -epic = group1.epics.get(epic.iid) -assert epic.title == "Fixed title" -assert len(group1.epics.list()) - -# issues -assert not epic.issues.list() -for i in EPIC_ISSUES: - epic.issues.create({"issue_id": i}) -assert len(EPIC_ISSUES) == len(epic.issues.list()) -for ei in epic.issues.list(): - ei.delete() - -epic.delete() -end_log() diff --git a/tests/functional/fixtures/.env b/tests/functional/fixtures/.env deleted file mode 100644 index 374f7ac..0000000 --- a/tests/functional/fixtures/.env +++ /dev/null @@ -1,2 +0,0 @@ -GITLAB_IMAGE=gitlab/gitlab-ce -GITLAB_TAG=14.3.2-ce.0 diff --git a/tests/functional/fixtures/avatar.png b/tests/functional/fixtures/avatar.png Binary files differdeleted file mode 100644 index a3a767c..0000000 --- a/tests/functional/fixtures/avatar.png +++ /dev/null diff --git a/tests/functional/fixtures/docker-compose.yml b/tests/functional/fixtures/docker-compose.yml deleted file mode 100644 index 134f266..0000000 --- a/tests/functional/fixtures/docker-compose.yml +++ /dev/null @@ -1,46 +0,0 @@ -version: '3' - -networks: - gitlab-network: - name: gitlab-network - -services: - gitlab: - image: '${GITLAB_IMAGE}:${GITLAB_TAG}' - container_name: 'gitlab-test' - hostname: 'gitlab.test' - privileged: true # Just in case https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/1350 - environment: - GITLAB_ROOT_PASSWORD: 5iveL!fe - GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN: registration-token - GITLAB_OMNIBUS_CONFIG: | - external_url 'http://gitlab.test' - registry['enable'] = false - nginx['redirect_http_to_https'] = false - nginx['listen_port'] = 80 - nginx['listen_https'] = false - pages_external_url 'http://pages.gitlab.lxd' - gitlab_pages['enable'] = true - gitlab_pages['inplace_chroot'] = true - prometheus['enable'] = false - alertmanager['enable'] = false - node_exporter['enable'] = false - redis_exporter['enable'] = false - postgres_exporter['enable'] = false - pgbouncer_exporter['enable'] = false - gitlab_exporter['enable'] = false - grafana['enable'] = false - letsencrypt['enable'] = false - ports: - - '8080:80' - - '2222:22' - networks: - - gitlab-network - - gitlab-runner: - image: gitlab/gitlab-runner:latest - container_name: 'gitlab-runner-test' - depends_on: - - gitlab - networks: - - gitlab-network diff --git a/tests/functional/fixtures/set_token.rb b/tests/functional/fixtures/set_token.rb deleted file mode 100644 index 503588b..0000000 --- a/tests/functional/fixtures/set_token.rb +++ /dev/null @@ -1,9 +0,0 @@ -# https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#programmatically-creating-a-personal-access-token - -user = User.find_by_username('root') - -token = user.personal_access_tokens.first_or_create(scopes: [:api, :sudo], name: 'default'); -token.set_token('python-gitlab-token'); -token.save! - -puts token.token diff --git a/tests/smoke/__init__.py b/tests/smoke/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/smoke/__init__.py +++ /dev/null diff --git a/tests/smoke/test_dists.py b/tests/smoke/test_dists.py deleted file mode 100644 index 6f38ff7..0000000 --- a/tests/smoke/test_dists.py +++ /dev/null @@ -1,33 +0,0 @@ -import tarfile -import zipfile -from pathlib import Path -from sys import version_info - -import pytest -from setuptools import sandbox - -from gitlab import __title__, __version__ - -DIST_DIR = Path("dist") -TEST_DIR = "tests" -SDIST_FILE = f"{__title__}-{__version__}.tar.gz" -WHEEL_FILE = ( - f"{__title__.replace('-', '_')}-{__version__}-py{version_info.major}-none-any.whl" -) - - -@pytest.fixture(scope="function") -def build(): - sandbox.run_setup("setup.py", ["clean", "--all"]) - return sandbox.run_setup("setup.py", ["sdist", "bdist_wheel"]) - - -def test_sdist_includes_tests(build): - sdist = tarfile.open(DIST_DIR / SDIST_FILE, "r:gz") - test_dir = sdist.getmember(f"{__title__}-{__version__}/{TEST_DIR}") - assert test_dir.isdir() - - -def test_wheel_excludes_tests(build): - wheel = zipfile.ZipFile(DIST_DIR / WHEEL_FILE) - assert [not file.startswith(TEST_DIR) for file in wheel.namelist()] 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) |