diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 31ed1f26..cffd4d2f 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -17,7 +17,7 @@ jobs: # If different modules use different Black configs, # we need to run Black for each python component group separately. # Otherwise, they all will use the same config. - ENABLED_DIRS=("cvat-sdk" "cvat-cli" "tests/python/sdk" "tests/python/cli") + ENABLED_DIRS=("cvat-sdk" "cvat-cli" "tests/python") isValueIn () { # Checks if a value is in an array diff --git a/.github/workflows/isort.yml b/.github/workflows/isort.yml index 950fcef4..6ef09343 100644 --- a/.github/workflows/isort.yml +++ b/.github/workflows/isort.yml @@ -17,7 +17,7 @@ jobs: # If different modules use different isort configs, # we need to run isort for each python component group separately. # Otherwise, they all will use the same config. - ENABLED_DIRS=("cvat-sdk" "cvat-cli" "tests/python/sdk" "tests/python/cli") + ENABLED_DIRS=("cvat-sdk" "cvat-cli" "tests/python") isValueIn () { # Checks if a value is in an array diff --git a/tests/python/rest_api/test_analytics.py b/tests/python/rest_api/test_analytics.py index 98f4304b..0a0b2b25 100644 --- a/tests/python/rest_api/test_analytics.py +++ b/tests/python/rest_api/test_analytics.py @@ -3,13 +3,17 @@ # # SPDX-License-Identifier: MIT -import pytest from http import HTTPStatus + +import pytest + from shared.utils.config import server_get -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestGetAnalytics: - endpoint = 'analytics/app/kibana' + endpoint = "analytics/app/kibana" + def _test_can_see(self, user): response = server_get(user, self.endpoint) @@ -20,12 +24,12 @@ class TestGetAnalytics: assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('privilege, is_allow', [ - ('admin', True), ('business', True), - ('worker', False), ('user', False) - ]) + @pytest.mark.parametrize( + "privilege, is_allow", + [("admin", True), ("business", True), ("worker", False), ("user", False)], + ) def test_can_see(self, privilege, is_allow, find_users): - user = find_users(privilege=privilege)[0]['username'] + user = find_users(privilege=privilege)[0]["username"] if is_allow: self._test_can_see(user) diff --git a/tests/python/rest_api/test_cache_policy.py b/tests/python/rest_api/test_cache_policy.py index 70591657..ce124dba 100644 --- a/tests/python/rest_api/test_cache_policy.py +++ b/tests/python/rest_api/test_cache_policy.py @@ -3,12 +3,13 @@ # # SPDX-License-Identifier: MIT -from http import HTTPStatus import re +from http import HTTPStatus + from shared.utils.config import server_get -class TestCachePolicy: +class TestCachePolicy: @staticmethod def _get_js_bundle_url(response): match = re.search(r'', response) @@ -17,22 +18,25 @@ class TestCachePolicy: def _test_cache_policy_enabled(self, response): assert response.status_code == HTTPStatus.OK - assert 'public' in response.headers['Cache-Control'] and 'max-age' in response.headers['Cache-Control'] + assert ( + "public" in response.headers["Cache-Control"] + and "max-age" in response.headers["Cache-Control"] + ) def _test_cache_policy_disabled(self, response): assert response.status_code == HTTPStatus.OK - assert 'no-cache' in response.headers['Cache-Control'] + assert "no-cache" in response.headers["Cache-Control"] def test_index_not_cached(self, find_users): - user = find_users(privilege='user')[0]['username'] - index_page_response = server_get(user, '/') + user = find_users(privilege="user")[0]["username"] + index_page_response = server_get(user, "/") self._test_cache_policy_disabled(index_page_response) def test_asset_cached(self, find_users): - user = find_users(privilege='user')[0]['username'] - index_page_response = server_get(user, '/') - js_asset_url = self._get_js_bundle_url(index_page_response.content.decode('utf-8')) + user = find_users(privilege="user")[0]["username"] + index_page_response = server_get(user, "/") + js_asset_url = self._get_js_bundle_url(index_page_response.content.decode("utf-8")) js_asset_response = server_get(user, js_asset_url) self._test_cache_policy_enabled(js_asset_response) diff --git a/tests/python/rest_api/test_check_objects_integrity.py b/tests/python/rest_api/test_check_objects_integrity.py index 129c14af..3e6181ec 100644 --- a/tests/python/rest_api/test_check_objects_integrity.py +++ b/tests/python/rest_api/test_check_objects_integrity.py @@ -3,30 +3,46 @@ # # SPDX-License-Identifier: MIT -import os.path as osp import glob import json +import os.path as osp + +import pytest from deepdiff import DeepDiff + from shared.utils import config -import pytest -@pytest.mark.usefixtures('dontchangedb') -class TestGetResources: - @pytest.mark.parametrize('path', glob.glob(osp.join(config.ASSETS_DIR, '*.json'))) +@pytest.mark.usefixtures("dontchangedb") +class TestGetResources: + @pytest.mark.parametrize("path", glob.glob(osp.join(config.ASSETS_DIR, "*.json"))) def test_check_objects_integrity(self, path): with open(path) as f: - endpoint = osp.basename(path).rsplit('.')[0] - if endpoint == 'annotations': + endpoint = osp.basename(path).rsplit(".")[0] + if endpoint == "annotations": objects = json.load(f) - for jid, annotations in objects['job'].items(): - response = config.get_method('admin1', f'jobs/{jid}/annotations').json() - assert DeepDiff(annotations, response, ignore_order=True, - exclude_paths="root['version']") == {} + for jid, annotations in objects["job"].items(): + response = config.get_method("admin1", f"jobs/{jid}/annotations").json() + assert ( + DeepDiff( + annotations, + response, + ignore_order=True, + exclude_paths="root['version']", + ) + == {} + ) else: - response = config.get_method('admin1', endpoint, page_size='all') + response = config.get_method("admin1", endpoint, page_size="all") json_objs = json.load(f) resp_objs = response.json() - assert DeepDiff(json_objs, resp_objs, ignore_order=True, - exclude_regex_paths=r"root\['results'\]\[\d+\]\['last_login'\]") == {} + assert ( + DeepDiff( + json_objs, + resp_objs, + ignore_order=True, + exclude_regex_paths=r"root\['results'\]\[\d+\]\['last_login'\]", + ) + == {} + ) diff --git a/tests/python/rest_api/test_cloud_storages.py b/tests/python/rest_api/test_cloud_storages.py index 70293568..d53b073e 100644 --- a/tests/python/rest_api/test_cloud_storages.py +++ b/tests/python/rest_api/test_cloud_storages.py @@ -3,58 +3,88 @@ # # SPDX-License-Identifier: MIT -import pytest from http import HTTPStatus + +import pytest from deepdiff import DeepDiff from shared.utils.config import get_method, patch_method, post_method -@pytest.mark.usefixtures('dontchangedb') -class TestGetCloudStorage: +@pytest.mark.usefixtures("dontchangedb") +class TestGetCloudStorage: def _test_can_see(self, user, storage_id, data, **kwargs): - response = get_method(user, f'cloudstorages/{storage_id}', **kwargs) + response = get_method(user, f"cloudstorages/{storage_id}", **kwargs) response_data = response.json() - response_data = response_data.get('results', response_data) + response_data = response_data.get("results", response_data) assert response.status_code == HTTPStatus.OK - assert DeepDiff(data, response_data, ignore_order=True, - exclude_paths="root['updated_date']") == {} + assert ( + DeepDiff(data, response_data, ignore_order=True, exclude_paths="root['updated_date']") + == {} + ) def _test_cannot_see(self, user, storage_id, **kwargs): - response = get_method(user, f'cloudstorages/{storage_id}', **kwargs) + response = get_method(user, f"cloudstorages/{storage_id}", **kwargs) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('storage_id', [1]) - @pytest.mark.parametrize('group, is_owner, is_allow', [ - ('admin', False, True), - ('business', False, False), - ('user', True, True), - ]) - def test_sandbox_user_get_coud_storage(self, storage_id, group, is_owner, is_allow, users, cloud_storages): - org = '' + @pytest.mark.parametrize("storage_id", [1]) + @pytest.mark.parametrize( + "group, is_owner, is_allow", + [ + ("admin", False, True), + ("business", False, False), + ("user", True, True), + ], + ) + def test_sandbox_user_get_coud_storage( + self, storage_id, group, is_owner, is_allow, users, cloud_storages + ): + org = "" cloud_storage = cloud_storages[storage_id] - username = cloud_storage['owner']['username'] if is_owner else \ - next((u for u in users if group in u['groups'] and u['id'] != cloud_storage['owner']['id']))['username'] + username = ( + cloud_storage["owner"]["username"] + if is_owner + else next( + ( + u + for u in users + if group in u["groups"] and u["id"] != cloud_storage["owner"]["id"] + ) + )["username"] + ) if is_allow: self._test_can_see(username, storage_id, cloud_storage, org=org) else: self._test_cannot_see(username, storage_id, org=org) - - @pytest.mark.parametrize('org_id', [2]) - @pytest.mark.parametrize('storage_id', [2]) - @pytest.mark.parametrize('role, is_owner, is_allow', [ - ('worker', True, True), - ('supervisor', False, True), - ('worker', False, False), - ]) - def test_org_user_get_coud_storage(self, org_id, storage_id, role, is_owner, is_allow, find_users, cloud_storages): + @pytest.mark.parametrize("org_id", [2]) + @pytest.mark.parametrize("storage_id", [2]) + @pytest.mark.parametrize( + "role, is_owner, is_allow", + [ + ("worker", True, True), + ("supervisor", False, True), + ("worker", False, False), + ], + ) + def test_org_user_get_coud_storage( + self, org_id, storage_id, role, is_owner, is_allow, find_users, cloud_storages + ): cloud_storage = cloud_storages[storage_id] - username = cloud_storage['owner']['username'] if is_owner else \ - next((u for u in find_users(role=role, org=org_id) if u['id'] != cloud_storage['owner']['id']))['username'] + username = ( + cloud_storage["owner"]["username"] + if is_owner + else next( + ( + u + for u in find_users(role=role, org=org_id) + if u["id"] != cloud_storage["owner"]["id"] + ) + )["username"] + ) if is_allow: self._test_can_see(username, storage_id, cloud_storage, org_id=org_id) @@ -62,138 +92,189 @@ class TestGetCloudStorage: self._test_cannot_see(username, storage_id, org_id=org_id) -@pytest.mark.usefixtures('changedb') -class TestPostCloudStorage(): +@pytest.mark.usefixtures("changedb") +class TestPostCloudStorage: _SPEC = { - 'provider_type': 'AWS_S3_BUCKET', - 'resource': 'test', - 'display_name': 'Bucket', - 'credentials_type': 'KEY_SECRET_KEY_PAIR', - 'key': 'minio_access_key', 'secret_key': 'minio_secret_key', - 'specific_attributes': 'endpoint_url=http://minio:9000', - 'description': 'Some description', - 'manifests': [ - 'manifest.jsonl' - ], + "provider_type": "AWS_S3_BUCKET", + "resource": "test", + "display_name": "Bucket", + "credentials_type": "KEY_SECRET_KEY_PAIR", + "key": "minio_access_key", + "secret_key": "minio_secret_key", + "specific_attributes": "endpoint_url=http://minio:9000", + "description": "Some description", + "manifests": ["manifest.jsonl"], } _EXCLUDE_PATHS = [ - f"root['{extra_field}']" for extra_field in { + f"root['{extra_field}']" + for extra_field in { # unchanged fields - 'created_date', 'id', 'organization', 'owner', 'updated_date', + "created_date", + "id", + "organization", + "owner", + "updated_date", # credentials that server doesn't return - 'key', 'secret_key', - }] + "key", + "secret_key", + } + ] def _test_can_create(self, user, spec, **kwargs): - response = post_method(user, 'cloudstorages', spec, **kwargs) + response = post_method(user, "cloudstorages", spec, **kwargs) response_data = response.json() - response_data = response_data.get('results', response_data) + response_data = response_data.get("results", response_data) assert response.status_code == HTTPStatus.CREATED - assert DeepDiff(self._SPEC, response_data, ignore_order=True, - exclude_paths=self._EXCLUDE_PATHS) == {} + assert ( + DeepDiff( + self._SPEC, response_data, ignore_order=True, exclude_paths=self._EXCLUDE_PATHS + ) + == {} + ) def _test_cannot_create(self, user, spec, **kwargs): - response = post_method(user, 'cloudstorages', spec, **kwargs) + response = post_method(user, "cloudstorages", spec, **kwargs) assert response.status_code == HTTPStatus.FORBIDDEN - - @pytest.mark.parametrize('group, is_allow', [ - ('user', True), ('worker', False) - ]) + @pytest.mark.parametrize("group, is_allow", [("user", True), ("worker", False)]) def test_sandbox_user_create_cloud_storage(self, group, is_allow, users): - org = '' - username = [u for u in users if group in u['groups']][0]['username'] + org = "" + username = [u for u in users if group in u["groups"]][0]["username"] if is_allow: self._test_can_create(username, self._SPEC, org=org) else: self._test_cannot_create(username, self._SPEC, org=org) - @pytest.mark.parametrize('org_id', [2]) - @pytest.mark.parametrize('role, is_allow', [ - ('owner', True), ('maintainer', True), - ('worker', False), ('supervisor', False), - ]) + @pytest.mark.parametrize("org_id", [2]) + @pytest.mark.parametrize( + "role, is_allow", + [ + ("owner", True), + ("maintainer", True), + ("worker", False), + ("supervisor", False), + ], + ) def test_org_user_create_coud_storage(self, org_id, role, is_allow, find_users): - username = find_users(role=role, org=org_id)[0]['username'] + username = find_users(role=role, org=org_id)[0]["username"] if is_allow: self._test_can_create(username, self._SPEC, org_id=org_id) else: self._test_cannot_create(username, self._SPEC, org_id=org_id) -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestPatchCloudStorage: _SPEC = { - 'display_name': 'New display name', - 'description': 'New description', - 'manifests': [ - 'manifest_1.jsonl', - 'manifest_2.jsonl', + "display_name": "New display name", + "description": "New description", + "manifests": [ + "manifest_1.jsonl", + "manifest_2.jsonl", ], } _PRIVATE_BUCKET_SPEC = { - 'display_name': 'New display name', - 'description': 'New description', - 'manifests': [ - 'sub/manifest_1.jsonl', - 'sub/manifest_2.jsonl', + "display_name": "New display name", + "description": "New description", + "manifests": [ + "sub/manifest_1.jsonl", + "sub/manifest_2.jsonl", ], } _EXCLUDE_PATHS = [ - f"root['{extra_field}']" for extra_field in { + f"root['{extra_field}']" + for extra_field in { # unchanged fields - 'created_date', 'credentials_type', 'id', 'organization', 'owner', - 'provider_type', 'resource', 'specific_attributes', 'updated_date', - }] + "created_date", + "credentials_type", + "id", + "organization", + "owner", + "provider_type", + "resource", + "specific_attributes", + "updated_date", + } + ] def _test_can_update(self, user, storage_id, spec, **kwargs): - response = patch_method(user, f'cloudstorages/{storage_id}', spec, **kwargs) + response = patch_method(user, f"cloudstorages/{storage_id}", spec, **kwargs) response_data = response.json() - response_data = response_data.get('results', response_data) + response_data = response_data.get("results", response_data) assert response.status_code == HTTPStatus.OK - assert DeepDiff(spec, response_data, ignore_order=True, - exclude_paths=self._EXCLUDE_PATHS) == {} + assert ( + DeepDiff(spec, response_data, ignore_order=True, exclude_paths=self._EXCLUDE_PATHS) + == {} + ) assert response.status_code == HTTPStatus.OK def _test_cannot_update(self, user, storage_id, spec, **kwargs): - response = patch_method(user, f'cloudstorages/{storage_id}', spec, **kwargs) + response = patch_method(user, f"cloudstorages/{storage_id}", spec, **kwargs) assert response.status_code == HTTPStatus.FORBIDDEN - - @pytest.mark.parametrize('storage_id', [1]) - @pytest.mark.parametrize('group, is_owner, is_allow', [ - ('admin', False, True), - ('business', False, False), - ('worker', True, True), - ]) - def test_sandbox_user_update_cloud_storage(self, storage_id, group, is_owner, is_allow, users, cloud_storages): - org = '' + @pytest.mark.parametrize("storage_id", [1]) + @pytest.mark.parametrize( + "group, is_owner, is_allow", + [ + ("admin", False, True), + ("business", False, False), + ("worker", True, True), + ], + ) + def test_sandbox_user_update_cloud_storage( + self, storage_id, group, is_owner, is_allow, users, cloud_storages + ): + org = "" cloud_storage = cloud_storages[storage_id] - username = cloud_storage['owner']['username'] if is_owner else \ - next((u for u in users if group in u['groups'] and u['id'] != cloud_storage['owner']['id']))['username'] + username = ( + cloud_storage["owner"]["username"] + if is_owner + else next( + ( + u + for u in users + if group in u["groups"] and u["id"] != cloud_storage["owner"]["id"] + ) + )["username"] + ) if is_allow: self._test_can_update(username, storage_id, self._SPEC, org=org) else: self._test_cannot_update(username, storage_id, self._SPEC, org=org) - @pytest.mark.parametrize('org_id', [2]) - @pytest.mark.parametrize('storage_id', [2]) - @pytest.mark.parametrize('role, is_owner, is_allow', [ - ('worker', True, True), - ('maintainer', False, True), - ('supervisor', False, False), - ]) - def test_org_user_update_cloud_storage(self, org_id, storage_id, role, is_owner, is_allow, find_users, cloud_storages): + @pytest.mark.parametrize("org_id", [2]) + @pytest.mark.parametrize("storage_id", [2]) + @pytest.mark.parametrize( + "role, is_owner, is_allow", + [ + ("worker", True, True), + ("maintainer", False, True), + ("supervisor", False, False), + ], + ) + def test_org_user_update_cloud_storage( + self, org_id, storage_id, role, is_owner, is_allow, find_users, cloud_storages + ): cloud_storage = cloud_storages[storage_id] - username = cloud_storage['owner']['username'] if is_owner else \ - next((u for u in find_users(role=role, org=org_id) if u['id'] != cloud_storage['owner']['id']))['username'] + username = ( + cloud_storage["owner"]["username"] + if is_owner + else next( + ( + u + for u in find_users(role=role, org=org_id) + if u["id"] != cloud_storage["owner"]["id"] + ) + )["username"] + ) if is_allow: self._test_can_update(username, storage_id, self._PRIVATE_BUCKET_SPEC, org_id=org_id) diff --git a/tests/python/rest_api/test_invitations.py b/tests/python/rest_api/test_invitations.py index dcb25324..06c957b8 100644 --- a/tests/python/rest_api/test_invitations.py +++ b/tests/python/rest_api/test_invitations.py @@ -4,71 +4,83 @@ # SPDX-License-Identifier: MIT from http import HTTPStatus + import pytest + from shared.utils.config import post_method -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestCreateInvitations: def _test_post_invitation_201(self, user, data, invitee, **kwargs): - response = post_method(user, 'invitations', data, **kwargs) + response = post_method(user, "invitations", data, **kwargs) assert response.status_code == HTTPStatus.CREATED - assert data['role'] == response.json()['role'] - assert invitee['id'] == response.json()['user']['id'] - assert kwargs['org_id'] == response.json()['organization'] + assert data["role"] == response.json()["role"] + assert invitee["id"] == response.json()["user"]["id"] + assert kwargs["org_id"] == response.json()["organization"] def _test_post_invitation_403(self, user, data, **kwargs): - response = post_method(user, 'invitations', data, **kwargs) + response = post_method(user, "invitations", data, **kwargs) assert response.status_code == HTTPStatus.FORBIDDEN @staticmethod def get_non_member_users(memberships, users): - organization_users = set(m['user']['id'] for m in memberships if m['user'] is not None) - non_member_users = [u for u in users if u['id'] not in organization_users] + organization_users = set(m["user"]["id"] for m in memberships if m["user"] is not None) + non_member_users = [u for u in users if u["id"] not in organization_users] return non_member_users @staticmethod def get_member(role, memberships, org_id): - member = [m['user'] for m in memberships if m['role'] == role and - m['organization'] == org_id and m['user'] is not None][0] + member = [ + m["user"] + for m in memberships + if m["role"] == role and m["organization"] == org_id and m["user"] is not None + ][0] return member - @pytest.mark.parametrize('org_id', [2]) - @pytest.mark.parametrize('org_role', ['worker', 'supervisor', 'maintainer', 'owner']) - def test_create_invitation(self, organizations, memberships, users, - org_id, org_role): + @pytest.mark.parametrize("org_id", [2]) + @pytest.mark.parametrize("org_role", ["worker", "supervisor", "maintainer", "owner"]) + def test_create_invitation(self, organizations, memberships, users, org_id, org_role): member = self.get_member(org_role, memberships, org_id) non_member_users = self.get_non_member_users(memberships, users) - if org_role in ['worker', 'supervisor']: - for invitee_role in ['worker', 'supervisor', 'maintainer', 'owner']: - self._test_post_invitation_403(member['username'], { - 'role': invitee_role, - 'email': non_member_users[0]['email'] - }, org_id=org_id) + if org_role in ["worker", "supervisor"]: + for invitee_role in ["worker", "supervisor", "maintainer", "owner"]: + self._test_post_invitation_403( + member["username"], + {"role": invitee_role, "email": non_member_users[0]["email"]}, + org_id=org_id, + ) else: - for idx, invitee_role in enumerate(['worker', 'supervisor']): - self._test_post_invitation_201(member['username'], { - 'role': invitee_role, - 'email': non_member_users[idx]['email'] - }, non_member_users[idx], org_id=org_id) + for idx, invitee_role in enumerate(["worker", "supervisor"]): + self._test_post_invitation_201( + member["username"], + {"role": invitee_role, "email": non_member_users[idx]["email"]}, + non_member_users[idx], + org_id=org_id, + ) # only the owner can invite a maintainer - if org_role == 'owner': - self._test_post_invitation_201(member['username'], { - 'role': 'maintainer', - 'email': non_member_users[2]['email'] - }, non_member_users[2], org_id=org_id) + if org_role == "owner": + self._test_post_invitation_201( + member["username"], + {"role": "maintainer", "email": non_member_users[2]["email"]}, + non_member_users[2], + org_id=org_id, + ) else: - self._test_post_invitation_403(member['username'], { - 'role': 'maintainer', - 'email': non_member_users[3]['email'] - }, org_id=org_id) + self._test_post_invitation_403( + member["username"], + {"role": "maintainer", "email": non_member_users[3]["email"]}, + org_id=org_id, + ) # nobody can invite an owner - self._test_post_invitation_403(member['username'], { - 'role': 'owner', - 'email': non_member_users[4]['email'] - }, org_id=org_id) + self._test_post_invitation_403( + member["username"], + {"role": "owner", "email": non_member_users[4]["email"]}, + org_id=org_id, + ) diff --git a/tests/python/rest_api/test_issues.py b/tests/python/rest_api/test_issues.py index 72d5992e..39d770a2 100644 --- a/tests/python/rest_api/test_issues.py +++ b/tests/python/rest_api/test_issues.py @@ -9,9 +9,8 @@ from http import HTTPStatus import pytest from cvat_sdk import models -from deepdiff import DeepDiff - from cvat_sdk.api_client import exceptions +from deepdiff import DeepDiff from shared.utils.config import make_api_client @@ -227,11 +226,13 @@ class TestPatchIssues: data = request_data(issue_id) self._test_check_response(username, issue_id, data, is_allow, org_id=org) - @pytest.mark.xfail(raises=exceptions.ServiceException, - reason="server bug, https://github.com/cvat-ai/cvat/issues/122") + @pytest.mark.xfail( + raises=exceptions.ServiceException, + reason="server bug, https://github.com/cvat-ai/cvat/issues/122", + ) def test_cant_update_message(self, admin_user: str, issues_by_org): org = 2 - issue_id = issues_by_org[org][0]['id'] + issue_id = issues_by_org[org][0]["id"] with make_api_client(admin_user) as client: client.issues_api.partial_update( diff --git a/tests/python/rest_api/test_jobs.py b/tests/python/rest_api/test_jobs.py index 880feba7..5f40aaeb 100644 --- a/tests/python/rest_api/test_jobs.py +++ b/tests/python/rest_api/test_jobs.py @@ -3,75 +3,86 @@ # # SPDX-License-Identifier: MIT -from http import HTTPStatus import json +from copy import deepcopy +from http import HTTPStatus from typing import List + +import pytest from cvat_sdk.core.helpers import get_paginated_collection from deepdiff import DeepDiff -import pytest -from copy import deepcopy + from shared.utils.config import make_api_client + from .utils import export_dataset + def get_job_staff(job, tasks, projects): job_staff = [] - job_staff.append(job['assignee']) - tid = job['task_id'] - job_staff.append(tasks[tid]['owner']) - job_staff.append(tasks[tid]['assignee']) + job_staff.append(job["assignee"]) + tid = job["task_id"] + job_staff.append(tasks[tid]["owner"]) + job_staff.append(tasks[tid]["assignee"]) - pid = job['project_id'] + pid = job["project_id"] if pid: - job_staff.append(projects[pid]['owner']) - job_staff.append(projects[pid]['assignee']) - job_staff = set(u['id'] for u in job_staff if u is not None) + job_staff.append(projects[pid]["owner"]) + job_staff.append(projects[pid]["assignee"]) + job_staff = set(u["id"] for u in job_staff if u is not None) return job_staff + def filter_jobs(jobs, tasks, org): if org is None: kwargs = {} jobs = jobs.raw - elif org == '': - kwargs = {'org': ''} - jobs = [job for job in jobs - if tasks[job['task_id']]['organization'] is None] + elif org == "": + kwargs = {"org": ""} + jobs = [job for job in jobs if tasks[job["task_id"]]["organization"] is None] else: - kwargs = {'org_id': org} - jobs = [job for job in jobs - if tasks[job['task_id']]['organization'] == org] + kwargs = {"org_id": org} + jobs = [job for job in jobs if tasks[job["task_id"]]["organization"] == org] return jobs, kwargs -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestGetJobs: def _test_get_job_200(self, user, jid, data, **kwargs): with make_api_client(user) as client: (_, response) = client.jobs_api.retrieve(jid, **kwargs) assert response.status == HTTPStatus.OK - assert DeepDiff(data, json.loads(response.data), exclude_paths="root['updated_date']", - ignore_order=True) == {} + assert ( + DeepDiff( + data, + json.loads(response.data), + exclude_paths="root['updated_date']", + ignore_order=True, + ) + == {} + ) def _test_get_job_403(self, user, jid, **kwargs): with make_api_client(user) as client: - (_, response) = client.jobs_api.retrieve(jid, **kwargs, - _check_status=False, _parse_response=False) + (_, response) = client.jobs_api.retrieve( + jid, **kwargs, _check_status=False, _parse_response=False + ) assert response.status == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('org', [None, '', 1, 2]) + @pytest.mark.parametrize("org", [None, "", 1, 2]) def test_admin_get_job(self, jobs, tasks, org): jobs, kwargs = filter_jobs(jobs, tasks, org) # keep only the reasonable amount of jobs for job in jobs[:8]: - self._test_get_job_200('admin2', job['id'], job, **kwargs) + self._test_get_job_200("admin2", job["id"], job, **kwargs) - @pytest.mark.parametrize('org_id', ['', None, 1, 2]) - @pytest.mark.parametrize('groups', [['business'], ['user'], ['worker'], []]) - def test_non_admin_get_job(self, org_id, groups, users, jobs, tasks, projects, - org_staff): + @pytest.mark.parametrize("org_id", ["", None, 1, 2]) + @pytest.mark.parametrize("groups", [["business"], ["user"], ["worker"], []]) + def test_non_admin_get_job(self, org_id, groups, users, jobs, tasks, projects, org_staff): # keep the reasonable amount of users and jobs - users = [u for u in users if u['groups'] == groups][:4] + users = [u for u in users if u["groups"] == groups][:4] jobs, kwargs = filter_jobs(jobs, tasks, org_id) org_staff = org_staff(org_id) @@ -80,36 +91,42 @@ class TestGetJobs: # check if the specific user in job_staff to see the job for user in users: - if user['id'] in job_staff | org_staff: - self._test_get_job_200(user['username'], job['id'], job, **kwargs) + if user["id"] in job_staff | org_staff: + self._test_get_job_200(user["username"], job["id"], job, **kwargs) else: - self._test_get_job_403(user['username'], job['id'], **kwargs) + self._test_get_job_403(user["username"], job["id"], **kwargs) -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestListJobs: def _test_list_jobs_200(self, user, data, **kwargs): with make_api_client(user) as client: - results = get_paginated_collection(client.jobs_api.list_endpoint, - return_json=True, **kwargs) - assert DeepDiff(data, results, exclude_paths="root['updated_date']", - ignore_order=True) == {} + results = get_paginated_collection( + client.jobs_api.list_endpoint, return_json=True, **kwargs + ) + assert ( + DeepDiff(data, results, exclude_paths="root['updated_date']", ignore_order=True) + == {} + ) def _test_list_jobs_403(self, user, **kwargs): with make_api_client(user) as client: - (_, response) = client.jobs_api.list(**kwargs, - _check_status=False, _parse_response=False) + (_, response) = client.jobs_api.list( + **kwargs, _check_status=False, _parse_response=False + ) assert response.status == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('org', [None, '', 1, 2]) + @pytest.mark.parametrize("org", [None, "", 1, 2]) def test_admin_list_jobs(self, jobs, tasks, org): jobs, kwargs = filter_jobs(jobs, tasks, org) - self._test_list_jobs_200('admin1', jobs, **kwargs) - - @pytest.mark.parametrize('org_id', ['', None, 1, 2]) - @pytest.mark.parametrize('groups', [['business'], ['user'], ['worker'], []]) - def test_non_admin_list_jobs(self, org_id, groups, users, jobs, tasks, - projects, org_staff, is_org_member): - users = [u for u in users if u['groups'] == groups][:2] + self._test_list_jobs_200("admin1", jobs, **kwargs) + + @pytest.mark.parametrize("org_id", ["", None, 1, 2]) + @pytest.mark.parametrize("groups", [["business"], ["user"], ["worker"], []]) + def test_non_admin_list_jobs( + self, org_id, groups, users, jobs, tasks, projects, org_staff, is_org_member + ): + users = [u for u in users if u["groups"] == groups][:2] jobs, kwargs = filter_jobs(jobs, tasks, org_id) org_staff = org_staff(org_id) @@ -117,14 +134,15 @@ class TestListJobs: user_jobs = [] for job in jobs: job_staff = get_job_staff(job, tasks, projects) - if user['id'] in job_staff | org_staff: + if user["id"] in job_staff | org_staff: user_jobs.append(job) - if is_org_member(user['id'], org_id): - self._test_list_jobs_200(user['username'], user_jobs, **kwargs) + if is_org_member(user["id"], org_id): + self._test_list_jobs_200(user["username"], user_jobs, **kwargs) else: - self._test_list_jobs_403(user['username'], **kwargs) + self._test_list_jobs_403(user["username"], **kwargs) + -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetAnnotations: def _test_get_job_annotations_200(self, user, jid, data, **kwargs): with make_api_client(user) as client: @@ -132,112 +150,191 @@ class TestGetAnnotations: assert response.status == HTTPStatus.OK response_data = json.loads(response.data) - response_data['shapes'] = sorted(response_data['shapes'], key=lambda a: a['id']) - assert DeepDiff(data, response_data, - exclude_regex_paths=r"root\['version|updated_date'\]") == {} + response_data["shapes"] = sorted(response_data["shapes"], key=lambda a: a["id"]) + assert ( + DeepDiff(data, response_data, exclude_regex_paths=r"root\['version|updated_date'\]") + == {} + ) def _test_get_job_annotations_403(self, user, jid, **kwargs): with make_api_client(user) as client: - (_, response) = client.jobs_api.retrieve_annotations(jid, **kwargs, - _check_status=False, _parse_response=False) + (_, response) = client.jobs_api.retrieve_annotations( + jid, **kwargs, _check_status=False, _parse_response=False + ) assert response.status == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('org', ['']) - @pytest.mark.parametrize('groups, job_staff, expect_success', [ - (['admin'], True, True), (['admin'], False, True), - (['business'], True, True), (['business'], False, False), - (['worker'], True, True), (['worker'], False, False), - (['user'], True, True), (['user'], False, False) - ]) - def test_user_get_job_annotations(self, org, groups, job_staff, - expect_success, users, jobs, tasks, annotations, find_job_staff_user): - users = [u for u in users if u['groups'] == groups] + @pytest.mark.parametrize("org", [""]) + @pytest.mark.parametrize( + "groups, job_staff, expect_success", + [ + (["admin"], True, True), + (["admin"], False, True), + (["business"], True, True), + (["business"], False, False), + (["worker"], True, True), + (["worker"], False, False), + (["user"], True, True), + (["user"], False, False), + ], + ) + def test_user_get_job_annotations( + self, + org, + groups, + job_staff, + expect_success, + users, + jobs, + tasks, + annotations, + find_job_staff_user, + ): + users = [u for u in users if u["groups"] == groups] jobs, kwargs = filter_jobs(jobs, tasks, org) username, job_id = find_job_staff_user(jobs, users, job_staff) if expect_success: - self._test_get_job_annotations_200(username, - job_id, annotations['job'][str(job_id)], **kwargs) + self._test_get_job_annotations_200( + username, job_id, annotations["job"][str(job_id)], **kwargs + ) else: self._test_get_job_annotations_403(username, job_id, **kwargs) - @pytest.mark.parametrize('org', [2]) - @pytest.mark.parametrize('role, job_staff, expect_success', [ - ('owner', True, True), ('owner', False, True), - ('maintainer', True, True), ('maintainer', False, True), - ('supervisor', True, True), ('supervisor', False, False), - ('worker', True, True), ('worker', False, False), - ]) - def test_member_get_job_annotations(self, org, role, job_staff, expect_success, - jobs, tasks, find_job_staff_user, annotations, find_users): + @pytest.mark.parametrize("org", [2]) + @pytest.mark.parametrize( + "role, job_staff, expect_success", + [ + ("owner", True, True), + ("owner", False, True), + ("maintainer", True, True), + ("maintainer", False, True), + ("supervisor", True, True), + ("supervisor", False, False), + ("worker", True, True), + ("worker", False, False), + ], + ) + def test_member_get_job_annotations( + self, + org, + role, + job_staff, + expect_success, + jobs, + tasks, + find_job_staff_user, + annotations, + find_users, + ): users = find_users(org=org, role=role) jobs, kwargs = filter_jobs(jobs, tasks, org) username, jid = find_job_staff_user(jobs, users, job_staff) if expect_success: - data = annotations['job'][str(jid)] - data['shapes'] = sorted(data['shapes'], key=lambda a: a['id']) + data = annotations["job"][str(jid)] + data["shapes"] = sorted(data["shapes"], key=lambda a: a["id"]) self._test_get_job_annotations_200(username, jid, data, **kwargs) else: self._test_get_job_annotations_403(username, jid, **kwargs) - @pytest.mark.parametrize('org', [1]) - @pytest.mark.parametrize('privilege, expect_success', [ - ('admin', True), ('business', False), ('worker', False), ('user', False) - ]) - def test_non_member_get_job_annotations(self, org, privilege, expect_success, - jobs, tasks, find_job_staff_user, annotations, find_users): + @pytest.mark.parametrize("org", [1]) + @pytest.mark.parametrize( + "privilege, expect_success", + [("admin", True), ("business", False), ("worker", False), ("user", False)], + ) + def test_non_member_get_job_annotations( + self, + org, + privilege, + expect_success, + jobs, + tasks, + find_job_staff_user, + annotations, + find_users, + ): users = find_users(privilege=privilege, exclude_org=org) jobs, kwargs = filter_jobs(jobs, tasks, org) username, job_id = find_job_staff_user(jobs, users, False) - kwargs = {'org_id': org} + kwargs = {"org_id": org} if expect_success: - self._test_get_job_annotations_200(username, - job_id, annotations['job'][str(job_id)], **kwargs) + self._test_get_job_annotations_200( + username, job_id, annotations["job"][str(job_id)], **kwargs + ) else: self._test_get_job_annotations_403(username, job_id, **kwargs) -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestPatchJobAnnotations: def _check_respone(self, username, jid, expect_success, data=None, org=None): kwargs = {} if org is not None: if isinstance(org, str): - kwargs['org'] = org + kwargs["org"] = org else: - kwargs['org_id'] = org + kwargs["org_id"] = org with make_api_client(username) as client: - (_, response) = client.jobs_api.partial_update_annotations(id=jid, - patched_labeled_data_request=deepcopy(data), action='update', **kwargs, - _parse_response=expect_success, _check_status=expect_success) + (_, response) = client.jobs_api.partial_update_annotations( + id=jid, + patched_labeled_data_request=deepcopy(data), + action="update", + **kwargs, + _parse_response=expect_success, + _check_status=expect_success, + ) if expect_success: assert response.status == HTTPStatus.OK - assert DeepDiff(data, json.loads(response.data), - exclude_regex_paths=r"root\['version|updated_date'\]") == {} + assert ( + DeepDiff( + data, + json.loads(response.data), + exclude_regex_paths=r"root\['version|updated_date'\]", + ) + == {} + ) else: assert response.status == HTTPStatus.FORBIDDEN - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def request_data(self, annotations): def get_data(jid): - data = deepcopy(annotations['job'][str(jid)]) - data['shapes'][0].update({'points': [2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}) - data['version'] += 1 + data = deepcopy(annotations["job"][str(jid)]) + data["shapes"][0].update({"points": [2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}) + data["version"] += 1 return data + return get_data - @pytest.mark.parametrize('org', [2]) - @pytest.mark.parametrize('role, job_staff, expect_success', [ - ('maintainer', False, True), ('owner', False, True), - ('supervisor', False, False), ('worker', False, False), - ('maintainer', True, True), ('owner', True, True), - ('supervisor', True, True), ('worker', True, True) - ]) - def test_member_update_job_annotations(self, org, role, job_staff, expect_success, - find_job_staff_user, find_users, request_data, jobs_by_org, filter_jobs_with_shapes): + @pytest.mark.parametrize("org", [2]) + @pytest.mark.parametrize( + "role, job_staff, expect_success", + [ + ("maintainer", False, True), + ("owner", False, True), + ("supervisor", False, False), + ("worker", False, False), + ("maintainer", True, True), + ("owner", True, True), + ("supervisor", True, True), + ("worker", True, True), + ], + ) + def test_member_update_job_annotations( + self, + org, + role, + job_staff, + expect_success, + find_job_staff_user, + find_users, + request_data, + jobs_by_org, + filter_jobs_with_shapes, + ): users = find_users(role=role, org=org) jobs = jobs_by_org[org] filtered_jobs = filter_jobs_with_shapes(jobs) @@ -246,12 +343,22 @@ class TestPatchJobAnnotations: data = request_data(jid) self._check_respone(username, jid, expect_success, data, org=org) - @pytest.mark.parametrize('org', [2]) - @pytest.mark.parametrize('privilege, expect_success', [ - ('admin', True), ('business', False), ('worker', False), ('user', False) - ]) - def test_non_member_update_job_annotations(self, org, privilege, expect_success, - find_job_staff_user, find_users, request_data, jobs_by_org, filter_jobs_with_shapes): + @pytest.mark.parametrize("org", [2]) + @pytest.mark.parametrize( + "privilege, expect_success", + [("admin", True), ("business", False), ("worker", False), ("user", False)], + ) + def test_non_member_update_job_annotations( + self, + org, + privilege, + expect_success, + find_job_staff_user, + find_users, + request_data, + jobs_by_org, + filter_jobs_with_shapes, + ): users = find_users(privilege=privilege, exclude_org=org) jobs = jobs_by_org[org] filtered_jobs = filter_jobs_with_shapes(jobs) @@ -260,15 +367,32 @@ class TestPatchJobAnnotations: data = request_data(jid) self._check_respone(username, jid, expect_success, data, org=org) - @pytest.mark.parametrize('org', ['']) - @pytest.mark.parametrize('privilege, job_staff, expect_success', [ - ('admin', True, True), ('admin', False, True), - ('business', True, True), ('business', False, False), - ('worker', True, True), ('worker', False, False), - ('user', True, True), ('user', False, False) - ]) - def test_user_update_job_annotations(self, org, privilege, job_staff, expect_success, - find_job_staff_user, find_users, request_data, jobs_by_org, filter_jobs_with_shapes): + @pytest.mark.parametrize("org", [""]) + @pytest.mark.parametrize( + "privilege, job_staff, expect_success", + [ + ("admin", True, True), + ("admin", False, True), + ("business", True, True), + ("business", False, False), + ("worker", True, True), + ("worker", False, False), + ("user", True, True), + ("user", False, False), + ], + ) + def test_user_update_job_annotations( + self, + org, + privilege, + job_staff, + expect_success, + find_job_staff_user, + find_users, + request_data, + jobs_by_org, + filter_jobs_with_shapes, + ): users = find_users(privilege=privilege) jobs = jobs_by_org[org] filtered_jobs = filter_jobs_with_shapes(jobs) @@ -277,62 +401,95 @@ class TestPatchJobAnnotations: data = request_data(jid) self._check_respone(username, jid, expect_success, data, org=org) -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestPatchJob: - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def find_task_staff_user(self, is_task_staff): def find(jobs, users, is_staff): for job in jobs: for user in users: - if is_staff == is_task_staff(user['id'], job['task_id']): - return user, job['id'] + if is_staff == is_task_staff(user["id"], job["task_id"]): + return user, job["id"] return None, None + return find - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def expected_data(self, jobs, users): - keys = ['url', 'id', 'username', 'first_name', 'last_name'] + keys = ["url", "id", "username", "first_name", "last_name"] + def find(job_id, assignee_id): data = deepcopy(jobs[job_id]) - data['assignee'] = dict(filter(lambda a: a[0] in keys, - users[assignee_id].items())) + data["assignee"] = dict(filter(lambda a: a[0] in keys, users[assignee_id].items())) return data + return find - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def new_assignee(self, jobs, tasks, assignee_id, org_staff): def find_new_assignee(jid, user_id): - members = org_staff(tasks[jobs[jid]['task_id']]['organization']) + members = org_staff(tasks[jobs[jid]["task_id"]]["organization"]) members -= {assignee_id(jobs[jid]), user_id} return members.pop() + return find_new_assignee - @pytest.mark.parametrize('org', [2]) - @pytest.mark.parametrize('role, task_staff, expect_success', [ - ('maintainer', False, True), ('owner', False, True), - ('supervisor', False, False), ('worker', False, False), - ('maintainer', True, True), ('owner', True, True), - ('supervisor', True, True), ('worker', True, True) - ]) - def test_member_update_job_assignee(self, org, role, task_staff, expect_success, - find_task_staff_user, find_users, jobs_by_org, new_assignee, expected_data): + @pytest.mark.parametrize("org", [2]) + @pytest.mark.parametrize( + "role, task_staff, expect_success", + [ + ("maintainer", False, True), + ("owner", False, True), + ("supervisor", False, False), + ("worker", False, False), + ("maintainer", True, True), + ("owner", True, True), + ("supervisor", True, True), + ("worker", True, True), + ], + ) + def test_member_update_job_assignee( + self, + org, + role, + task_staff, + expect_success, + find_task_staff_user, + find_users, + jobs_by_org, + new_assignee, + expected_data, + ): users, jobs = find_users(role=role, org=org), jobs_by_org[org] user, jid = find_task_staff_user(jobs, users, task_staff) - assignee = new_assignee(jid, user['id']) - with make_api_client(user['username']) as client: - (_, response) = client.jobs_api.partial_update(id=jid, - patched_job_write_request={'assignee': assignee}, org_id=org, - _parse_response=expect_success, _check_status=expect_success) + assignee = new_assignee(jid, user["id"]) + with make_api_client(user["username"]) as client: + (_, response) = client.jobs_api.partial_update( + id=jid, + patched_job_write_request={"assignee": assignee}, + org_id=org, + _parse_response=expect_success, + _check_status=expect_success, + ) if expect_success: assert response.status == HTTPStatus.OK - assert DeepDiff(expected_data(jid, assignee), json.loads(response.data), - exclude_paths="root['updated_date']", ignore_order=True) == {} + assert ( + DeepDiff( + expected_data(jid, assignee), + json.loads(response.data), + exclude_paths="root['updated_date']", + ignore_order=True, + ) + == {} + ) else: assert response.status == HTTPStatus.FORBIDDEN -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestJobDataset: def _export_dataset(self, username, jid, **kwargs): with make_api_client(username) as api_client: @@ -340,15 +497,16 @@ class TestJobDataset: def _export_annotations(self, username, jid, **kwargs): with make_api_client(username) as api_client: - return export_dataset(api_client.jobs_api.retrieve_annotations_endpoint, - id=jid, **kwargs) + return export_dataset( + api_client.jobs_api.retrieve_annotations_endpoint, id=jid, **kwargs + ) def test_can_export_dataset(self, admin_user: str, jobs_with_shapes: List): job = jobs_with_shapes[0] - response = self._export_dataset(admin_user, job['id'], format='CVAT for images 1.1') + response = self._export_dataset(admin_user, job["id"], format="CVAT for images 1.1") assert response.data def test_can_export_annotations(self, admin_user: str, jobs_with_shapes: List): job = jobs_with_shapes[0] - response = self._export_annotations(admin_user, job['id'], format='CVAT for images 1.1') + response = self._export_annotations(admin_user, job["id"], format="CVAT for images 1.1") assert response.data diff --git a/tests/python/rest_api/test_memberships.py b/tests/python/rest_api/test_memberships.py index ae4bb009..35b8f12b 100644 --- a/tests/python/rest_api/test_memberships.py +++ b/tests/python/rest_api/test_memberships.py @@ -3,77 +3,84 @@ # # SPDX-License-Identifier: MIT -import pytest from http import HTTPStatus + +import pytest from deepdiff import DeepDiff from shared.utils.config import get_method, patch_method -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestGetMemberships: def _test_can_see_memberships(self, user, data, **kwargs): - response = get_method(user, 'memberships', **kwargs) + response = get_method(user, "memberships", **kwargs) assert response.status_code == HTTPStatus.OK - assert DeepDiff(data, response.json()['results']) == {} + assert DeepDiff(data, response.json()["results"]) == {} def _test_cannot_see_memberships(self, user, **kwargs): - response = get_method(user, 'memberships', **kwargs) + response = get_method(user, "memberships", **kwargs) assert response.status_code == HTTPStatus.FORBIDDEN def test_admin_can_see_all_memberships(self, memberships): - self._test_can_see_memberships('admin2', memberships.raw, page_size='all') + self._test_can_see_memberships("admin2", memberships.raw, page_size="all") def test_non_admin_can_see_only_self_memberships(self, memberships): - non_admins= ['business1', 'user1', 'dummy1','worker2'] + non_admins = ["business1", "user1", "dummy1", "worker2"] for username in non_admins: - data = [obj for obj in memberships - if obj['user']['username'] == username] + data = [obj for obj in memberships if obj["user"]["username"] == username] self._test_can_see_memberships(username, data) def test_all_members_can_see_other_members_membership(self, memberships): - data = [obj for obj in memberships if obj['organization'] == 1] + data = [obj for obj in memberships if obj["organization"] == 1] for membership in data: - self._test_can_see_memberships(membership['user']['username'], - data, org_id=1) + self._test_can_see_memberships(membership["user"]["username"], data, org_id=1) def test_non_members_cannot_see_members_membership(self): - non_org1_users = ['user2', 'worker3'] + non_org1_users = ["user2", "worker3"] for user in non_org1_users: self._test_cannot_see_memberships(user, org_id=1) -@pytest.mark.usefixtures('changedb') + + +@pytest.mark.usefixtures("changedb") class TestPatchMemberships: _ORG = 2 def _test_can_change_membership(self, user, membership_id, new_role): - response = patch_method(user, f"memberships/{membership_id}", - {'role': new_role}, org_id=self._ORG) + response = patch_method( + user, f"memberships/{membership_id}", {"role": new_role}, org_id=self._ORG + ) assert response.status_code == HTTPStatus.OK - assert response.json()['role'] == new_role + assert response.json()["role"] == new_role def _test_cannot_change_membership(self, user, membership_id, new_role): - response = patch_method(user, f"memberships/{membership_id}", - {'role': new_role}, org_id=self._ORG) + response = patch_method( + user, f"memberships/{membership_id}", {"role": new_role}, org_id=self._ORG + ) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('who, whom, new_role, is_allow', [ - ('supervisor', 'worker', 'supervisor', False), - ('supervisor', 'maintainer', 'supervisor', False), - ('worker', 'supervisor', 'worker', False), - ('worker', 'maintainer', 'worker', False), - ('maintainer', 'maintainer', 'worker', False), - ('maintainer', 'supervisor', 'worker', True), - ('maintainer', 'worker', 'supervisor', True), - ('owner', 'maintainer', 'worker', True), - ('owner', 'supervisor', 'worker', True), - ('owner', 'worker', 'supervisor', True), - ]) + @pytest.mark.parametrize( + "who, whom, new_role, is_allow", + [ + ("supervisor", "worker", "supervisor", False), + ("supervisor", "maintainer", "supervisor", False), + ("worker", "supervisor", "worker", False), + ("worker", "maintainer", "worker", False), + ("maintainer", "maintainer", "worker", False), + ("maintainer", "supervisor", "worker", True), + ("maintainer", "worker", "supervisor", True), + ("owner", "maintainer", "worker", True), + ("owner", "supervisor", "worker", True), + ("owner", "worker", "supervisor", True), + ], + ) def test_user_can_change_role_of_member(self, who, whom, new_role, is_allow, find_users): - user = find_users(org=self._ORG, role=who)[0]['username'] - membership_id = find_users(org=self._ORG, role=whom)[1]['membership_id'] + user = find_users(org=self._ORG, role=who)[0]["username"] + membership_id = find_users(org=self._ORG, role=whom)[1]["membership_id"] if is_allow: self._test_can_change_membership(user, membership_id, new_role) diff --git a/tests/python/rest_api/test_organizations.py b/tests/python/rest_api/test_organizations.py index d26b8532..9bc2255e 100644 --- a/tests/python/rest_api/test_organizations.py +++ b/tests/python/rest_api/test_organizations.py @@ -3,129 +3,156 @@ # # SPDX-License-Identifier: MIT +from copy import deepcopy from http import HTTPStatus + import pytest -from shared.utils.config import get_method, options_method, patch_method, delete_method from deepdiff import DeepDiff -from copy import deepcopy + +from shared.utils.config import delete_method, get_method, options_method, patch_method + class TestMetadataOrganizations: _ORG = 2 - @pytest.mark.parametrize('privilege, role, is_member', [ - ('admin', None, None), - ('user', None, False), - ('business', None, False), - ('worker', None, False), - (None, 'owner', True), - (None, 'maintainer', True), - (None, 'worker', True), - (None, 'supervisor', True), - ]) - def test_can_send_options_request(self, privilege, role, is_member, - find_users, organizations): + @pytest.mark.parametrize( + "privilege, role, is_member", + [ + ("admin", None, None), + ("user", None, False), + ("business", None, False), + ("worker", None, False), + (None, "owner", True), + (None, "maintainer", True), + (None, "worker", True), + (None, "supervisor", True), + ], + ) + def test_can_send_options_request(self, privilege, role, is_member, find_users, organizations): exclude_org = None if is_member else self._ORG org = self._ORG if is_member else None - user = find_users(privilege=privilege, role=role, org=org, - exclude_org=exclude_org)[0]['username'] + user = find_users(privilege=privilege, role=role, org=org, exclude_org=exclude_org)[0][ + "username" + ] - response = options_method(user, f'organizations') + response = options_method(user, f"organizations") assert response.status_code == HTTPStatus.OK - response = options_method(user, f'organizations/{self._ORG}') + response = options_method(user, f"organizations/{self._ORG}") assert response.status_code == HTTPStatus.OK -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestGetOrganizations: _ORG = 2 - @pytest.mark.parametrize('privilege, role, is_member, is_allow', [ - ('admin', None, None, True), - ('user', None, False, False), - ('business', None, False, False), - ('worker', None, False, False), - (None, 'owner', True, True), - (None, 'maintainer', True, True), - (None, 'worker', True, True), - (None, 'supervisor', True, True), - ]) - def test_can_see_specific_organization(self, privilege, role, is_member, - is_allow, find_users, organizations): + @pytest.mark.parametrize( + "privilege, role, is_member, is_allow", + [ + ("admin", None, None, True), + ("user", None, False, False), + ("business", None, False, False), + ("worker", None, False, False), + (None, "owner", True, True), + (None, "maintainer", True, True), + (None, "worker", True, True), + (None, "supervisor", True, True), + ], + ) + def test_can_see_specific_organization( + self, privilege, role, is_member, is_allow, find_users, organizations + ): exclude_org = None if is_member else self._ORG org = self._ORG if is_member else None - user = find_users(privilege=privilege, role=role, org=org, - exclude_org=exclude_org)[0]['username'] + user = find_users(privilege=privilege, role=role, org=org, exclude_org=exclude_org)[0][ + "username" + ] - response = get_method(user, f'organizations/{self._ORG}') + response = get_method(user, f"organizations/{self._ORG}") if is_allow: assert response.status_code == HTTPStatus.OK assert DeepDiff(organizations[self._ORG], response.json()) == {} else: assert response.status_code == HTTPStatus.NOT_FOUND -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestPatchOrganizations: _ORG = 2 - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def request_data(self): - return {'slug': 'new', 'name': 'new', 'description': 'new', - 'contact': {'email': 'new@cvat.org'}} - - @pytest.fixture(scope='class') + return { + "slug": "new", + "name": "new", + "description": "new", + "contact": {"email": "new@cvat.org"}, + } + + @pytest.fixture(scope="class") def expected_data(self, organizations, request_data): data = deepcopy(organizations[self._ORG]) data.update(request_data) return data - @pytest.mark.parametrize('privilege, role, is_member, is_allow', [ - ('admin', None, None, True), - ('user', None, False, False), - ('business', None, False, False), - ('worker', None, False, False), - (None, 'owner', True, True), - (None, 'maintainer', True, True), - (None, 'worker', True, False), - (None, 'supervisor', True, False), - ]) - def test_can_update_specific_organization(self, privilege, role, is_member, - is_allow, find_users, request_data, expected_data): + @pytest.mark.parametrize( + "privilege, role, is_member, is_allow", + [ + ("admin", None, None, True), + ("user", None, False, False), + ("business", None, False, False), + ("worker", None, False, False), + (None, "owner", True, True), + (None, "maintainer", True, True), + (None, "worker", True, False), + (None, "supervisor", True, False), + ], + ) + def test_can_update_specific_organization( + self, privilege, role, is_member, is_allow, find_users, request_data, expected_data + ): exclude_org = None if is_member else self._ORG org = self._ORG if is_member else None - user = find_users(privilege=privilege, role=role, org=org, - exclude_org=exclude_org)[0]['username'] + user = find_users(privilege=privilege, role=role, org=org, exclude_org=exclude_org)[0][ + "username" + ] - response = patch_method(user, f'organizations/{self._ORG}', request_data) + response = patch_method(user, f"organizations/{self._ORG}", request_data) if is_allow: assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_data, response.json(), - exclude_paths="root['updated_date']") == {} + assert ( + DeepDiff(expected_data, response.json(), exclude_paths="root['updated_date']") == {} + ) else: assert response.status_code != HTTPStatus.OK -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestDeleteOrganizations: _ORG = 2 - @pytest.mark.parametrize('privilege, role, is_member, is_allow', [ - ('admin', None, None, True), - (None, 'owner', True, True), - (None, 'maintainer', True, False), - (None, 'worker', True, False), - (None, 'supervisor', True, False), - ('user', None, False, False), - ('business', None, False, False), - ('worker', None, False, False), - ]) - def test_can_delete(self, privilege, role, is_member, - is_allow, find_users): + @pytest.mark.parametrize( + "privilege, role, is_member, is_allow", + [ + ("admin", None, None, True), + (None, "owner", True, True), + (None, "maintainer", True, False), + (None, "worker", True, False), + (None, "supervisor", True, False), + ("user", None, False, False), + ("business", None, False, False), + ("worker", None, False, False), + ], + ) + def test_can_delete(self, privilege, role, is_member, is_allow, find_users): exclude_org = None if is_member else self._ORG org = self._ORG if is_member else None - user = find_users(privilege=privilege, role=role, org=org, - exclude_org=exclude_org)[0]['username'] + user = find_users(privilege=privilege, role=role, org=org, exclude_org=exclude_org)[0][ + "username" + ] - response = delete_method(user, f'organizations/{self._ORG}') + response = delete_method(user, f"organizations/{self._ORG}") if is_allow: assert response.status_code == HTTPStatus.NO_CONTENT diff --git a/tests/python/rest_api/test_projects.py b/tests/python/rest_api/test_projects.py index 2966a37a..e67e6ee7 100644 --- a/tests/python/rest_api/test_projects.py +++ b/tests/python/rest_api/test_projects.py @@ -4,25 +4,25 @@ # SPDX-License-Identifier: MIT import io +from copy import deepcopy from http import HTTPStatus from itertools import groupby, product - from time import sleep import pytest -from copy import deepcopy from deepdiff import DeepDiff -from shared.utils.config import get_method, patch_method, make_api_client +from shared.utils.config import get_method, make_api_client, patch_method + from .utils import export_dataset -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetProjects: def _find_project_by_user_org(self, user, projects, is_project_staff_flag, is_project_staff): for p in projects: - if is_project_staff(user['id'], p['id']) == is_project_staff_flag: - return p['id'] + if is_project_staff(user["id"], p["id"]) == is_project_staff_flag: + return p["id"] def _test_response_200(self, username, project_id, **kwargs): with make_api_client(username) as api_client: @@ -32,84 +32,98 @@ class TestGetProjects: def _test_response_403(self, username, project_id): with make_api_client(username) as api_client: - (_, response) = api_client.projects_api.retrieve(project_id, - _parse_response=False, _check_status=False) + (_, response) = api_client.projects_api.retrieve( + project_id, _parse_response=False, _check_status=False + ) assert response.status == HTTPStatus.FORBIDDEN # Admin can see any project even he has no ownerships for this project. def test_project_admin_accessibility(self, projects, find_users, is_project_staff, org_staff): - users = find_users(privilege='admin') + users = find_users(privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['organization']) - and user['id'] not in org_staff(project['organization']) + if not is_project_staff(user["id"], project["organization"]) + and user["id"] not in org_staff(project["organization"]) ) - self._test_response_200(user['username'], project['id']) + self._test_response_200(user["username"], project["id"]) # Project owner or project assignee can see project. def test_project_owner_accessibility(self, projects): for p in projects: - if p['owner'] is not None: + if p["owner"] is not None: project_with_owner = p - if p['assignee'] is not None: + if p["assignee"] is not None: project_with_assignee = p assert project_with_owner is not None assert project_with_assignee is not None - self._test_response_200(project_with_owner['owner']['username'], project_with_owner['id']) - self._test_response_200(project_with_assignee['assignee']['username'], project_with_assignee['id']) + self._test_response_200(project_with_owner["owner"]["username"], project_with_owner["id"]) + self._test_response_200( + project_with_assignee["assignee"]["username"], project_with_assignee["id"] + ) def test_user_cannot_see_project(self, projects, find_users, is_project_staff, org_staff): - users = find_users(exclude_privilege='admin') + users = find_users(exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['organization']) - and user['id'] not in org_staff(project['organization']) + if not is_project_staff(user["id"], project["organization"]) + and user["id"] not in org_staff(project["organization"]) + ) + self._test_response_403(user["username"], project["id"]) + + @pytest.mark.parametrize("role", ("supervisor", "worker")) + def test_if_supervisor_or_worker_cannot_see_project( + self, projects, is_project_staff, find_users, role + ): + user, pid = next( + ( + (user, project["id"]) + for user in find_users(role=role, exclude_privilege="admin") + for project in projects + if project["organization"] == user["org"] + and not is_project_staff(user["id"], project["id"]) + ) + ) + + self._test_response_403(user["username"], pid) + + @pytest.mark.parametrize("role", ("maintainer", "owner")) + def test_if_maintainer_or_owner_can_see_project( + self, find_users, projects, is_project_staff, role + ): + user, pid = next( + ( + (user, project["id"]) + for user in find_users(role=role, exclude_privilege="admin") + for project in projects + if project["organization"] == user["org"] + and not is_project_staff(user["id"], project["id"]) + ) ) - self._test_response_403(user['username'], project['id']) - - @pytest.mark.parametrize('role', ('supervisor', 'worker')) - def test_if_supervisor_or_worker_cannot_see_project(self, projects, is_project_staff, - find_users, role): - user, pid = next(( - (user, project['id']) - for user in find_users(role=role, exclude_privilege='admin') - for project in projects - if project['organization'] == user['org'] \ - and not is_project_staff(user['id'], project['id']) - )) - - self._test_response_403(user['username'], pid) - - @pytest.mark.parametrize('role', ('maintainer', 'owner')) - def test_if_maintainer_or_owner_can_see_project(self, find_users, projects, is_project_staff, role): - user, pid = next(( - (user, project['id']) - for user in find_users(role=role, exclude_privilege='admin') - for project in projects - if project['organization'] == user['org'] \ - and not is_project_staff(user['id'], project['id']) - )) - - self._test_response_200(user['username'], pid, org_id=user['org']) - - @pytest.mark.parametrize('role', ('supervisor', 'worker')) - def test_if_org_member_supervisor_or_worker_can_see_project(self, projects, - find_users, is_project_staff, role): - user, pid = next(( - (user, project['id']) - for user in find_users(role=role, exclude_privilege='admin') - for project in projects - if project['organization'] == user['org'] \ - and is_project_staff(user['id'], project['id']) - )) - - self._test_response_200(user['username'], pid, org_id=user['org']) + + self._test_response_200(user["username"], pid, org_id=user["org"]) + + @pytest.mark.parametrize("role", ("supervisor", "worker")) + def test_if_org_member_supervisor_or_worker_can_see_project( + self, projects, find_users, is_project_staff, role + ): + user, pid = next( + ( + (user, project["id"]) + for user in find_users(role=role, exclude_privilege="admin") + for project in projects + if project["organization"] == user["org"] + and is_project_staff(user["id"], project["id"]) + ) + ) + + self._test_response_200(user["username"], pid, org_id=user["org"]) + class TestGetProjectBackup: def _test_can_get_project_backup(self, username, pid, **kwargs): @@ -128,105 +142,130 @@ class TestGetProjectBackup: def test_admin_can_get_project_backup(self, projects): project = list(projects)[0] - self._test_can_get_project_backup('admin1', project['id']) + self._test_can_get_project_backup("admin1", project["id"]) # User that not in [project:owner, project:assignee] cannot get project backup. def test_user_cannot_get_project_backup(self, find_users, projects, is_project_staff): - users = find_users(exclude_privilege='admin') + users = find_users(exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) + if not is_project_staff(user["id"], project["id"]) ) - self._test_cannot_get_project_backup(user['username'], project['id']) + self._test_cannot_get_project_backup(user["username"], project["id"]) # Org worker that not in [project:owner, project:assignee] cannot get project backup. - def test_org_worker_cannot_get_project_backup(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='worker', exclude_privilege='admin') + def test_org_worker_cannot_get_project_backup( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="worker", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - self._test_cannot_get_project_backup(user['username'], project['id'], org_id=project['organization']) + self._test_cannot_get_project_backup( + user["username"], project["id"], org_id=project["organization"] + ) # Org worker that in [project:owner, project:assignee] can get project backup. - def test_org_worker_can_get_project_backup(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='worker', exclude_privilege='admin') + def test_org_worker_can_get_project_backup( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="worker", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - self._test_can_get_project_backup(user['username'], project['id'], org_id=project['organization']) + self._test_can_get_project_backup( + user["username"], project["id"], org_id=project["organization"] + ) # Org supervisor that in [project:owner, project:assignee] can get project backup. - def test_org_supervisor_can_get_project_backup(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='supervisor', exclude_privilege='admin') + def test_org_supervisor_can_get_project_backup( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="supervisor", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - self._test_can_get_project_backup(user['username'], project['id'], org_id=project['organization']) + self._test_can_get_project_backup( + user["username"], project["id"], org_id=project["organization"] + ) # Org supervisor that not in [project:owner, project:assignee] cannot get project backup. - def test_org_supervisor_cannot_get_project_backup(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='supervisor', exclude_privilege='admin') + def test_org_supervisor_cannot_get_project_backup( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="supervisor", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - self._test_cannot_get_project_backup(user['username'], project['id'], org_id=project['organization']) + self._test_cannot_get_project_backup( + user["username"], project["id"], org_id=project["organization"] + ) # Org maintainer that not in [project:owner, project:assignee] can get project backup. - def test_org_maintainer_can_get_project_backup(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='maintainer', exclude_privilege='admin') + def test_org_maintainer_can_get_project_backup( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="maintainer", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - self._test_can_get_project_backup(user['username'], project['id'], org_id=project['organization']) + self._test_can_get_project_backup( + user["username"], project["id"], org_id=project["organization"] + ) # Org owner that not in [project:owner, project:assignee] can get project backup. - def test_org_owner_can_get_project_backup(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='owner', exclude_privilege='admin') + def test_org_owner_can_get_project_backup( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="owner", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) + ) + + self._test_can_get_project_backup( + user["username"], project["id"], org_id=project["organization"] ) - self._test_can_get_project_backup(user['username'], project['id'], org_id=project['organization']) -@pytest.mark.usefixtures('changedb') +@pytest.mark.usefixtures("changedb") class TestPostProjects: def _test_create_project_201(self, user, spec, **kwargs): with make_api_client(user) as api_client: @@ -235,53 +274,48 @@ class TestPostProjects: def _test_create_project_403(self, user, spec, **kwargs): with make_api_client(user) as api_client: - (_, response) = api_client.projects_api.create(spec, **kwargs, - _parse_response=False, _check_status=False) + (_, response) = api_client.projects_api.create( + spec, **kwargs, _parse_response=False, _check_status=False + ) assert response.status == HTTPStatus.FORBIDDEN def test_if_worker_cannot_create_project(self, find_users): - workers = find_users(privilege='worker') + workers = find_users(privilege="worker") assert len(workers) - username = workers[0]['username'] - spec = { - 'name': f'test {username} tries to create a project' - } + username = workers[0]["username"] + spec = {"name": f"test {username} tries to create a project"} self._test_create_project_403(username, spec) - @pytest.mark.parametrize('privilege', ('admin', 'business', 'user')) + @pytest.mark.parametrize("privilege", ("admin", "business", "user")) def test_if_user_can_create_project(self, find_users, privilege): privileged_users = find_users(privilege=privilege) assert len(privileged_users) - username = privileged_users[0]['username'] - spec = { - 'name': f'test {username} tries to create a project' - } + username = privileged_users[0]["username"] + spec = {"name": f"test {username} tries to create a project"} self._test_create_project_201(username, spec) def test_if_user_cannot_have_more_than_3_projects(self, projects, find_users): - users = find_users(privilege='user') + users = find_users(privilege="user") user_id, user_projects = next( (user_id, len(list(projects))) - for user_id, projects in groupby(projects, lambda a: a['owner']['id']) + for user_id, projects in groupby(projects, lambda a: a["owner"]["id"]) if len(list(projects)) < 3 ) user = users[user_id] for i in range(1, 4 - user_projects): spec = { - 'name': f'test: {user["username"]} tries to create a project number {user_projects + i}' + "name": f'test: {user["username"]} tries to create a project number {user_projects + i}' } - self._test_create_project_201(user['username'], spec) + self._test_create_project_201(user["username"], spec) - spec = { - 'name': f'test {user["username"]} tries to create more than 3 projects' - } - self._test_create_project_403(user['username'], spec) + spec = {"name": f'test {user["username"]} tries to create more than 3 projects'} + self._test_create_project_403(user["username"], spec) - @pytest.mark.parametrize('privilege', ('admin', 'business')) + @pytest.mark.parametrize("privilege", ("admin", "business")) def test_if_user_can_have_more_than_3_projects(self, find_users, privilege): privileged_users = find_users(privilege=privilege) assert len(privileged_users) @@ -290,105 +324,111 @@ class TestPostProjects: for i in range(1, 5): spec = { - 'name': f'test: {user["username"]} with privilege {privilege} tries to create a project number {i}' + "name": f'test: {user["username"]} with privilege {privilege} tries to create a project number {i}' } - self._test_create_project_201(user['username'], spec) + self._test_create_project_201(user["username"], spec) def test_if_org_worker_cannot_crate_project(self, find_users): - workers = find_users(role='worker') + workers = find_users(role="worker") - worker = next(u for u in workers if u['org']) + worker = next(u for u in workers if u["org"]) spec = { - 'name': f'test: worker {worker["username"]} creating a project for his organization', + "name": f'test: worker {worker["username"]} creating a project for his organization', } - self._test_create_project_403(worker['username'], spec, org_id=worker['org']) + self._test_create_project_403(worker["username"], spec, org_id=worker["org"]) - @pytest.mark.parametrize('role', ('supervisor', 'maintainer', 'owner')) + @pytest.mark.parametrize("role", ("supervisor", "maintainer", "owner")) def test_if_org_role_can_create_project(self, find_users, role): privileged_users = find_users(role=role) assert len(privileged_users) - user = next(u for u in privileged_users if u['org']) + user = next(u for u in privileged_users if u["org"]) spec = { - 'name': f'test: worker {user["username"]} creating a project for his organization', + "name": f'test: worker {user["username"]} creating a project for his organization', } - self._test_create_project_201(user['username'], spec, org_id=user['org']) + self._test_create_project_201(user["username"], spec, org_id=user["org"]) + @pytest.mark.usefixtures("changedb") class TestImportExportDatasetProject: def _test_export_project(self, username, pid, format_name): with make_api_client(username) as api_client: - return export_dataset(api_client.projects_api.retrieve_dataset_endpoint, - id=pid, format=format_name) + return export_dataset( + api_client.projects_api.retrieve_dataset_endpoint, id=pid, format=format_name + ) def _test_import_project(self, username, project_id, format_name, data): with make_api_client(username) as api_client: - (_, response) = api_client.projects_api.create_dataset(id=project_id, - format=format_name, dataset_write_request=deepcopy(data), - _content_type="multipart/form-data") + (_, response) = api_client.projects_api.create_dataset( + id=project_id, + format=format_name, + dataset_write_request=deepcopy(data), + _content_type="multipart/form-data", + ) assert response.status == HTTPStatus.ACCEPTED while True: # TODO: It's better be refactored to a separate endpoint to get request status - (_, response) = api_client.projects_api.retrieve_dataset(project_id, - action='import_status') + (_, response) = api_client.projects_api.retrieve_dataset( + project_id, action="import_status" + ) if response.status == HTTPStatus.CREATED: break def test_can_import_dataset_in_org(self, admin_user): project_id = 4 - response = self._test_export_project(admin_user, project_id, 'CVAT for images 1.1') + response = self._test_export_project(admin_user, project_id, "CVAT for images 1.1") tmp_file = io.BytesIO(response.data) - tmp_file.name = 'dataset.zip' + tmp_file.name = "dataset.zip" import_data = { - 'dataset_file': tmp_file, + "dataset_file": tmp_file, } - self._test_import_project(admin_user, project_id, 'CVAT 1.1', import_data) + self._test_import_project(admin_user, project_id, "CVAT 1.1", import_data) def test_can_export_and_import_dataset_with_skeletons_coco_keypoints(self, admin_user): project_id = 5 - response = self._test_export_project(admin_user, project_id, 'COCO Keypoints 1.0') + response = self._test_export_project(admin_user, project_id, "COCO Keypoints 1.0") tmp_file = io.BytesIO(response.data) - tmp_file.name = 'dataset.zip' + tmp_file.name = "dataset.zip" import_data = { - 'dataset_file': tmp_file, + "dataset_file": tmp_file, } - self._test_import_project(admin_user, project_id, 'COCO Keypoints 1.0', import_data) + self._test_import_project(admin_user, project_id, "COCO Keypoints 1.0", import_data) def test_can_export_and_import_dataset_with_skeletons_cvat_for_images(self, admin_user): project_id = 5 - response = self._test_export_project(admin_user, project_id, 'CVAT for images 1.1') + response = self._test_export_project(admin_user, project_id, "CVAT for images 1.1") tmp_file = io.BytesIO(response.data) - tmp_file.name = 'dataset.zip' + tmp_file.name = "dataset.zip" import_data = { - 'dataset_file': tmp_file, + "dataset_file": tmp_file, } - self._test_import_project(admin_user, project_id, 'CVAT 1.1', import_data) + self._test_import_project(admin_user, project_id, "CVAT 1.1", import_data) def test_can_export_and_import_dataset_with_skeletons_cvat_for_video(self, admin_user): project_id = 5 - response = self._test_export_project(admin_user, project_id, 'CVAT for video 1.1') + response = self._test_export_project(admin_user, project_id, "CVAT for video 1.1") tmp_file = io.BytesIO(response.data) - tmp_file.name = 'dataset.zip' + tmp_file.name = "dataset.zip" import_data = { - 'dataset_file': tmp_file, + "dataset_file": tmp_file, } - self._test_import_project(admin_user, project_id, 'CVAT 1.1', import_data) + self._test_import_project(admin_user, project_id, "CVAT 1.1", import_data) def _test_can_get_project_backup(self, username, pid, **kwargs): for _ in range(30): @@ -406,130 +446,162 @@ class TestImportExportDatasetProject: response = self._test_can_get_project_backup(admin_user, project_id) tmp_file = io.BytesIO(response.content) - tmp_file.name = 'dataset.zip' + tmp_file.name = "dataset.zip" import_data = { - 'project_file': tmp_file, + "project_file": tmp_file, } with make_api_client(admin_user) as api_client: (_, response) = api_client.projects_api.create_backup( - backup_write_request=deepcopy(import_data), - _content_type="multipart/form-data") + backup_write_request=deepcopy(import_data), _content_type="multipart/form-data" + ) assert response.status == HTTPStatus.ACCEPTED -@pytest.mark.usefixtures('changedb') + +@pytest.mark.usefixtures("changedb") class TestPatchProjectLabel: def test_admin_can_delete_label(self, projects): project = deepcopy(list(projects)[1]) - labels = project['labels'][0] - labels.update({'deleted': True}) - response = patch_method('admin1', f'/projects/{project["id"]}', {'labels': [labels]}) + labels = project["labels"][0] + labels.update({"deleted": True}) + response = patch_method("admin1", f'/projects/{project["id"]}', {"labels": [labels]}) assert response.status_code == HTTPStatus.OK - assert len(response.json()['labels']) == len(project['labels']) - 1 + assert len(response.json()["labels"]) == len(project["labels"]) - 1 def test_admin_can_delete_skeleton_label(self, projects): project = deepcopy(projects[5]) - labels = project['labels'][0] - labels.update({'deleted': True}) - response = patch_method('admin1', f'/projects/{project["id"]}', {'labels': [labels]}) + labels = project["labels"][0] + labels.update({"deleted": True}) + response = patch_method("admin1", f'/projects/{project["id"]}', {"labels": [labels]}) assert response.status_code == HTTPStatus.OK - assert len(response.json()['labels']) == len(project['labels']) - 4 + assert len(response.json()["labels"]) == len(project["labels"]) - 4 def test_admin_can_rename_label(self, projects): project = deepcopy(list(projects)[0]) - labels = project['labels'][0] - labels.update({'name': 'new name'}) - response = patch_method('admin1', f'/projects/{project["id"]}', {'labels': [labels]}) + labels = project["labels"][0] + labels.update({"name": "new name"}) + response = patch_method("admin1", f'/projects/{project["id"]}', {"labels": [labels]}) assert response.status_code == HTTPStatus.OK - assert DeepDiff(response.json()['labels'], project['labels'], ignore_order=True) == {} + assert DeepDiff(response.json()["labels"], project["labels"], ignore_order=True) == {} def test_admin_can_add_label(self, projects): project = list(projects)[0] - labels = {'name': 'new name'} - response = patch_method('admin1', f'/projects/{project["id"]}', {'labels': [labels]}) + labels = {"name": "new name"} + response = patch_method("admin1", f'/projects/{project["id"]}', {"labels": [labels]}) assert response.status_code == HTTPStatus.OK - assert len(response.json()['labels']) == len(project['labels']) + 1 + assert len(response.json()["labels"]) == len(project["labels"]) + 1 # Org maintainer can add label even he is not in [project:owner, project:assignee] - def test_org_maintainer_can_add_label(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='maintainer', exclude_privilege='admin') + def test_org_maintainer_can_add_label( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="maintainer", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - labels = {'name': 'new name'} - response = patch_method(user['username'], f'/projects/{project["id"]}', {'labels': [labels]}, org_id=project['organization']) + labels = {"name": "new name"} + response = patch_method( + user["username"], + f'/projects/{project["id"]}', + {"labels": [labels]}, + org_id=project["organization"], + ) assert response.status_code == HTTPStatus.OK - assert len(response.json()['labels']) == len(project['labels']) + 1 + assert len(response.json()["labels"]) == len(project["labels"]) + 1 # Org supervisor cannot add label - def test_org_supervisor_can_add_label(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='supervisor', exclude_privilege='admin') + def test_org_supervisor_can_add_label( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="supervisor", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - labels = {'name': 'new name'} - response = patch_method(user['username'], f'/projects/{project["id"]}', {'labels': [labels]}, org_id=project['organization']) + labels = {"name": "new name"} + response = patch_method( + user["username"], + f'/projects/{project["id"]}', + {"labels": [labels]}, + org_id=project["organization"], + ) assert response.status_code == HTTPStatus.FORBIDDEN # Org worker cannot add label - def test_org_worker_cannot_add_label(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='worker', exclude_privilege='admin') + def test_org_worker_cannot_add_label( + self, find_users, projects, is_project_staff, is_org_member + ): + users = find_users(role="worker", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - labels = {'name': 'new name'} - response = patch_method(user['username'], f'/projects/{project["id"]}', {'labels': [labels]}, org_id=project['organization']) + labels = {"name": "new name"} + response = patch_method( + user["username"], + f'/projects/{project["id"]}', + {"labels": [labels]}, + org_id=project["organization"], + ) assert response.status_code == HTTPStatus.FORBIDDEN # Org worker that in [project:owner, project:assignee] can add label def test_org_worker_can_add_label(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='worker', exclude_privilege='admin') + users = find_users(role="worker", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - labels = {'name': 'new name'} - response = patch_method(user['username'], f'/projects/{project["id"]}', {'labels': [labels]}, org_id=project['organization']) + labels = {"name": "new name"} + response = patch_method( + user["username"], + f'/projects/{project["id"]}', + {"labels": [labels]}, + org_id=project["organization"], + ) assert response.status_code == HTTPStatus.OK - assert len(response.json()['labels']) == len(project['labels']) + 1 + assert len(response.json()["labels"]) == len(project["labels"]) + 1 # Org owner can add label even he is not in [project:owner, project:assignee] def test_org_owner_can_add_label(self, find_users, projects, is_project_staff, is_org_member): - users = find_users(role='owner', exclude_privilege='admin') + users = find_users(role="owner", exclude_privilege="admin") user, project = next( (user, project) for user, project in product(users, projects) - if not is_project_staff(user['id'], project['id']) - and project['organization'] - and is_org_member(user['id'], project['organization']) + if not is_project_staff(user["id"], project["id"]) + and project["organization"] + and is_org_member(user["id"], project["organization"]) ) - labels = {'name': 'new name'} - response = patch_method(user['username'], f'/projects/{project["id"]}', {'labels': [labels]}, org_id=project['organization']) + labels = {"name": "new name"} + response = patch_method( + user["username"], + f'/projects/{project["id"]}', + {"labels": [labels]}, + org_id=project["organization"], + ) assert response.status_code == HTTPStatus.OK - assert len(response.json()['labels']) == len(project['labels']) + 1 + assert len(response.json()["labels"]) == len(project["labels"]) + 1 diff --git a/tests/python/rest_api/test_remote_url.py b/tests/python/rest_api/test_remote_url.py index 7c87299a..459ce371 100644 --- a/tests/python/rest_api/test_remote_url.py +++ b/tests/python/rest_api/test_remote_url.py @@ -13,34 +13,36 @@ from shared.utils.config import get_method, post_method def _post_task_remote_data(username, task_id, resources): data = { - 'remote_files': resources, - 'image_quality': 30, + "remote_files": resources, + "image_quality": 30, } - return post_method(username, f'tasks/{task_id}/data', data) + return post_method(username, f"tasks/{task_id}/data", data) + def _wait_until_task_is_created(username, task_id): - url = f'tasks/{task_id}/status' + url = f"tasks/{task_id}/status" for _ in range(100): response = get_method(username, url) response_json = response.json() - if response_json['state'] == 'Finished' or response_json['state'] == 'Failed': + if response_json["state"] == "Finished" or response_json["state"] == "Failed": return response sleep(1) - raise Exception('Cannot create task') + raise Exception("Cannot create task") -@pytest.mark.usefixtures('changedb') +@pytest.mark.usefixtures("changedb") class TestCreateFromRemote: task_id = 12 + def _test_can_create(self, user, task_id, resources): response = _post_task_remote_data(user, task_id, resources) assert response.status_code == HTTPStatus.ACCEPTED response = _wait_until_task_is_created(user, task_id) response_json = response.json() - assert response_json['state'] == 'Finished' + assert response_json["state"] == "Finished" def _test_cannot_create(self, user, task_id, resources): response = _post_task_remote_data(user, task_id, resources) @@ -48,16 +50,16 @@ class TestCreateFromRemote: response = _wait_until_task_is_created(user, task_id) response_json = response.json() - assert response_json['state'] == 'Failed' + assert response_json["state"] == "Failed" def test_cannot_create(self, find_users): - user = find_users(privilege='admin')[0]['username'] - remote_resources = ['http://localhost/favicon.ico'] + user = find_users(privilege="admin")[0]["username"] + remote_resources = ["http://localhost/favicon.ico"] self._test_cannot_create(user, self.task_id, remote_resources) def test_can_create(self, find_users): - user = find_users(privilege='admin')[0]['username'] - remote_resources = ['https://opencv.github.io/cvat/favicons/favicon-32x32.png'] + user = find_users(privilege="admin")[0]["username"] + remote_resources = ["https://opencv.github.io/cvat/favicons/favicon-32x32.png"] self._test_can_create(user, self.task_id, remote_resources) diff --git a/tests/python/rest_api/test_resource_import_export.py b/tests/python/rest_api/test_resource_import_export.py index 77ec8051..5424b640 100644 --- a/tests/python/rest_api/test_resource_import_export.py +++ b/tests/python/rest_api/test_resource_import_export.py @@ -3,64 +3,74 @@ # # SPDX-License-Identifier: MIT -import pytest -import boto3 import functools import json +from http import HTTPStatus +import boto3 +import pytest from botocore.exceptions import ClientError -from http import HTTPStatus from shared.utils.config import ( - get_method, post_method, MINIO_KEY, MINIO_SECRET_KEY, MINIO_ENDPOINT_URL, + MINIO_ENDPOINT_URL, + MINIO_KEY, + MINIO_SECRET_KEY, + get_method, + post_method, ) -FILENAME_TEMPLATE = 'cvat/{}/{}.zip' -FORMAT = 'COCO 1.0' +FILENAME_TEMPLATE = "cvat/{}/{}.zip" +FORMAT = "COCO 1.0" + def _use_custom_settings(obj, resource, cloud_storage_id): return { - 'filename': FILENAME_TEMPLATE.format(obj, resource), - 'use_default_location': False, - 'location': 'cloud_storage', - 'cloud_storage_id': cloud_storage_id, - 'format': FORMAT, + "filename": FILENAME_TEMPLATE.format(obj, resource), + "use_default_location": False, + "location": "cloud_storage", + "cloud_storage_id": cloud_storage_id, + "format": FORMAT, } + def _use_default_settings(obj, resource): return { - 'filename': FILENAME_TEMPLATE.format(obj, resource), - 'use_default_location': True, - 'format': FORMAT, + "filename": FILENAME_TEMPLATE.format(obj, resource), + "use_default_location": True, + "format": FORMAT, } + def define_client(): s3 = boto3.resource( - 's3', + "s3", aws_access_key_id=MINIO_KEY, aws_secret_access_key=MINIO_SECRET_KEY, - endpoint_url= MINIO_ENDPOINT_URL, + endpoint_url=MINIO_ENDPOINT_URL, ) return s3.meta.client + def assert_file_does_not_exist(client, bucket, filename): try: client.head_object(Bucket=bucket, Key=filename) - raise AssertionError(f'File {filename} on bucket {bucket} already exists') + raise AssertionError(f"File {filename} on bucket {bucket} already exists") except ClientError: pass + def assert_file_exists(client, bucket, filename): try: client.head_object(Bucket=bucket, Key=filename) except ClientError: raise AssertionError(f"File {filename} on bucket {bucket} doesn't exist") + def assert_file_status(func): @functools.wraps(func) def wrapper(user, storage_conf, *args, **kwargs): - filename = kwargs['filename'] - bucket = storage_conf['resource'] + filename = kwargs["filename"] + bucket = storage_conf["resource"] # get storage client client = define_client() # check that file doesn't exist on the bucket @@ -68,88 +78,109 @@ def assert_file_status(func): func(user, storage_conf, *args, **kwargs) # check that file exists on the bucket assert_file_exists(client, bucket, filename) + return wrapper + def remove_asset(bucket, filename): client = define_client() client.delete_object(Bucket=bucket, Key=filename) + @assert_file_status def _save_resource_to_cloud_storage(user, storage_conf, obj_id, obj, resource, **kwargs): - response = get_method(user, f'{obj}/{obj_id}/{resource}', **kwargs) + response = get_method(user, f"{obj}/{obj_id}/{resource}", **kwargs) status = response.status_code while status != HTTPStatus.OK: assert status in (HTTPStatus.CREATED, HTTPStatus.ACCEPTED) - response = get_method(user, f'{obj}/{obj_id}/{resource}', action='download', **kwargs) + response = get_method(user, f"{obj}/{obj_id}/{resource}", action="download", **kwargs) status = response.status_code + def _idempotent_saving_resource_to_cloud_storage(*args, **kwargs): _save_resource_to_cloud_storage(*args, **kwargs) - remove_asset(args[1]['resource'], kwargs['filename']) + remove_asset(args[1]["resource"], kwargs["filename"]) + -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestSaveResource: - _USERNAME = 'admin1' + _USERNAME = "admin1" _ORG = 2 - @pytest.mark.parametrize('cloud_storage_id', [3]) - @pytest.mark.parametrize('obj_id, obj, resource', [ - (2, 'projects', 'annotations'), - (2, 'projects', 'dataset'), - (2, 'projects', 'backup'), - (11, 'tasks', 'annotations'), - (11, 'tasks', 'dataset'), - (11, 'tasks', 'backup'), - (16, 'jobs', 'annotations'), - (16, 'jobs', 'dataset'), - ]) + @pytest.mark.parametrize("cloud_storage_id", [3]) + @pytest.mark.parametrize( + "obj_id, obj, resource", + [ + (2, "projects", "annotations"), + (2, "projects", "dataset"), + (2, "projects", "backup"), + (11, "tasks", "annotations"), + (11, "tasks", "dataset"), + (11, "tasks", "backup"), + (16, "jobs", "annotations"), + (16, "jobs", "dataset"), + ], + ) def test_save_resource_to_cloud_storage_with_specific_location( self, cloud_storage_id, obj_id, obj, resource, cloud_storages ): cloud_storage = cloud_storages[cloud_storage_id] kwargs = _use_custom_settings(obj, resource, cloud_storage_id) - if resource == 'backup': - kwargs.pop('format') - - _idempotent_saving_resource_to_cloud_storage(self._USERNAME, cloud_storage, - obj_id, obj, resource, org_id=self._ORG, **kwargs) - - @pytest.mark.parametrize('obj_id, obj, resource', [ - (2, 'projects', 'annotations'), - (2, 'projects', 'dataset'), - (2, 'projects', 'backup'), - (11, 'tasks', 'annotations'), - (11, 'tasks', 'dataset'), - (11, 'tasks', 'backup'), - (16, 'jobs', 'annotations'), - (16, 'jobs', 'dataset'), - ]) + if resource == "backup": + kwargs.pop("format") + + _idempotent_saving_resource_to_cloud_storage( + self._USERNAME, cloud_storage, obj_id, obj, resource, org_id=self._ORG, **kwargs + ) + + @pytest.mark.parametrize( + "obj_id, obj, resource", + [ + (2, "projects", "annotations"), + (2, "projects", "dataset"), + (2, "projects", "backup"), + (11, "tasks", "annotations"), + (11, "tasks", "dataset"), + (11, "tasks", "backup"), + (16, "jobs", "annotations"), + (16, "jobs", "dataset"), + ], + ) def test_save_resource_to_cloud_storage_with_default_location( - self, obj_id, obj, resource, projects, tasks, jobs, cloud_storages, + self, + obj_id, + obj, + resource, + projects, + tasks, + jobs, + cloud_storages, ): objects = { - 'projects': projects, - 'tasks': tasks, - 'jobs': jobs, + "projects": projects, + "tasks": tasks, + "jobs": jobs, } - if obj in ('projects', 'tasks'): - cloud_storage_id = objects[obj][obj_id]['target_storage']['cloud_storage_id'] + if obj in ("projects", "tasks"): + cloud_storage_id = objects[obj][obj_id]["target_storage"]["cloud_storage_id"] else: - task_id = jobs[obj_id]['task_id'] - cloud_storage_id = tasks[task_id]['target_storage']['cloud_storage_id'] + task_id = jobs[obj_id]["task_id"] + cloud_storage_id = tasks[task_id]["target_storage"]["cloud_storage_id"] cloud_storage = cloud_storages[cloud_storage_id] kwargs = _use_default_settings(obj, resource) - if resource == 'backup': - kwargs.pop('format') + if resource == "backup": + kwargs.pop("format") + + _idempotent_saving_resource_to_cloud_storage( + self._USERNAME, cloud_storage, obj_id, obj, resource, org_id=self._ORG, **kwargs + ) - _idempotent_saving_resource_to_cloud_storage(self._USERNAME, cloud_storage, - obj_id, obj, resource, org_id=self._ORG, **kwargs) def _import_annotations_from_cloud_storage(user, obj_id, obj, **kwargs): - url = f'{obj}/{obj_id}/annotations' + url = f"{obj}/{obj_id}/annotations" response = post_method(user, url, data=None, **kwargs) status = response.status_code @@ -158,41 +189,47 @@ def _import_annotations_from_cloud_storage(user, obj_id, obj, **kwargs): response = post_method(user, url, data=None, **kwargs) status = response.status_code + def _import_backup_from_cloud_storage(user, obj_id, obj, **kwargs): - url = f'{obj}/backup' + url = f"{obj}/backup" response = post_method(user, url, data=None, **kwargs) status = response.status_code while status != HTTPStatus.CREATED: assert status == HTTPStatus.ACCEPTED - data = json.loads(response.content.decode('utf8')) + data = json.loads(response.content.decode("utf8")) response = post_method(user, url, data=data, **kwargs) status = response.status_code + def _import_dataset_from_cloud_storage(user, obj_id, obj, **kwargs): - url = f'{obj}/{obj_id}/dataset' + url = f"{obj}/{obj_id}/dataset" response = post_method(user, url, data=None, **kwargs) status = response.status_code while status != HTTPStatus.CREATED: assert status == HTTPStatus.ACCEPTED - response = get_method(user, url, action='import_status') + response = get_method(user, url, action="import_status") status = response.status_code -@pytest.mark.usefixtures('changedb') -@pytest.mark.usefixtures('restore_cvat_data') + +@pytest.mark.usefixtures("changedb") +@pytest.mark.usefixtures("restore_cvat_data") class TestImportResource: - _USERNAME = 'admin1' + _USERNAME = "admin1" _ORG = 2 - @pytest.mark.parametrize('cloud_storage_id', [3]) - @pytest.mark.parametrize('obj_id, obj, resource', [ - (2, 'projects', 'dataset'), - (2, 'projects', 'backup'), - (11, 'tasks', 'annotations'), - (11, 'tasks', 'backup'), - (16, 'jobs', 'annotations'), - ]) + @pytest.mark.parametrize("cloud_storage_id", [3]) + @pytest.mark.parametrize( + "obj_id, obj, resource", + [ + (2, "projects", "dataset"), + (2, "projects", "backup"), + (11, "tasks", "annotations"), + (11, "tasks", "backup"), + (16, "jobs", "annotations"), + ], + ) def test_import_resource_from_cloud_storage_with_specific_location( self, cloud_storage_id, obj_id, obj, resource, cloud_storages ): @@ -200,50 +237,64 @@ class TestImportResource: kwargs = _use_custom_settings(obj, resource, cloud_storage_id) export_kwargs = _use_custom_settings(obj, resource, cloud_storage_id) - if resource == 'backup': - kwargs.pop('format') - kwargs.pop('use_default_location') - export_kwargs.pop('format') + if resource == "backup": + kwargs.pop("format") + kwargs.pop("use_default_location") + export_kwargs.pop("format") # export current resource to cloud storage - _save_resource_to_cloud_storage(self._USERNAME, cloud_storage, obj_id, obj, resource, org_id=self._ORG, **export_kwargs) + _save_resource_to_cloud_storage( + self._USERNAME, cloud_storage, obj_id, obj, resource, org_id=self._ORG, **export_kwargs + ) import_resource = { - 'annotations': _import_annotations_from_cloud_storage, - 'dataset': _import_dataset_from_cloud_storage, - 'backup': _import_backup_from_cloud_storage, + "annotations": _import_annotations_from_cloud_storage, + "dataset": _import_dataset_from_cloud_storage, + "backup": _import_backup_from_cloud_storage, } import_resource[resource](self._USERNAME, obj_id, obj, org_id=self._ORG, **kwargs) - remove_asset(cloud_storage['resource'], kwargs['filename']) - - @pytest.mark.parametrize('obj_id, obj, resource', [ - (2, 'projects', 'dataset'), - (11, 'tasks', 'annotations'), - (16, 'jobs', 'annotations'), - ]) + remove_asset(cloud_storage["resource"], kwargs["filename"]) + + @pytest.mark.parametrize( + "obj_id, obj, resource", + [ + (2, "projects", "dataset"), + (11, "tasks", "annotations"), + (16, "jobs", "annotations"), + ], + ) def test_import_resource_from_cloud_storage_with_default_location( - self, obj_id, obj, resource, projects, tasks, jobs, cloud_storages, + self, + obj_id, + obj, + resource, + projects, + tasks, + jobs, + cloud_storages, ): objects = { - 'projects': projects, - 'tasks': tasks, - 'jobs': jobs, + "projects": projects, + "tasks": tasks, + "jobs": jobs, } - if obj in ('projects', 'tasks'): - cloud_storage_id = objects[obj][obj_id]['source_storage']['cloud_storage_id'] + if obj in ("projects", "tasks"): + cloud_storage_id = objects[obj][obj_id]["source_storage"]["cloud_storage_id"] else: - task_id = jobs[obj_id]['task_id'] - cloud_storage_id = tasks[task_id]['source_storage']['cloud_storage_id'] + task_id = jobs[obj_id]["task_id"] + cloud_storage_id = tasks[task_id]["source_storage"]["cloud_storage_id"] cloud_storage = cloud_storages[cloud_storage_id] kwargs = _use_default_settings(obj, resource) # export current resource to cloud storage - _save_resource_to_cloud_storage(self._USERNAME, cloud_storage, obj_id, obj, resource, org_id=self._ORG, **kwargs) + _save_resource_to_cloud_storage( + self._USERNAME, cloud_storage, obj_id, obj, resource, org_id=self._ORG, **kwargs + ) import_resource = { - 'annotations': _import_annotations_from_cloud_storage, - 'dataset': _import_dataset_from_cloud_storage, - 'backup': _import_backup_from_cloud_storage, + "annotations": _import_annotations_from_cloud_storage, + "dataset": _import_dataset_from_cloud_storage, + "backup": _import_backup_from_cloud_storage, } import_resource[resource](self._USERNAME, obj_id, obj, org_id=self._ORG, **kwargs) - remove_asset(cloud_storage['resource'], kwargs['filename']) + remove_asset(cloud_storage["resource"], kwargs["filename"]) diff --git a/tests/python/rest_api/test_server.py b/tests/python/rest_api/test_server.py index d677f21d..d5f1b807 100644 --- a/tests/python/rest_api/test_server.py +++ b/tests/python/rest_api/test_server.py @@ -4,11 +4,13 @@ from http import HTTPStatus + import pytest + from shared.utils.config import make_api_client -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetServer: def test_can_retrieve_about_unauthorized(self): with make_api_client(user=None, password=None) as api_client: @@ -26,7 +28,7 @@ class TestGetServer: assert len(data.exporters) != 0 -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetSchema: def test_can_get_schema_unauthorized(self): with make_api_client(user=None, password=None) as api_client: diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 4f017e18..5c30d364 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -7,107 +7,142 @@ import json from copy import deepcopy from http import HTTPStatus from time import sleep -from cvat_sdk.api_client import models, apis -from cvat_sdk.core.helpers import get_paginated_collection import pytest +from cvat_sdk.api_client import apis, models +from cvat_sdk.core.helpers import get_paginated_collection from deepdiff import DeepDiff from shared.utils.config import get_method, make_api_client, patch_method from shared.utils.helpers import generate_image_files + from .utils import export_dataset + def get_cloud_storage_content(username, cloud_storage_id, manifest): with make_api_client(username) as api_client: - (data, _) = api_client.cloudstorages_api.retrieve_content(cloud_storage_id, - manifest_path=manifest) + (data, _) = api_client.cloudstorages_api.retrieve_content( + cloud_storage_id, manifest_path=manifest + ) return data -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetTasks: - def _test_task_list_200(self, user, project_id, data, exclude_paths = '', **kwargs): + def _test_task_list_200(self, user, project_id, data, exclude_paths="", **kwargs): with make_api_client(user) as api_client: - results = get_paginated_collection(api_client.projects_api.list_tasks_endpoint, - return_json=True, id=project_id, **kwargs) + results = get_paginated_collection( + api_client.projects_api.list_tasks_endpoint, + return_json=True, + id=project_id, + **kwargs, + ) assert DeepDiff(data, results, ignore_order=True, exclude_paths=exclude_paths) == {} def _test_task_list_403(self, user, project_id, **kwargs): with make_api_client(user) as api_client: - (_, response) = api_client.projects_api.list_tasks(project_id, **kwargs, - _parse_response=False, _check_status=False) + (_, response) = api_client.projects_api.list_tasks( + project_id, **kwargs, _parse_response=False, _check_status=False + ) assert response.status == HTTPStatus.FORBIDDEN - def _test_users_to_see_task_list(self, project_id, tasks, users, is_staff, is_allow, is_project_staff, **kwargs): + def _test_users_to_see_task_list( + self, project_id, tasks, users, is_staff, is_allow, is_project_staff, **kwargs + ): if is_staff: - users = [user for user in users if is_project_staff(user['id'], project_id) ] + users = [user for user in users if is_project_staff(user["id"], project_id)] else: - users = [user for user in users if not is_project_staff(user['id'], project_id)] + users = [user for user in users if not is_project_staff(user["id"], project_id)] assert len(users) for user in users: if is_allow: - self._test_task_list_200(user['username'], project_id, tasks, **kwargs) + self._test_task_list_200(user["username"], project_id, tasks, **kwargs) else: - self._test_task_list_403(user['username'], project_id, **kwargs) + self._test_task_list_403(user["username"], project_id, **kwargs) def _test_assigned_users_to_see_task_data(self, tasks, users, is_task_staff, **kwargs): for task in tasks: - staff_users = [user for user in users if is_task_staff(user['id'], task['id'])] + staff_users = [user for user in users if is_task_staff(user["id"], task["id"])] assert len(staff_users) for user in staff_users: - with make_api_client(user['username']) as api_client: + with make_api_client(user["username"]) as api_client: (_, response) = api_client.tasks_api.list(**kwargs) assert response.status == HTTPStatus.OK response_data = json.loads(response.data) - assert any(_task['id'] == task['id'] for _task in response_data['results']) - - @pytest.mark.parametrize('project_id', [1]) - @pytest.mark.parametrize('groups, is_staff, is_allow', [ - ('admin', False, True), - ('business', False, False), - ]) - def test_project_tasks_visibility(self, project_id, groups, users, tasks, is_staff, is_allow, find_users, is_project_staff): + assert any(_task["id"] == task["id"] for _task in response_data["results"]) + + @pytest.mark.parametrize("project_id", [1]) + @pytest.mark.parametrize( + "groups, is_staff, is_allow", + [ + ("admin", False, True), + ("business", False, False), + ], + ) + def test_project_tasks_visibility( + self, project_id, groups, users, tasks, is_staff, is_allow, find_users, is_project_staff + ): users = find_users(privilege=groups) - tasks = list(filter(lambda x: x['project_id'] == project_id, tasks)) + tasks = list(filter(lambda x: x["project_id"] == project_id, tasks)) assert len(tasks) - self._test_users_to_see_task_list(project_id, tasks, users, is_staff, is_allow, is_project_staff) + self._test_users_to_see_task_list( + project_id, tasks, users, is_staff, is_allow, is_project_staff + ) - @pytest.mark.parametrize('project_id, groups', [(1, 'user')]) - def test_task_assigned_to_see_task(self, project_id, groups, users, tasks, find_users, is_task_staff): + @pytest.mark.parametrize("project_id, groups", [(1, "user")]) + def test_task_assigned_to_see_task( + self, project_id, groups, users, tasks, find_users, is_task_staff + ): users = find_users(privilege=groups) - tasks = list(filter(lambda x: x['project_id'] == project_id and x['assignee'], tasks)) + tasks = list(filter(lambda x: x["project_id"] == project_id and x["assignee"], tasks)) assert len(tasks) self._test_assigned_users_to_see_task_data(tasks, users, is_task_staff) - @pytest.mark.parametrize('org, project_id', [({'id': 2, 'slug': 'org2'}, 2)]) - @pytest.mark.parametrize('role, is_staff, is_allow', [ - ('maintainer', False, True), - ('supervisor', False, False), - ]) - def test_org_project_tasks_visibility(self, org, project_id, role, is_staff, is_allow, tasks, is_task_staff, is_project_staff, find_users): - users = find_users(org=org['id'], role=role) - tasks = list(filter(lambda x: x['project_id'] == project_id, tasks)) + @pytest.mark.parametrize("org, project_id", [({"id": 2, "slug": "org2"}, 2)]) + @pytest.mark.parametrize( + "role, is_staff, is_allow", + [ + ("maintainer", False, True), + ("supervisor", False, False), + ], + ) + def test_org_project_tasks_visibility( + self, + org, + project_id, + role, + is_staff, + is_allow, + tasks, + is_task_staff, + is_project_staff, + find_users, + ): + users = find_users(org=org["id"], role=role) + tasks = list(filter(lambda x: x["project_id"] == project_id, tasks)) assert len(tasks) - self._test_users_to_see_task_list(project_id, tasks, users, is_staff, is_allow, is_project_staff, org=org['slug']) + self._test_users_to_see_task_list( + project_id, tasks, users, is_staff, is_allow, is_project_staff, org=org["slug"] + ) - @pytest.mark.parametrize('org, project_id, role', [ - ({'id': 2, 'slug': 'org2'}, 2, 'worker') - ]) - def test_org_task_assigneed_to_see_task(self, org, project_id, role, users, tasks, find_users, is_task_staff): - users = find_users(org=org['id'], role=role) - tasks = list(filter(lambda x: x['project_id'] == project_id and x['assignee'], tasks)) + @pytest.mark.parametrize("org, project_id, role", [({"id": 2, "slug": "org2"}, 2, "worker")]) + def test_org_task_assigneed_to_see_task( + self, org, project_id, role, users, tasks, find_users, is_task_staff + ): + users = find_users(org=org["id"], role=role) + tasks = list(filter(lambda x: x["project_id"] == project_id and x["assignee"], tasks)) assert len(tasks) - self._test_assigned_users_to_see_task_data(tasks, users, is_task_staff, org=org['slug']) + self._test_assigned_users_to_see_task_data(tasks, users, is_task_staff, org=org["slug"]) -@pytest.mark.usefixtures('changedb') +@pytest.mark.usefixtures("changedb") class TestPostTasks: def _test_create_task_201(self, user, spec, **kwargs): with make_api_client(user) as api_client: @@ -116,22 +151,25 @@ class TestPostTasks: def _test_create_task_403(self, user, spec, **kwargs): with make_api_client(user) as api_client: - (_, response) = api_client.tasks_api.create(spec, **kwargs, - _parse_response=False, _check_status=False) + (_, response) = api_client.tasks_api.create( + spec, **kwargs, _parse_response=False, _check_status=False + ) assert response.status == HTTPStatus.FORBIDDEN - def _test_users_to_create_task_in_project(self, project_id, users, is_staff, is_allow, is_project_staff, **kwargs): + def _test_users_to_create_task_in_project( + self, project_id, users, is_staff, is_allow, is_project_staff, **kwargs + ): if is_staff: - users = [user for user in users if is_project_staff(user['id'], project_id) ] + users = [user for user in users if is_project_staff(user["id"], project_id)] else: - users = [user for user in users if not is_project_staff(user['id'], project_id)] + users = [user for user in users if not is_project_staff(user["id"], project_id)] assert len(users) for user in users: - username = user['username'] + username = user["username"] spec = { - 'name': f'test {username} to create a task within a project', - 'project_id': project_id, + "name": f"test {username} to create a task within a project", + "project_id": project_id, } if is_allow: @@ -139,139 +177,159 @@ class TestPostTasks: else: self._test_create_task_403(username, spec, **kwargs) - @pytest.mark.parametrize('project_id', [1]) - @pytest.mark.parametrize('groups, is_staff, is_allow', [ - ('admin', False, True), - ('business', False, False), - ('user', True, True), - ]) - def test_users_to_create_task_in_project(self, project_id, groups, is_staff, is_allow, is_project_staff, find_users): + @pytest.mark.parametrize("project_id", [1]) + @pytest.mark.parametrize( + "groups, is_staff, is_allow", + [ + ("admin", False, True), + ("business", False, False), + ("user", True, True), + ], + ) + def test_users_to_create_task_in_project( + self, project_id, groups, is_staff, is_allow, is_project_staff, find_users + ): users = find_users(privilege=groups) - self._test_users_to_create_task_in_project(project_id, users, is_staff, is_allow, is_project_staff) - - @pytest.mark.parametrize('org, project_id', [({'id': 2, 'slug': 'org2'}, 2)]) - @pytest.mark.parametrize('role, is_staff, is_allow', [ - ('worker', False, False), - ]) - def test_worker_cannot_create_task_in_project_without_ownership(self, org, project_id, role, is_staff, is_allow, is_project_staff, find_users): - users = find_users(org=org['id'], role=role) - self._test_users_to_create_task_in_project(project_id, users, is_staff, is_allow, is_project_staff, org=org['slug']) + self._test_users_to_create_task_in_project( + project_id, users, is_staff, is_allow, is_project_staff + ) + + @pytest.mark.parametrize("org, project_id", [({"id": 2, "slug": "org2"}, 2)]) + @pytest.mark.parametrize( + "role, is_staff, is_allow", + [ + ("worker", False, False), + ], + ) + def test_worker_cannot_create_task_in_project_without_ownership( + self, org, project_id, role, is_staff, is_allow, is_project_staff, find_users + ): + users = find_users(org=org["id"], role=role) + self._test_users_to_create_task_in_project( + project_id, users, is_staff, is_allow, is_project_staff, org=org["slug"] + ) def test_can_create_task_with_skeleton(self): username = "admin1" spec = { - "name": f'test admin1 to create a task with skeleton', + "name": f"test admin1 to create a task with skeleton", "labels": [ { - "name": "s1", - "color": "#5c5eba", - "attributes": [ - { - "name": "color", - "mutable": False, - "input_type": "select", - "default_value": "white", - "values": [ - "white", - "black" - ] - } - ], - "type": "skeleton", - "sublabels": [ - { - "name": "1", - "color": "#d53957", + "name": "s1", + "color": "#5c5eba", "attributes": [ { - "id": 23, - "name": "attr", - "mutable": False, - "input_type": "select", - "default_value": "val1", - "values": [ - "val1", - "val2" - ] + "name": "color", + "mutable": False, + "input_type": "select", + "default_value": "white", + "values": ["white", "black"], } ], - "type": "points" - }, - { - "name": "2", - "color": "#4925ec", - "attributes": [], - "type": "points" - }, - { - "name": "3", - "color": "#59a8fe", - "attributes": [], - "type": "points" - } - ], - "svg": "" \ - "" \ - "" \ - "" \ - "" + "type": "skeleton", + "sublabels": [ + { + "name": "1", + "color": "#d53957", + "attributes": [ + { + "id": 23, + "name": "attr", + "mutable": False, + "input_type": "select", + "default_value": "val1", + "values": ["val1", "val2"], + } + ], + "type": "points", + }, + {"name": "2", "color": "#4925ec", "attributes": [], "type": "points"}, + {"name": "3", "color": "#59a8fe", "attributes": [], "type": "points"}, + ], + "svg": '' + '' + '' + '' + '', } - ] + ], } self._test_create_task_201(username, spec) -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetData: - _USERNAME = 'user1' - - @pytest.mark.parametrize('content_type, task_id', [ - ('image/png', 8), - ('image/png', 5), - ('image/x.point-cloud-data', 6), - ]) + _USERNAME = "user1" + + @pytest.mark.parametrize( + "content_type, task_id", + [ + ("image/png", 8), + ("image/png", 5), + ("image/x.point-cloud-data", 6), + ], + ) def test_frame_content_type(self, content_type, task_id): with make_api_client(self._USERNAME) as api_client: - (_, response) = api_client.tasks_api.retrieve_data(task_id, - type='frame', quality='original', number=0) + (_, response) = api_client.tasks_api.retrieve_data( + task_id, type="frame", quality="original", number=0 + ) assert response.status == HTTPStatus.OK - assert response.headers['Content-Type'] == content_type + assert response.headers["Content-Type"] == content_type + -@pytest.mark.usefixtures('changedb') +@pytest.mark.usefixtures("changedb") class TestPatchTaskAnnotations: def _test_check_response(self, is_allow, response, data=None): if is_allow: assert response.status == HTTPStatus.OK - assert DeepDiff(data, json.loads(response.data), - exclude_paths="root['version']") == {} + assert DeepDiff(data, json.loads(response.data), exclude_paths="root['version']") == {} else: assert response.status == HTTPStatus.FORBIDDEN - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def request_data(self, annotations): def get_data(tid): - data = deepcopy(annotations['task'][str(tid)]) - data['shapes'][0].update({'points': [2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}) - data['version'] += 1 + data = deepcopy(annotations["task"][str(tid)]) + data["shapes"][0].update({"points": [2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}) + data["version"] += 1 return data + return get_data - @pytest.mark.parametrize('org', ['']) - @pytest.mark.parametrize('privilege, task_staff, is_allow', [ - ('admin', True, True), ('admin', False, True), - ('business', True, True), ('business', False, False), - ('worker', True, True), ('worker', False, False), - ('user', True, True), ('user', False, False) - ]) - def test_user_update_task_annotations(self, org, privilege, task_staff, is_allow, - find_task_staff_user, find_users, request_data, tasks_by_org, filter_tasks_with_shapes): + @pytest.mark.parametrize("org", [""]) + @pytest.mark.parametrize( + "privilege, task_staff, is_allow", + [ + ("admin", True, True), + ("admin", False, True), + ("business", True, True), + ("business", False, False), + ("worker", True, True), + ("worker", False, False), + ("user", True, True), + ("user", False, False), + ], + ) + def test_user_update_task_annotations( + self, + org, + privilege, + task_staff, + is_allow, + find_task_staff_user, + find_users, + request_data, + tasks_by_org, + filter_tasks_with_shapes, + ): users = find_users(privilege=privilege) tasks = tasks_by_org[org] filtered_tasks = filter_tasks_with_shapes(tasks) @@ -280,21 +338,41 @@ class TestPatchTaskAnnotations: data = request_data(tid) with make_api_client(username) as api_client: (_, response) = api_client.tasks_api.partial_update_annotations( - id=tid, action='update', org=org, + id=tid, + action="update", + org=org, patched_labeled_data_request=deepcopy(data), - _parse_response=False, _check_status=False) + _parse_response=False, + _check_status=False, + ) self._test_check_response(is_allow, response, data) - @pytest.mark.parametrize('org', [2]) - @pytest.mark.parametrize('role, task_staff, is_allow', [ - ('maintainer', False, True), ('owner', False, True), - ('supervisor', False, False), ('worker', False, False), - ('maintainer', True, True), ('owner', True, True), - ('supervisor', True, True), ('worker', True, True) - ]) - def test_member_update_task_annotation(self, org, role, task_staff, is_allow, - find_task_staff_user, find_users, tasks_by_org, request_data): + @pytest.mark.parametrize("org", [2]) + @pytest.mark.parametrize( + "role, task_staff, is_allow", + [ + ("maintainer", False, True), + ("owner", False, True), + ("supervisor", False, False), + ("worker", False, False), + ("maintainer", True, True), + ("owner", True, True), + ("supervisor", True, True), + ("worker", True, True), + ], + ) + def test_member_update_task_annotation( + self, + org, + role, + task_staff, + is_allow, + find_task_staff_user, + find_users, + tasks_by_org, + request_data, + ): users = find_users(role=role, org=org) tasks = tasks_by_org[org] username, tid = find_task_staff_user(tasks, users, task_staff, [14]) @@ -302,13 +380,18 @@ class TestPatchTaskAnnotations: data = request_data(tid) with make_api_client(username) as api_client: (_, response) = api_client.tasks_api.partial_update_annotations( - id=tid, org_id=org, action='update', + id=tid, + org_id=org, + action="update", patched_labeled_data_request=deepcopy(data), - _parse_response=False, _check_status=False) + _parse_response=False, + _check_status=False, + ) self._test_check_response(is_allow, response, data) -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestGetTaskDataset: def _test_export_task(self, username, tid, **kwargs): with make_api_client(username) as api_client: @@ -316,64 +399,69 @@ class TestGetTaskDataset: def test_can_export_task_dataset(self, admin_user, tasks_with_shapes): task = tasks_with_shapes[0] - response = self._test_export_task(admin_user, task['id'], format='CVAT for images 1.1') + response = self._test_export_task(admin_user, task["id"], format="CVAT for images 1.1") assert response.data + @pytest.mark.usefixtures("changedb") @pytest.mark.usefixtures("restore_cvat_data") class TestPostTaskData: - _USERNAME = 'admin1' + _USERNAME = "admin1" @staticmethod def _wait_until_task_is_created(api: apis.TasksApi, task_id: int) -> models.RqStatus: for _ in range(100): (status, _) = api.retrieve_status(task_id) - if status.state.value in ['Finished', 'Failed']: + if status.state.value in ["Finished", "Failed"]: return status sleep(1) - raise Exception('Cannot create task') + raise Exception("Cannot create task") def _test_create_task(self, username, spec, data, content_type, **kwargs): with make_api_client(username) as api_client: (task, response) = api_client.tasks_api.create(spec, **kwargs) assert response.status == HTTPStatus.CREATED - (_, response) = api_client.tasks_api.create_data(task.id, data_request=deepcopy(data), - _content_type=content_type, **kwargs) + (_, response) = api_client.tasks_api.create_data( + task.id, data_request=deepcopy(data), _content_type=content_type, **kwargs + ) assert response.status == HTTPStatus.ACCEPTED status = self._wait_until_task_is_created(api_client.tasks_api, task.id) - assert status.state.value == 'Finished' + assert status.state.value == "Finished" return task.id def test_can_create_task_with_defined_start_and_stop_frames(self): task_spec = { - 'name': f'test {self._USERNAME} to create a task with defined start and stop frames', - "labels": [{ - "name": "car", - "color": "#ff00ff", - "attributes": [ - { - "name": "a", - "mutable": True, - "input_type": "number", - "default_value": "5", - "values": ["4", "5", "6"] - } - ] - }], + "name": f"test {self._USERNAME} to create a task with defined start and stop frames", + "labels": [ + { + "name": "car", + "color": "#ff00ff", + "attributes": [ + { + "name": "a", + "mutable": True, + "input_type": "number", + "default_value": "5", + "values": ["4", "5", "6"], + } + ], + } + ], } task_data = { - 'image_quality': 75, - 'start_frame': 2, - 'stop_frame': 5, - 'client_files': generate_image_files(7), + "image_quality": 75, + "start_frame": 2, + "stop_frame": 5, + "client_files": generate_image_files(7), } - task_id = self._test_create_task(self._USERNAME, task_spec, task_data, - content_type="multipart/form-data") + task_id = self._test_create_task( + self._USERNAME, task_spec, task_data, content_type="multipart/form-data" + ) # check task size with make_api_client(self._USERNAME) as api_client: @@ -382,7 +470,7 @@ class TestPostTaskData: def test_can_get_annotations_from_new_task_with_skeletons(self): spec = { - "name": f'test admin1 to create a task with skeleton', + "name": f"test admin1 to create a task with skeleton", "labels": [ { "name": "s1", @@ -390,36 +478,27 @@ class TestPostTaskData: "attributes": [], "type": "skeleton", "sublabels": [ - { - "name": "1", - "color": "#d12345", - "attributes": [], - "type": "points" - }, - { - "name": "2", - "color": "#350dea", - "attributes": [], - "type": "points" - } + {"name": "1", "color": "#d12345", "attributes": [], "type": "points"}, + {"name": "2", "color": "#350dea", "attributes": [], "type": "points"}, ], - "svg": "" \ - "" \ - "" + "svg": '' + '' + '', } - ] + ], } task_data = { - 'image_quality': 75, - 'client_files': generate_image_files(3), + "image_quality": 75, + "client_files": generate_image_files(3), } - task_id = self._test_create_task(self._USERNAME, spec, task_data, - content_type="multipart/form-data") + task_id = self._test_create_task( + self._USERNAME, spec, task_data, content_type="multipart/form-data" + ) response = get_method(self._USERNAME, f"tasks/{task_id}") label_ids = {} @@ -428,60 +507,8 @@ class TestPostTaskData: job_id = response.json()["segments"][0]["jobs"][0]["id"] patch_data = { - "shapes": [{ - "type": "skeleton", - "occluded": False, - "outside": False, - "z_order": 0, - "rotation": 0, - "points": [], - "frame": 0, - "label_id": label_ids["skeleton"][0], - "group": 0, - "source": "manual", - "attributes": [], - "elements": [ - { - "type": "points", - "occluded": False, - "outside": False, - "z_order": 0, - "rotation": 0, - "points": [ - 131.63947368421032, - 165.0868421052637 - ], - "frame": 0, - "label_id": label_ids["points"][0], - "group": 0, - "source": "manual", - "attributes": [] - }, - { - "type": "points", - "occluded": False, - "outside": False, - "z_order": 0, - "rotation": 0, - "points": [ - 354.98157894736823, - 304.2710526315795 - ], - "frame": 0, - "label_id": label_ids["points"][1], - "group": 0, - "source": "manual", - "attributes": [] - } - ] - }], - "tracks": [{ - "frame": 0, - "label_id": label_ids["skeleton"][0], - "group": 0, - "source": "manual", - "shapes": [ - { + "shapes": [ + { "type": "skeleton", "occluded": False, "outside": False, @@ -489,90 +516,146 @@ class TestPostTaskData: "rotation": 0, "points": [], "frame": 0, - "attributes": [] - } - ], - "attributes": [], - "elements": [ - { - "frame": 0, - "label_id": label_ids["points"][0], + "label_id": label_ids["skeleton"][0], "group": 0, "source": "manual", - "shapes": [ + "attributes": [], + "elements": [ { - "type": "points", - "occluded": False, - "outside": False, - "z_order": 0, - "rotation": 0, - "points": [ - 295.6394736842103, - 472.5868421052637 - ], - "frame": 0, - "attributes": [] - } + "type": "points", + "occluded": False, + "outside": False, + "z_order": 0, + "rotation": 0, + "points": [131.63947368421032, 165.0868421052637], + "frame": 0, + "label_id": label_ids["points"][0], + "group": 0, + "source": "manual", + "attributes": [], + }, + { + "type": "points", + "occluded": False, + "outside": False, + "z_order": 0, + "rotation": 0, + "points": [354.98157894736823, 304.2710526315795], + "frame": 0, + "label_id": label_ids["points"][1], + "group": 0, + "source": "manual", + "attributes": [], + }, ], - "attributes": [] - }, - { + } + ], + "tracks": [ + { "frame": 0, - "label_id": label_ids["points"][1], + "label_id": label_ids["skeleton"][0], "group": 0, "source": "manual", "shapes": [ { - "type": "points", - "occluded": False, - "outside": False, - "z_order": 0, - "rotation": 0, - "points": [ - 619.3236842105262, - 846.9815789473689 - ], - "frame": 0, - "attributes": [] + "type": "skeleton", + "occluded": False, + "outside": False, + "z_order": 0, + "rotation": 0, + "points": [], + "frame": 0, + "attributes": [], } ], - "attributes": [] - } - ] - }], + "attributes": [], + "elements": [ + { + "frame": 0, + "label_id": label_ids["points"][0], + "group": 0, + "source": "manual", + "shapes": [ + { + "type": "points", + "occluded": False, + "outside": False, + "z_order": 0, + "rotation": 0, + "points": [295.6394736842103, 472.5868421052637], + "frame": 0, + "attributes": [], + } + ], + "attributes": [], + }, + { + "frame": 0, + "label_id": label_ids["points"][1], + "group": 0, + "source": "manual", + "shapes": [ + { + "type": "points", + "occluded": False, + "outside": False, + "z_order": 0, + "rotation": 0, + "points": [619.3236842105262, 846.9815789473689], + "frame": 0, + "attributes": [], + } + ], + "attributes": [], + }, + ], + } + ], "tags": [], - "version": 0 + "version": 0, } - response = patch_method(self._USERNAME, f"jobs/{job_id}/annotations", patch_data, action="create") + response = patch_method( + self._USERNAME, f"jobs/{job_id}/annotations", patch_data, action="create" + ) response = get_method(self._USERNAME, f"jobs/{job_id}/annotations") assert response.status_code == HTTPStatus.OK - @pytest.mark.parametrize('cloud_storage_id, manifest, use_bucket_content, org', [ - (1, 'manifest.jsonl', False, ''), # public bucket - (2, 'sub/manifest.jsonl', True, 'org2'), # private bucket - ]) - def test_create_task_with_cloud_storage_files(self, cloud_storage_id, manifest, use_bucket_content, org): + @pytest.mark.parametrize( + "cloud_storage_id, manifest, use_bucket_content, org", + [ + (1, "manifest.jsonl", False, ""), # public bucket + (2, "sub/manifest.jsonl", True, "org2"), # private bucket + ], + ) + def test_create_task_with_cloud_storage_files( + self, cloud_storage_id, manifest, use_bucket_content, org + ): if use_bucket_content: - cloud_storage_content = get_cloud_storage_content(self._USERNAME, cloud_storage_id, manifest) + cloud_storage_content = get_cloud_storage_content( + self._USERNAME, cloud_storage_id, manifest + ) else: - cloud_storage_content = ['image_case_65_1.png', 'image_case_65_2.png'] + cloud_storage_content = ["image_case_65_1.png", "image_case_65_2.png"] cloud_storage_content.append(manifest) task_spec = { "name": f"Task with files from cloud storage {cloud_storage_id}", - "labels": [{ - "name": "car", - }], + "labels": [ + { + "name": "car", + } + ], } data_spec = { - 'image_quality': 75, - 'use_cache': True, - 'storage': 'cloud_storage', - 'cloud_storage_id': cloud_storage_id, - 'server_files': cloud_storage_content, + "image_quality": 75, + "use_cache": True, + "storage": "cloud_storage", + "cloud_storage_id": cloud_storage_id, + "server_files": cloud_storage_content, } - self._test_create_task(self._USERNAME, task_spec, data_spec, - content_type="application/json", org=org) + self._test_create_task( + self._USERNAME, task_spec, data_spec, content_type="application/json", org=org + ) diff --git a/tests/python/rest_api/test_users.py b/tests/python/rest_api/test_users.py index 9228bac2..d2e8c274 100644 --- a/tests/python/rest_api/test_users.py +++ b/tests/python/rest_api/test_users.py @@ -3,81 +3,91 @@ # # SPDX-License-Identifier: MIT -from http import HTTPStatus import json import typing -from cvat_sdk.core.helpers import get_paginated_collection +from http import HTTPStatus import pytest +from cvat_sdk.core.helpers import get_paginated_collection from deepdiff import DeepDiff from shared.utils.config import make_api_client -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetUsers: - def _test_can_see(self, user, data, - id_: typing.Union[typing.Literal['self'], int, None] = None, - *, - exclude_paths='', **kwargs): + def _test_can_see( + self, + user, + data, + id_: typing.Union[typing.Literal["self"], int, None] = None, + *, + exclude_paths="", + **kwargs, + ): with make_api_client(user) as api_client: # TODO: refactor into several functions - if id_ == 'self': - (_, response) = api_client.users_api.retrieve_self(**kwargs, - _parse_response=False) + if id_ == "self": + (_, response) = api_client.users_api.retrieve_self(**kwargs, _parse_response=False) assert response.status == HTTPStatus.OK response_data = json.loads(response.data) elif id_ is None: - response_data = get_paginated_collection(api_client.users_api.list_endpoint, - return_json=True, **kwargs) + response_data = get_paginated_collection( + api_client.users_api.list_endpoint, return_json=True, **kwargs + ) else: - (_, response) = api_client.users_api.retrieve(id_, **kwargs, - _parse_response=False) + (_, response) = api_client.users_api.retrieve(id_, **kwargs, _parse_response=False) assert response.status == HTTPStatus.OK response_data = json.loads(response.data) - assert DeepDiff(data, response_data, ignore_order=True, - exclude_paths=exclude_paths) == {} + assert DeepDiff(data, response_data, ignore_order=True, exclude_paths=exclude_paths) == {} - def _test_cannot_see(self, user, id_: typing.Union[typing.Literal['self'], int, None] = None, - **kwargs): + def _test_cannot_see( + self, user, id_: typing.Union[typing.Literal["self"], int, None] = None, **kwargs + ): with make_api_client(user) as api_client: # TODO: refactor into several functions - if id_ == 'self': - (_, response) = api_client.users_api.retrieve_self(**kwargs, - _parse_response=False, _check_status=False) + if id_ == "self": + (_, response) = api_client.users_api.retrieve_self( + **kwargs, _parse_response=False, _check_status=False + ) elif id_ is None: - (_, response) = api_client.users_api.list(**kwargs, - _parse_response=False, _check_status=False) + (_, response) = api_client.users_api.list( + **kwargs, _parse_response=False, _check_status=False + ) else: - (_, response) = api_client.users_api.retrieve(id_, **kwargs, - _parse_response=False, _check_status=False) + (_, response) = api_client.users_api.retrieve( + id_, **kwargs, _parse_response=False, _check_status=False + ) assert response.status == HTTPStatus.FORBIDDEN def test_admin_can_see_all_others(self, users): exclude_paths = [f"root[{i}]['last_login']" for i in range(len(users))] - self._test_can_see('admin2', users.raw, exclude_paths=exclude_paths) + self._test_can_see("admin2", users.raw, exclude_paths=exclude_paths) def test_everybody_can_see_self(self, users_by_name): for user, data in users_by_name.items(): self._test_can_see(user, data, id_="self", exclude_paths="root['last_login']") def test_non_members_cannot_see_list_of_members(self): - self._test_cannot_see('user2', org='org1') + self._test_cannot_see("user2", org="org1") def test_non_admin_cannot_see_others(self, users): - non_admins = (v for v in users if not v['is_superuser']) - user = next(non_admins)['username'] - user_id = next(non_admins)['id'] + non_admins = (v for v in users if not v["is_superuser"]) + user = next(non_admins)["username"] + user_id = next(non_admins)["id"] self._test_cannot_see(user, id_=user_id) def test_all_members_can_see_list_of_members(self, find_users, users): - org_members = [user['username'] for user in find_users(org=1)] - available_fields = ['url', 'id', 'username', 'first_name', 'last_name'] + org_members = [user["username"] for user in find_users(org=1)] + available_fields = ["url", "id", "username", "first_name", "last_name"] - data = [dict(filter(lambda row: row[0] in available_fields, user.items())) - for user in users if user['username'] in org_members] + data = [ + dict(filter(lambda row: row[0] in available_fields, user.items())) + for user in users + if user["username"] in org_members + ] for member in org_members: - self._test_can_see(member, data, org='org1') + self._test_can_see(member, data, org="org1") diff --git a/tests/python/rest_api/test_webhooks.py b/tests/python/rest_api/test_webhooks.py index 34f193f4..010e0ab7 100644 --- a/tests/python/rest_api/test_webhooks.py +++ b/tests/python/rest_api/test_webhooks.py @@ -12,740 +12,810 @@ from deepdiff import DeepDiff from shared.utils.config import delete_method, get_method, patch_method, post_method -@pytest.mark.usefixtures('changedb') +@pytest.mark.usefixtures("changedb") class TestPostWebhooks: proj_webhook = { - 'description': 'webhook description', - 'content_type': 'application/json', - 'enable_ssl': False, - 'events': [ - 'create:task', - 'delete:task' - ], - 'is_active': True, - 'project_id': 1, - 'secret': 'secret', - 'target_url': 'http://example.com', - 'type': 'project', + "description": "webhook description", + "content_type": "application/json", + "enable_ssl": False, + "events": ["create:task", "delete:task"], + "is_active": True, + "project_id": 1, + "secret": "secret", + "target_url": "http://example.com", + "type": "project", } org_webhook = { - 'description': 'webhook description', - 'content_type': 'application/json', - 'enable_ssl': False, - 'events': [ - 'create:task', - 'delete:task' - ], - 'is_active': True, - 'secret': 'secret', - 'target_url': 'http://example.com', - 'type': 'organization', + "description": "webhook description", + "content_type": "application/json", + "enable_ssl": False, + "events": ["create:task", "delete:task"], + "is_active": True, + "secret": "secret", + "target_url": "http://example.com", + "type": "organization", } def test_sandbox_admin_can_create_webhook_for_project(self, projects, users): - admin = next((u for u in users if 'admin' in u['groups'])) - project = [p for p in projects if p['owner']['id'] != admin['id'] and p['organization'] is None][0] + admin = next((u for u in users if "admin" in u["groups"])) + project = [ + p for p in projects if p["owner"]["id"] != admin["id"] and p["organization"] is None + ][0] webhook = deepcopy(self.proj_webhook) - webhook['project_id'] = project['id'] + webhook["project_id"] = project["id"] - response = post_method(admin['username'], 'webhooks', webhook) + response = post_method(admin["username"], "webhooks", webhook) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() + assert "secret" not in response.json() def test_admin_can_create_webhook_for_org(self, users, organizations, is_org_member): - admins = [u for u in users if 'admin' in u['groups']] - username, org_id = next(( - (user['username'], org['id']) - for user in admins - for org in organizations - if not is_org_member(user['id'], org['id']) - )) + admins = [u for u in users if "admin" in u["groups"]] + username, org_id = next( + ( + (user["username"], org["id"]) + for user in admins + for org in organizations + if not is_org_member(user["id"], org["id"]) + ) + ) webhook = deepcopy(self.org_webhook) - response = post_method(username, 'webhooks', webhook, org_id=org_id) + response = post_method(username, "webhooks", webhook, org_id=org_id) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() - - def test_admin_can_create_webhook_for_project_in_org(self, users, projects_by_org, - organizations, is_org_member): - admins = [u for u in users if 'admin' in u['groups']] - not_org_members = [(u, o) for u, o in product(admins, organizations) - if not is_org_member(u['id'], o['id'])] + assert "secret" not in response.json() + + def test_admin_can_create_webhook_for_project_in_org( + self, users, projects_by_org, organizations, is_org_member + ): + admins = [u for u in users if "admin" in u["groups"]] + not_org_members = [ + (u, o) for u, o in product(admins, organizations) if not is_org_member(u["id"], o["id"]) + ] - username, org_id = next(( - (u['username'], o['id']) - for u, o in not_org_members - for p in projects_by_org.get(o['id'], []) - if p['owner']['id'] != u['id'] - )) + username, org_id = next( + ( + (u["username"], o["id"]) + for u, o in not_org_members + for p in projects_by_org.get(o["id"], []) + if p["owner"]["id"] != u["id"] + ) + ) webhook = deepcopy(self.org_webhook) - response = post_method(username, 'webhooks', webhook, org_id=org_id) + response = post_method(username, "webhooks", webhook, org_id=org_id) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() + assert "secret" not in response.json() - - @pytest.mark.parametrize('privilege', ['user', 'business']) + @pytest.mark.parametrize("privilege", ["user", "business"]) def test_sandbox_project_owner_can_create_webhook_for_project(self, privilege, projects, users): - users = [user for user in users if privilege in user['groups']] - username, project_id = next(( - (user['username'], project['id']) - for user in users - for project in projects - if project['owner']['id'] == user['id'] and project['organization'] is None - )) + users = [user for user in users if privilege in user["groups"]] + username, project_id = next( + ( + (user["username"], project["id"]) + for user in users + for project in projects + if project["owner"]["id"] == user["id"] and project["organization"] is None + ) + ) webhook = deepcopy(self.proj_webhook) - webhook['project_id'] = project_id + webhook["project_id"] = project_id - response = post_method(username, 'webhooks', webhook) + response = post_method(username, "webhooks", webhook) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() - - @pytest.mark.parametrize('privilege', ['worker', 'user', 'business']) - def test_sandbox_project_assignee_cannot_create_webhook_for_project(self, privilege, projects, users): - users = [u for u in users if privilege in u['groups']] - projects = [p for p in projects if p['assignee'] is not None] - username, project_id = next(( - (user['username'], project['id']) - for user in users - for project in projects - if project['assignee']['id'] == user['id'] and project['organization'] is None - )) - + assert "secret" not in response.json() + + @pytest.mark.parametrize("privilege", ["worker", "user", "business"]) + def test_sandbox_project_assignee_cannot_create_webhook_for_project( + self, privilege, projects, users + ): + users = [u for u in users if privilege in u["groups"]] + projects = [p for p in projects if p["assignee"] is not None] + username, project_id = next( + ( + (user["username"], project["id"]) + for user in users + for project in projects + if project["assignee"]["id"] == user["id"] and project["organization"] is None + ) + ) webhook = deepcopy(self.proj_webhook) - webhook['project_id'] = project_id + webhook["project_id"] = project_id - response = post_method(username, 'webhooks', webhook) + response = post_method(username, "webhooks", webhook) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['maintainer', 'owner']) + @pytest.mark.parametrize("role", ["maintainer", "owner"]) def test_member_can_create_webhook_for_org(self, role, find_users, organizations): - username, org_id = next(( - (u['username'], o['id']) - for o in organizations - for u in find_users(org=o['id'], role=role, exclude_privilege='admin') - )) + username, org_id = next( + ( + (u["username"], o["id"]) + for o in organizations + for u in find_users(org=o["id"], role=role, exclude_privilege="admin") + ) + ) webhook = deepcopy(self.org_webhook) - response = post_method(username, 'webhooks', webhook, org_id=org_id) + response = post_method(username, "webhooks", webhook, org_id=org_id) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() - - @pytest.mark.parametrize('role', ['maintainer', 'owner']) - def test_member_can_create_webhook_for_project(self, role, find_users, organizations, - projects_by_org, is_project_staff): - username, oid, pid = next(( - (u['username'], o['id'], p['id']) - for o in organizations - for u in find_users(org=o['id'], role=role, exclude_privilege='admin') - for p in projects_by_org.get(o['id'], []) - if not is_project_staff(u['id'], p['id']) - )) + assert "secret" not in response.json() + + @pytest.mark.parametrize("role", ["maintainer", "owner"]) + def test_member_can_create_webhook_for_project( + self, role, find_users, organizations, projects_by_org, is_project_staff + ): + username, oid, pid = next( + ( + (u["username"], o["id"], p["id"]) + for o in organizations + for u in find_users(org=o["id"], role=role, exclude_privilege="admin") + for p in projects_by_org.get(o["id"], []) + if not is_project_staff(u["id"], p["id"]) + ) + ) webhook = deepcopy(self.proj_webhook) - webhook['project_id'] = pid + webhook["project_id"] = pid - response = post_method(username, 'webhooks', webhook, org_id=oid) + response = post_method(username, "webhooks", webhook, org_id=oid) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() + assert "secret" not in response.json() - @pytest.mark.parametrize('role', ['supervisor', 'worker']) + @pytest.mark.parametrize("role", ["supervisor", "worker"]) def test_member_cannot_create_webhook_for_org(self, role, find_users, organizations): - username, org_id = next(( - (u['username'], o['id']) - for o in organizations - for u in find_users(org=o['id'], role=role, exclude_privilege='admin') - )) + username, org_id = next( + ( + (u["username"], o["id"]) + for o in organizations + for u in find_users(org=o["id"], role=role, exclude_privilege="admin") + ) + ) webhook = deepcopy(self.org_webhook) - response = post_method(username, 'webhooks', webhook, org_id=org_id) + response = post_method(username, "webhooks", webhook, org_id=org_id) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['supervisor', 'worker']) - def test_member_cannot_create_webhook_for_project(self, role, find_users, organizations, - projects_by_org, is_project_staff): - username, oid, pid = next(( - (u['username'], o['id'], p['id']) - for o in organizations - for u in find_users(org=o['id'], role=role, exclude_privilege='admin') - for p in projects_by_org.get(o['id'], []) - if not is_project_staff(u['id'], p['id']) - )) + @pytest.mark.parametrize("role", ["supervisor", "worker"]) + def test_member_cannot_create_webhook_for_project( + self, role, find_users, organizations, projects_by_org, is_project_staff + ): + username, oid, pid = next( + ( + (u["username"], o["id"], p["id"]) + for o in organizations + for u in find_users(org=o["id"], role=role, exclude_privilege="admin") + for p in projects_by_org.get(o["id"], []) + if not is_project_staff(u["id"], p["id"]) + ) + ) webhook = deepcopy(self.proj_webhook) - webhook['project_id'] = pid + webhook["project_id"] = pid - response = post_method(username, 'webhooks', webhook, org_id=oid) + response = post_method(username, "webhooks", webhook, org_id=oid) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['supervisor']) - def test_member_project_owner_can_create_webhook_for_project(self, role, find_users, organizations, - projects_by_org, is_project_staff): - username, oid, pid = next(( - (u['username'], o['id'], p['id']) - for o in organizations - for u in find_users(org=o['id'], role=role, exclude_privilege='admin') - for p in projects_by_org.get(o['id'], []) - if p['owner']['id'] == u['id'] - )) + @pytest.mark.parametrize("role", ["supervisor"]) + def test_member_project_owner_can_create_webhook_for_project( + self, role, find_users, organizations, projects_by_org, is_project_staff + ): + username, oid, pid = next( + ( + (u["username"], o["id"], p["id"]) + for o in organizations + for u in find_users(org=o["id"], role=role, exclude_privilege="admin") + for p in projects_by_org.get(o["id"], []) + if p["owner"]["id"] == u["id"] + ) + ) webhook = deepcopy(self.proj_webhook) - webhook['project_id'] = pid + webhook["project_id"] = pid - response = post_method(username, 'webhooks', webhook, org_id=oid) + response = post_method(username, "webhooks", webhook, org_id=oid) assert response.status_code == HTTPStatus.CREATED - assert 'secret' not in response.json() - - def test_non_member_cannot_create_webhook_for_org(self, find_users, organizations, - is_org_member): - username, org_id = next(( - (u['username'], o['id']) - for o in organizations - for u in find_users(exclude_privilege='admin') - if not is_org_member(u['id'], o['id']) - )) + assert "secret" not in response.json() + + def test_non_member_cannot_create_webhook_for_org( + self, find_users, organizations, is_org_member + ): + username, org_id = next( + ( + (u["username"], o["id"]) + for o in organizations + for u in find_users(exclude_privilege="admin") + if not is_org_member(u["id"], o["id"]) + ) + ) webhook = deepcopy(self.org_webhook) - response = post_method(username, 'webhooks', webhook, org_id=org_id) + response = post_method(username, "webhooks", webhook, org_id=org_id) assert response.status_code == HTTPStatus.FORBIDDEN - def test_can_create_without_unnecessary_fields(self): post_data = deepcopy(self.proj_webhook) - post_data.pop('enable_ssl') - post_data.pop('content_type') - post_data.pop('description') - post_data.pop('is_active') - post_data.pop('secret') + post_data.pop("enable_ssl") + post_data.pop("content_type") + post_data.pop("description") + post_data.pop("is_active") + post_data.pop("secret") - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.CREATED def test_cannot_create_without_target_url(self): post_data = deepcopy(self.proj_webhook) - post_data.pop('target_url') + post_data.pop("target_url") - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST - def test_cannot_create_without_events_list(self): post_data = deepcopy(self.proj_webhook) - post_data.pop('events') + post_data.pop("events") - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST def test_cannot_create_without_type(self): post_data = deepcopy(self.proj_webhook) - post_data.pop('type') + post_data.pop("type") - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST def test_cannot_create_without_project_id(self): post_data = deepcopy(self.proj_webhook) - post_data.pop('project_id') + post_data.pop("project_id") - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR def test_cannot_create_organization_webhook_when_project_id_is_not_null(self, organizations): post_data = deepcopy(self.proj_webhook) - post_data['type'] = 'organization' - org_id = organizations.raw[0]['id'] + post_data["type"] = "organization" + org_id = organizations.raw[0]["id"] - response = post_method('admin2', 'webhooks', post_data, org_id=org_id) + response = post_method("admin2", "webhooks", post_data, org_id=org_id) assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR def test_cannot_create_non_unique_webhook(self): - pytest.skip('Not implemeted yet') - response = post_method('admin2', 'webhooks', self.proj_webhook) + pytest.skip("Not implemeted yet") + response = post_method("admin2", "webhooks", self.proj_webhook) - response = post_method('admin2', 'webhooks', self.proj_webhook) + response = post_method("admin2", "webhooks", self.proj_webhook) assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR def test_cannot_create_for_non_existent_organization(self, organizations): post_data = deepcopy(self.proj_webhook) - post_data['type'] = 'organization' - org_id = max(a['id'] for a in organizations.raw) + 1 + post_data["type"] = "organization" + org_id = max(a["id"] for a in organizations.raw) + 1 - response = post_method('admin2', 'webhooks', post_data, org_id=org_id) + response = post_method("admin2", "webhooks", post_data, org_id=org_id) assert response.status_code == HTTPStatus.BAD_REQUEST def test_cannot_create_for_non_existent_project(self, projects): post_data = deepcopy(self.proj_webhook) - post_data['project_id'] = max(a['id'] for a in projects.raw) + 1 + post_data["project_id"] = max(a["id"] for a in projects.raw) + 1 - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST - def test_cannot_create_with_non_supported_type(self): post_data = deepcopy(self.proj_webhook) - post_data['type'] = 'some_type' + post_data["type"] = "some_type" - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST def test_cannot_create_with_non_supported_content_type(self): post_data = deepcopy(self.proj_webhook) - post_data['content_type'] = ['application/x-www-form-urlencoded'] + post_data["content_type"] = ["application/x-www-form-urlencoded"] - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST - @pytest.mark.parametrize('event', ['some:event', 'create:project', 'update:organization', 'create:invitation']) + @pytest.mark.parametrize( + "event", ["some:event", "create:project", "update:organization", "create:invitation"] + ) def test_cannot_create_project_webhook_with_non_supported_event_type(self, event): post_data = deepcopy(self.proj_webhook) - post_data['events'] = [event] + post_data["events"] = [event] - response = post_method('admin2', 'webhooks', post_data) + response = post_method("admin2", "webhooks", post_data) assert response.status_code == HTTPStatus.BAD_REQUEST - @pytest.mark.parametrize('event', ['some:event', 'create:organization']) - def test_cannot_create_organization_webhook_with_non_supported_event_type(self, event, organizations): + @pytest.mark.parametrize("event", ["some:event", "create:organization"]) + def test_cannot_create_organization_webhook_with_non_supported_event_type( + self, event, organizations + ): post_data = deepcopy(self.proj_webhook) - post_data['type'] = 'organization' - post_data['events'] = [event] - org_id = next(iter(organizations))['id'] + post_data["type"] = "organization" + post_data["events"] = [event] + org_id = next(iter(organizations))["id"] - response = post_method('admin2', 'webhooks', post_data, org_id=org_id) + response = post_method("admin2", "webhooks", post_data, org_id=org_id) assert response.status_code == HTTPStatus.BAD_REQUEST -@pytest.mark.usefixtures('dontchangedb') + +@pytest.mark.usefixtures("dontchangedb") class TestGetWebhooks: def test_admin_can_get_webhook(self, webhooks, users, projects): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, wid = next(( - (user['username'], webhook['id']) - for user in users - for webhook in proj_webhooks - if 'admin' in user['groups'] - and webhook['owner']['id'] != user['id'] - and projects[webhook['project']]['owner']['id'] != user['id'] - )) + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, wid = next( + ( + (user["username"], webhook["id"]) + for user in users + for webhook in proj_webhooks + if "admin" in user["groups"] + and webhook["owner"]["id"] != user["id"] + and projects[webhook["project"]]["owner"]["id"] != user["id"] + ) + ) response = get_method(username, f"webhooks/{wid}") assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() + assert "secret" not in response.json() assert DeepDiff(webhooks[wid], response.json(), ignore_order=True) == {} - @pytest.mark.parametrize('privilege', ['user', 'business']) + @pytest.mark.parametrize("privilege", ["user", "business"]) def test_project_owner_can_get_webhook(self, privilege, webhooks, projects, users): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, wid = next(( - (user['username'], webhook['id']) - for user in users - for webhook in proj_webhooks - if privilege not in user['groups'] - and projects[webhook['project']]['owner']['id'] == user['id'] - )) + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, wid = next( + ( + (user["username"], webhook["id"]) + for user in users + for webhook in proj_webhooks + if privilege not in user["groups"] + and projects[webhook["project"]]["owner"]["id"] == user["id"] + ) + ) response = get_method(username, f"webhooks/{wid}") assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() + assert "secret" not in response.json() assert DeepDiff(webhooks[wid], response.json(), ignore_order=True) == {} - @pytest.mark.parametrize('privilege', ['user', 'business']) + @pytest.mark.parametrize("privilege", ["user", "business"]) def test_webhook_owner_can_get_webhook(self, privilege, webhooks, projects, users): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, wid = next(( - (user['username'], webhook['id']) - for user in users - for webhook in proj_webhooks - if privilege in user['groups'] - and webhook['owner']['id'] == user['id'] - )) + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, wid = next( + ( + (user["username"], webhook["id"]) + for user in users + for webhook in proj_webhooks + if privilege in user["groups"] and webhook["owner"]["id"] == user["id"] + ) + ) response = get_method(username, f"webhooks/{wid}") assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() + assert "secret" not in response.json() assert DeepDiff(webhooks[wid], response.json(), ignore_order=True) == {} - @pytest.mark.parametrize('privilege', ['user', 'business']) - def test_not_project_staff_cannot_get_webhook(self, privilege, webhooks, - projects, users): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, wid = next(( - (user['username'], webhook['id']) - for user in users - for webhook in proj_webhooks - if privilege in user['groups'] - and projects[webhook['project']]['owner']['id'] != user['id'] - and webhook['owner']['id'] != user['id'] - )) + @pytest.mark.parametrize("privilege", ["user", "business"]) + def test_not_project_staff_cannot_get_webhook(self, privilege, webhooks, projects, users): + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, wid = next( + ( + (user["username"], webhook["id"]) + for user in users + for webhook in proj_webhooks + if privilege in user["groups"] + and projects[webhook["project"]]["owner"]["id"] != user["id"] + and webhook["owner"]["id"] != user["id"] + ) + ) response = get_method(username, f"webhooks/{wid}") assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['owner', 'maintainer']) + @pytest.mark.parametrize("role", ["owner", "maintainer"]) def test_org_staff_can_see_org_webhook(self, role, webhooks, find_users): - webhook = next((w for w in webhooks if w['type'] == 'organization')) - username = next(( - u['username'] for u in find_users(role=role, org=webhook['organization']) - )) + webhook = next((w for w in webhooks if w["type"] == "organization")) + username = next((u["username"] for u in find_users(role=role, org=webhook["organization"]))) - response = get_method(username, f"webhooks/{webhook['id']}", - org_id=webhook['organization']) + response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"]) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() + assert "secret" not in response.json() assert DeepDiff(webhook, response.json(), ignore_order=True) == {} - @pytest.mark.parametrize('role', ['owner', 'maintainer']) - def test_org_staff_can_see_project_webhook_in_org(self, role, webhooks, find_users, - projects): - proj_webhooks = [w for w in webhooks if w['organization'] is not None and - w['type'] == 'project'] - username, webhook = next(( - (user['username'], webhook) - for webhook in proj_webhooks - for user in find_users(role=role, org=webhook['organization']) - if projects[webhook['project']]['owner']['id'] != user['id'] - and webhook['owner']['id'] != user['id'] - )) - - response = get_method(username, f"webhooks/{webhook['id']}", - org_id=webhook['organization']) + @pytest.mark.parametrize("role", ["owner", "maintainer"]) + def test_org_staff_can_see_project_webhook_in_org(self, role, webhooks, find_users, projects): + proj_webhooks = [ + w for w in webhooks if w["organization"] is not None and w["type"] == "project" + ] + username, webhook = next( + ( + (user["username"], webhook) + for webhook in proj_webhooks + for user in find_users(role=role, org=webhook["organization"]) + if projects[webhook["project"]]["owner"]["id"] != user["id"] + and webhook["owner"]["id"] != user["id"] + ) + ) + + response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"]) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() + assert "secret" not in response.json() assert DeepDiff(webhook, response.json(), ignore_order=True) == {} - @pytest.mark.parametrize('role', ['worker', 'supervisor']) + @pytest.mark.parametrize("role", ["worker", "supervisor"]) def test_member_cannot_get_org_webhook(self, role, webhooks, find_users): - webhook = next((w for w in webhooks if w['type'] == 'organization')) - username = next(( - u['username'] for u in find_users(role=role, org=webhook['organization']) - )) + webhook = next((w for w in webhooks if w["type"] == "organization")) + username = next((u["username"] for u in find_users(role=role, org=webhook["organization"]))) - response = get_method(username, f"webhooks/{webhook['id']}", - org_id=webhook['organization']) + response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"]) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['worker', 'supervisor']) - def test_member_cannot_get_project_webhook_in_org(self, role, webhooks, find_users, - projects): - proj_webhooks = [w for w in webhooks if w['organization'] is not None and - w['type'] == 'project'] - username, webhook = next(( - (user['username'], webhook) - for webhook in proj_webhooks - for user in find_users(role=role, org=webhook['organization']) - if projects[webhook['project']]['owner']['id'] != user['id'] - and webhook['owner']['id'] != user['id'] - )) - - response = get_method(username, f"webhooks/{webhook['id']}", - org_id=webhook['organization']) + @pytest.mark.parametrize("role", ["worker", "supervisor"]) + def test_member_cannot_get_project_webhook_in_org(self, role, webhooks, find_users, projects): + proj_webhooks = [ + w for w in webhooks if w["organization"] is not None and w["type"] == "project" + ] + username, webhook = next( + ( + (user["username"], webhook) + for webhook in proj_webhooks + for user in find_users(role=role, org=webhook["organization"]) + if projects[webhook["project"]]["owner"]["id"] != user["id"] + and webhook["owner"]["id"] != user["id"] + ) + ) + + response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"]) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['supervisor']) - def test_member_can_get_project_webhook_in_org(self, role, webhooks, find_users, - projects): - proj_webhooks = [w for w in webhooks if w['organization'] is not None and - w['type'] == 'project'] - username, webhook = next(( - (user['username'], webhook) - for webhook in proj_webhooks - for user in find_users(role=role, org=webhook['organization']) - if projects[webhook['project']]['owner']['id'] == user['id'] - or webhook['owner']['id'] == user['id'] - )) - - response = get_method(username, f"webhooks/{webhook['id']}", - org_id=webhook['organization']) + @pytest.mark.parametrize("role", ["supervisor"]) + def test_member_can_get_project_webhook_in_org(self, role, webhooks, find_users, projects): + proj_webhooks = [ + w for w in webhooks if w["organization"] is not None and w["type"] == "project" + ] + username, webhook = next( + ( + (user["username"], webhook) + for webhook in proj_webhooks + for user in find_users(role=role, org=webhook["organization"]) + if projects[webhook["project"]]["owner"]["id"] == user["id"] + or webhook["owner"]["id"] == user["id"] + ) + ) + + response = get_method(username, f"webhooks/{webhook['id']}", org_id=webhook["organization"]) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() + assert "secret" not in response.json() assert DeepDiff(webhook, response.json(), ignore_order=True) == {} -@pytest.mark.usefixtures('dontchangedb') +@pytest.mark.usefixtures("dontchangedb") class TestGetListWebhooks: def test_can_get_webhooks_list(self, webhooks): - response = get_method('admin2', 'webhooks') + response = get_method("admin2", "webhooks") assert response.status_code == HTTPStatus.OK - assert all(['secret' not in webhook for webhook in response.json()['results']]) - assert DeepDiff(webhooks.raw, response.json()['results'], ignore_order=True) == {} + assert all(["secret" not in webhook for webhook in response.json()["results"]]) + assert DeepDiff(webhooks.raw, response.json()["results"], ignore_order=True) == {} def test_admin_can_get_webhooks_for_project(self, webhooks): - pid = next((webhook['project'] for webhook in webhooks - if webhook['type'] == 'project' and webhook['organization'] is None)) + pid = next( + ( + webhook["project"] + for webhook in webhooks + if webhook["type"] == "project" and webhook["organization"] is None + ) + ) - expected_response = [webhook for webhook in webhooks - if webhook['type'] == 'project' and webhook['project'] == pid] + expected_response = [ + webhook + for webhook in webhooks + if webhook["type"] == "project" and webhook["project"] == pid + ] filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid - response = get_method('admin2', "webhooks", filter=filter_val) + response = get_method("admin2", "webhooks", filter=filter_val) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], ignore_order=True) == {} + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} def test_admin_can_get_webhooks_for_organization(self, webhooks): - org_id = next((webhook['organization'] for webhook in webhooks - if webhook['organization'] is not None)) + org_id = next( + (webhook["organization"] for webhook in webhooks if webhook["organization"] is not None) + ) - expected_response = [webhook for webhook in webhooks - if webhook['organization'] == org_id] + expected_response = [webhook for webhook in webhooks if webhook["organization"] == org_id] - response = get_method('admin2', "webhooks", org_id=org_id) + response = get_method("admin2", "webhooks", org_id=org_id) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], ignore_order=True) == {} + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} def test_admin_can_get_webhooks_for_project_in_org(self, webhooks): - pid, oid = next(( - (webhook['project'], webhook['organization']) - for webhook in webhooks - if webhook['type'] == 'project' - and webhook['organization'] is not None - )) + pid, oid = next( + ( + (webhook["project"], webhook["organization"]) + for webhook in webhooks + if webhook["type"] == "project" and webhook["organization"] is not None + ) + ) - expected_response = [webhook for webhook in webhooks - if webhook['project'] == pid and webhook['organization'] == oid] + expected_response = [ + webhook + for webhook in webhooks + if webhook["project"] == pid and webhook["organization"] == oid + ] filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid - response = get_method('admin2', "webhooks", org_id=oid, filter=filter_val) + response = get_method("admin2", "webhooks", org_id=oid, filter=filter_val) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], ignore_order=True) == {} - - @pytest.mark.parametrize('privilege', ['user', 'business']) - def test_user_cannot_get_webhook_list_for_project(self, privilege, find_users, - webhooks, projects): - username, pid = next(( - (user['username'], webhook['project']) - for user in find_users(privilege=privilege) - for webhook in webhooks - if webhook['type'] == 'project' - and webhook['organization'] is None - and webhook['owner']['id'] != user['id'] - and projects[webhook['project']]['owner']['id'] != user['id'] - )) + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} + + @pytest.mark.parametrize("privilege", ["user", "business"]) + def test_user_cannot_get_webhook_list_for_project( + self, privilege, find_users, webhooks, projects + ): + username, pid = next( + ( + (user["username"], webhook["project"]) + for user in find_users(privilege=privilege) + for webhook in webhooks + if webhook["type"] == "project" + and webhook["organization"] is None + and webhook["owner"]["id"] != user["id"] + and projects[webhook["project"]]["owner"]["id"] != user["id"] + ) + ) filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid response = get_method(username, "webhooks", filter=filter_val) assert response.status_code == HTTPStatus.OK - assert DeepDiff([], response.json()['results'], ignore_order=True) == {} - - @pytest.mark.parametrize('privilege', ['user', 'business']) - def test_user_can_get_webhook_list_for_project(self, privilege, find_users, - webhooks, projects): - username, pid = next(( - (user['username'], webhook['project']) - for user in find_users(privilege=privilege) - for webhook in webhooks - if webhook['type'] == 'project' - and webhook['organization'] is None - and projects[webhook['project']]['owner']['id'] == user['id'] - )) - - expected_response = [w for w in webhooks - if w['type'] == 'project' and w['project'] == pid] + assert DeepDiff([], response.json()["results"], ignore_order=True) == {} + + @pytest.mark.parametrize("privilege", ["user", "business"]) + def test_user_can_get_webhook_list_for_project(self, privilege, find_users, webhooks, projects): + username, pid = next( + ( + (user["username"], webhook["project"]) + for user in find_users(privilege=privilege) + for webhook in webhooks + if webhook["type"] == "project" + and webhook["organization"] is None + and projects[webhook["project"]]["owner"]["id"] == user["id"] + ) + ) + + expected_response = [w for w in webhooks if w["type"] == "project" and w["project"] == pid] filter_val = '{"and":[{"==":[{"var":"project_id"},%s]}]}' % pid response = get_method(username, "webhooks", filter=filter_val) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], - ignore_order=True) == {} - - def test_non_member_cannot_see_webhook_list_for_org(self, webhooks, users, - is_org_member): - username, org_id = next(( - (user['username'], webhook['organization']) - for webhook in webhooks - for user in users - if webhook['organization'] is not None - and not is_org_member(user['id'], webhook['organization']) - and 'admin' not in user['groups'] - )) - - response = get_method(username, 'webhooks', org_id=org_id) + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} + + def test_non_member_cannot_see_webhook_list_for_org(self, webhooks, users, is_org_member): + username, org_id = next( + ( + (user["username"], webhook["organization"]) + for webhook in webhooks + for user in users + if webhook["organization"] is not None + and not is_org_member(user["id"], webhook["organization"]) + and "admin" not in user["groups"] + ) + ) + + response = get_method(username, "webhooks", org_id=org_id) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role', ['maintainer', 'owner']) - def test_org_staff_can_see_all_org_webhooks(self, role, webhooks, organizations, - find_users): - username, org_id = next(( - (user['username'], org['id']) - for webhook in webhooks - for org in organizations - for user in find_users(role=role, org=org['id']) - if webhook['organization'] == org['id'] - )) + @pytest.mark.parametrize("role", ["maintainer", "owner"]) + def test_org_staff_can_see_all_org_webhooks(self, role, webhooks, organizations, find_users): + username, org_id = next( + ( + (user["username"], org["id"]) + for webhook in webhooks + for org in organizations + for user in find_users(role=role, org=org["id"]) + if webhook["organization"] == org["id"] + ) + ) - expected_response = [webhook for webhook in webhooks - if webhook['organization'] == org_id] + expected_response = [webhook for webhook in webhooks if webhook["organization"] == org_id] - response = get_method(username, 'webhooks', org_id=org_id) + response = get_method(username, "webhooks", org_id=org_id) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], - ignore_order=True) == {} - - @pytest.mark.parametrize('role', ['worker', 'supervisor']) - def test_member_cannot_see_all_org_webhook(self, role, webhooks, organizations, - find_users, projects): - username, org_id = next(( - (user['username'], org['id']) - for webhook in webhooks - for org in organizations - for user in find_users(role=role, org=org['id']) - if webhook['organization'] == org['id'] - )) + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} + + @pytest.mark.parametrize("role", ["worker", "supervisor"]) + def test_member_cannot_see_all_org_webhook( + self, role, webhooks, organizations, find_users, projects + ): + username, org_id = next( + ( + (user["username"], org["id"]) + for webhook in webhooks + for org in organizations + for user in find_users(role=role, org=org["id"]) + if webhook["organization"] == org["id"] + ) + ) expected_response = [ - webhook for webhook in webhooks - if webhook['organization'] == org_id - and (webhook['owner']['username'] == username - or (webhook['project'] - and projects[webhook['project']]['owner']['username'] == username)) + webhook + for webhook in webhooks + if webhook["organization"] == org_id + and ( + webhook["owner"]["username"] == username + or ( + webhook["project"] + and projects[webhook["project"]]["owner"]["username"] == username + ) + ) ] - response = get_method(username, 'webhooks', org_id=org_id) + response = get_method(username, "webhooks", org_id=org_id) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], - ignore_order=True) == {} - - @pytest.mark.parametrize('role', ['supervisor']) - def test_member_can_see_list_of_project_webhooks_in_org(self, role, webhooks, - organizations, find_users, projects): - username, org_id = next(( - (user['username'], org['id']) - for webhook in webhooks - for org in organizations - for user in find_users(role=role, org=org['id']) - if webhook['organization'] == org['id'] - and webhook['type'] == 'project' - and projects[webhook['project']]['owner']['id'] == user['id'] - )) + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} + + @pytest.mark.parametrize("role", ["supervisor"]) + def test_member_can_see_list_of_project_webhooks_in_org( + self, role, webhooks, organizations, find_users, projects + ): + username, org_id = next( + ( + (user["username"], org["id"]) + for webhook in webhooks + for org in organizations + for user in find_users(role=role, org=org["id"]) + if webhook["organization"] == org["id"] + and webhook["type"] == "project" + and projects[webhook["project"]]["owner"]["id"] == user["id"] + ) + ) expected_response = [ - webhook for webhook in webhooks - if webhook['organization'] == org_id - and webhook['type'] == 'project' - and projects[webhook['project']]['owner']['username'] == username + webhook + for webhook in webhooks + if webhook["organization"] == org_id + and webhook["type"] == "project" + and projects[webhook["project"]]["owner"]["username"] == username ] - response = get_method(username, 'webhooks', org_id=org_id) + response = get_method(username, "webhooks", org_id=org_id) assert response.status_code == HTTPStatus.OK - assert DeepDiff(expected_response, response.json()['results'], - ignore_order=True) == {} + assert DeepDiff(expected_response, response.json()["results"], ignore_order=True) == {} -@pytest.mark.usefixtures('changedb') +@pytest.mark.usefixtures("changedb") class TestPatchWebhooks: WID = 2 def test_sandbox_admin_can_update_any_webhook(self, webhooks, find_users): - username, webhook = next(( - (user['username'], deepcopy(webhook)) - for user in find_users(privilege='admin') - for webhook in webhooks - if webhook['owner']['id'] != user['id'] and webhook['organization'] is None - )) + username, webhook = next( + ( + (user["username"], deepcopy(webhook)) + for user in find_users(privilege="admin") + for webhook in webhooks + if webhook["owner"]["id"] != user["id"] and webhook["organization"] is None + ) + ) patch_data = { - 'target_url': 'http://newexample.com', - 'secret': 'newsecret', - 'events': ['create:task'], - 'is_active': not webhook['is_active'], - 'enable_ssl': not webhook['enable_ssl'], + "target_url": "http://newexample.com", + "secret": "newsecret", + "events": ["create:task"], + "is_active": not webhook["is_active"], + "enable_ssl": not webhook["enable_ssl"], } webhook.update(patch_data) response = patch_method(username, f"webhooks/{webhook['id']}", patch_data) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() - assert DeepDiff(webhook, response.json(), ignore_order=True, - exclude_paths=["root['updated_date']", "root['secret']"]) == {} + assert "secret" not in response.json() + assert ( + DeepDiff( + webhook, + response.json(), + ignore_order=True, + exclude_paths=["root['updated_date']", "root['secret']"], + ) + == {} + ) def test_cannot_update_with_nonexistent_contenttype(self): patch_data = { - 'content_type': 'application/x-www-form-urlencoded', + "content_type": "application/x-www-form-urlencoded", } - response = patch_method('admin2', f'webhooks/{self.WID}', patch_data) + response = patch_method("admin2", f"webhooks/{self.WID}", patch_data) assert response.status_code == HTTPStatus.BAD_REQUEST - @pytest.mark.parametrize('privilege', ['user', 'business']) + @pytest.mark.parametrize("privilege", ["user", "business"]) def test_sandbox_user_can_update_webhook(self, privilege, find_users, webhooks): - username, webhook = next(( - (user['username'], deepcopy(webhook)) - for user in find_users(privilege=privilege) - for webhook in webhooks - if webhook['owner']['id'] == user['id'] - )) - - patch_data = {'target_url': 'http://newexample.com'} + username, webhook = next( + ( + (user["username"], deepcopy(webhook)) + for user in find_users(privilege=privilege) + for webhook in webhooks + if webhook["owner"]["id"] == user["id"] + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) response = patch_method(username, f"webhooks/{webhook['id']}", patch_data) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() - assert DeepDiff(webhook, response.json(), ignore_order=True, - exclude_paths=["root['updated_date']", "root['secret']"]) == {} - - - @pytest.mark.parametrize('privilege', ['worker', 'user', 'business']) + assert "secret" not in response.json() + assert ( + DeepDiff( + webhook, + response.json(), + ignore_order=True, + exclude_paths=["root['updated_date']", "root['secret']"], + ) + == {} + ) + + @pytest.mark.parametrize("privilege", ["worker", "user", "business"]) def test_sandbox_user_cannot_update_webhook(self, privilege, find_users, webhooks): - username, webhook = next(( - (user['username'], deepcopy(webhook)) - for user in find_users(privilege=privilege) - for webhook in webhooks - if webhook['owner']['id'] != user['id'] - )) - - patch_data = {'target_url': 'http://newexample.com'} + username, webhook = next( + ( + (user["username"], deepcopy(webhook)) + for user in find_users(privilege=privilege) + for webhook in webhooks + if webhook["owner"]["id"] != user["id"] + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) response = patch_method(username, f"webhooks/{webhook['id']}", patch_data) @@ -753,300 +823,360 @@ class TestPatchWebhooks: assert response.status_code == HTTPStatus.FORBIDDEN def test_admin_can_update_org_webhook(self, find_users, organizations, webhooks, is_org_member): - org_webhooks = [w for w in webhooks if w['type'] == 'organization'] - admin, oid, webhook = next(( - (u['username'], o['id'], deepcopy(w)) - for u in find_users(privilege='admin') - for o in organizations - for w in org_webhooks - if w['organization'] == o['id'] and not is_org_member(u['id'], o['id']) - )) - - patch_data = {'target_url': 'http://newexample.com'} + org_webhooks = [w for w in webhooks if w["type"] == "organization"] + admin, oid, webhook = next( + ( + (u["username"], o["id"], deepcopy(w)) + for u in find_users(privilege="admin") + for o in organizations + for w in org_webhooks + if w["organization"] == o["id"] and not is_org_member(u["id"], o["id"]) + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) response = patch_method(admin, f"webhooks/{webhook['id']}", patch_data, org_id=oid) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() - assert DeepDiff(webhook, response.json(), ignore_order=True, - exclude_paths=["root['updated_date']", "root['secret']"]) == {} - - @pytest.mark.parametrize('role', ['maintainer', 'owner']) + assert "secret" not in response.json() + assert ( + DeepDiff( + webhook, + response.json(), + ignore_order=True, + exclude_paths=["root['updated_date']", "root['secret']"], + ) + == {} + ) + + @pytest.mark.parametrize("role", ["maintainer", "owner"]) def test_member_can_update_org_webhook(self, role, find_users, organizations, webhooks): - org_webhooks = [w for w in webhooks if w['type'] == 'organization'] - username, oid, webhook = next(( - (u['username'], o['id'], deepcopy(w)) - for o in organizations - for u in find_users(role=role, org=o['id']) - for w in org_webhooks - if w['organization'] == o['id'] - )) - - patch_data = {'target_url': 'http://newexample.com'} + org_webhooks = [w for w in webhooks if w["type"] == "organization"] + username, oid, webhook = next( + ( + (u["username"], o["id"], deepcopy(w)) + for o in organizations + for u in find_users(role=role, org=o["id"]) + for w in org_webhooks + if w["organization"] == o["id"] + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=oid) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() - assert DeepDiff(webhook, response.json(), ignore_order=True, - exclude_paths=["root['updated_date']", "root['secret']"]) == {} - - - @pytest.mark.parametrize('role', ['worker', 'supervisor']) + assert "secret" not in response.json() + assert ( + DeepDiff( + webhook, + response.json(), + ignore_order=True, + exclude_paths=["root['updated_date']", "root['secret']"], + ) + == {} + ) + + @pytest.mark.parametrize("role", ["worker", "supervisor"]) def test_member_cannot_update_org_webhook(self, role, find_users, organizations, webhooks): - org_webhooks = [w for w in webhooks if w['type'] == 'organization'] - username, oid, webhook = next(( - (u['username'], o['id'], deepcopy(w)) - for o in organizations - for u in find_users(role=role, org=o['id']) - for w in org_webhooks - if w['organization'] == o['id'] - )) - - patch_data = {'target_url': 'http://newexample.com'} + org_webhooks = [w for w in webhooks if w["type"] == "organization"] + username, oid, webhook = next( + ( + (u["username"], o["id"], deepcopy(w)) + for o in organizations + for u in find_users(role=role, org=o["id"]) + for w in org_webhooks + if w["organization"] == o["id"] + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=oid) assert response.status_code == HTTPStatus.FORBIDDEN - @pytest.mark.parametrize('role, allow', [ - ('maintainer', True), ('owner', True), - ('supervisor', False), ('worker', False) - ]) - def test_member_can_update_any_project_webhook_in_org(self, role, allow, find_users, - organizations, projects_by_org, webhooks, is_project_staff): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, org_id, webhook = next(( - (u['username'], o['id'], deepcopy(w)) - for o in organizations - for u in find_users(role=role, org=o['id']) - for w in proj_webhooks - for p in projects_by_org.get(o['id'], []) - if w['project'] == p['id'] - and w['organization'] == o['id'] - and not is_project_staff(u['id'], p['id']) - and w['owner']['id'] != u['id'] - )) - - patch_data = {'target_url': 'http://newexample.com'} + @pytest.mark.parametrize( + "role, allow", + [("maintainer", True), ("owner", True), ("supervisor", False), ("worker", False)], + ) + def test_member_can_update_any_project_webhook_in_org( + self, role, allow, find_users, organizations, projects_by_org, webhooks, is_project_staff + ): + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, org_id, webhook = next( + ( + (u["username"], o["id"], deepcopy(w)) + for o in organizations + for u in find_users(role=role, org=o["id"]) + for w in proj_webhooks + for p in projects_by_org.get(o["id"], []) + if w["project"] == p["id"] + and w["organization"] == o["id"] + and not is_project_staff(u["id"], p["id"]) + and w["owner"]["id"] != u["id"] + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) - response = patch_method(username, f"webhooks/{webhook['id']}", - patch_data, org_id=org_id) + response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=org_id) if not allow: assert response.status_code == HTTPStatus.FORBIDDEN else: assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() - assert DeepDiff(webhook, response.json(), ignore_order=True, - exclude_paths=["root['updated_date']", "root['secret']"]) == {} - - @pytest.mark.parametrize('role', ['supervisor']) - def test_member_can_update_project_webhook_in_org(self, role, find_users, - organizations, projects_by_org, webhooks): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, org_id, webhook = next(( - (u['username'], o['id'], deepcopy(w)) - for o in organizations - for u in find_users(role=role, org=o['id']) - for w in proj_webhooks - for p in projects_by_org.get(o['id'], []) - if w['project'] == p['id'] - and w['organization'] == o['id'] - and u['id'] == p['owner']['id'] - )) - - patch_data = {'target_url': 'http://newexample.com'} + assert "secret" not in response.json() + assert ( + DeepDiff( + webhook, + response.json(), + ignore_order=True, + exclude_paths=["root['updated_date']", "root['secret']"], + ) + == {} + ) + + @pytest.mark.parametrize("role", ["supervisor"]) + def test_member_can_update_project_webhook_in_org( + self, role, find_users, organizations, projects_by_org, webhooks + ): + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, org_id, webhook = next( + ( + (u["username"], o["id"], deepcopy(w)) + for o in organizations + for u in find_users(role=role, org=o["id"]) + for w in proj_webhooks + for p in projects_by_org.get(o["id"], []) + if w["project"] == p["id"] + and w["organization"] == o["id"] + and u["id"] == p["owner"]["id"] + ) + ) + + patch_data = {"target_url": "http://newexample.com"} webhook.update(patch_data) - response = patch_method(username, f"webhooks/{webhook['id']}", - patch_data, org_id=org_id) + response = patch_method(username, f"webhooks/{webhook['id']}", patch_data, org_id=org_id) assert response.status_code == HTTPStatus.OK - assert 'secret' not in response.json() - assert DeepDiff(webhook, response.json(), ignore_order=True, - exclude_paths=["root['updated_date']", "root['secret']"]) == {} - - - -@pytest.mark.usefixtures('changedb') + assert "secret" not in response.json() + assert ( + DeepDiff( + webhook, + response.json(), + ignore_order=True, + exclude_paths=["root['updated_date']", "root['secret']"], + ) + == {} + ) + + +@pytest.mark.usefixtures("changedb") class TestDeleteWebhooks: - @pytest.mark.parametrize('privilege, allow', [ - ('user', False), ('business', False), ('admin', True) - ]) - def test_user_can_delete_project_webhook(self, privilege, allow, find_users, - webhooks, projects): + @pytest.mark.parametrize( + "privilege, allow", [("user", False), ("business", False), ("admin", True)] + ) + def test_user_can_delete_project_webhook( + self, privilege, allow, find_users, webhooks, projects + ): users = find_users(privilege=privilege) - username, webhook_id = next(( - (user['username'], webhook['id']) - for webhook in webhooks for user in users - if webhook['type'] == 'project' - and webhook['organization'] is None - and webhook['owner']['id'] != user['id'] - and projects[webhook['project']]['owner']['id'] != user['id'] - )) + username, webhook_id = next( + ( + (user["username"], webhook["id"]) + for webhook in webhooks + for user in users + if webhook["type"] == "project" + and webhook["organization"] is None + and webhook["owner"]["id"] != user["id"] + and projects[webhook["project"]]["owner"]["id"] != user["id"] + ) + ) if not allow: - response = delete_method(username, f'webhooks/{webhook_id}') + response = delete_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.FORBIDDEN else: - response = delete_method(username, f'webhooks/{webhook_id}') + response = delete_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}') + response = get_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NOT_FOUND - def test_admin_can_delete_project_webhook_in_org(self, find_users, webhooks, - projects, is_org_member): - admins = find_users(privilege='admin') - username, webhook_id = next(( - (user['username'], webhook['id']) - for user in admins - for webhook in webhooks - if webhook['type'] == 'project' - and webhook['organization'] is not None - and webhook['owner']['id'] != user['id'] - and projects[webhook['project']]['owner']['id'] != user['id'] - and not is_org_member(user['id'], webhook['organization']) - )) - - response = delete_method(username, f'webhooks/{webhook_id}') + def test_admin_can_delete_project_webhook_in_org( + self, find_users, webhooks, projects, is_org_member + ): + admins = find_users(privilege="admin") + username, webhook_id = next( + ( + (user["username"], webhook["id"]) + for user in admins + for webhook in webhooks + if webhook["type"] == "project" + and webhook["organization"] is not None + and webhook["owner"]["id"] != user["id"] + and projects[webhook["project"]]["owner"]["id"] != user["id"] + and not is_org_member(user["id"], webhook["organization"]) + ) + ) + + response = delete_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}') + response = get_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NOT_FOUND def test_admin_can_delete_org_webhook(self, find_users, webhooks, is_org_member): - admins = find_users(privilege='admin') - username, webhook_id = next(( - (user['username'], webhook['id']) - for user in admins - for webhook in webhooks - if webhook['type'] == 'organization' - and webhook['organization'] is not None - and webhook['owner']['id'] != user['id'] - and not is_org_member(user['id'], webhook['organization']) - )) - - response = delete_method(username, f'webhooks/{webhook_id}') + admins = find_users(privilege="admin") + username, webhook_id = next( + ( + (user["username"], webhook["id"]) + for user in admins + for webhook in webhooks + if webhook["type"] == "organization" + and webhook["organization"] is not None + and webhook["owner"]["id"] != user["id"] + and not is_org_member(user["id"], webhook["organization"]) + ) + ) + + response = delete_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}') + response = get_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NOT_FOUND - @pytest.mark.parametrize('privilege', ['user', 'business']) - def test_project_owner_can_delete_project_webhook(self, privilege, find_users, - webhooks, projects): + @pytest.mark.parametrize("privilege", ["user", "business"]) + def test_project_owner_can_delete_project_webhook( + self, privilege, find_users, webhooks, projects + ): users = find_users(privilege=privilege) - username, webhook_id = next(( - (user['username'], webhook['id']) - for user in users - for webhook in webhooks - if webhook['type'] == 'project' - and webhook['organization'] is None - and projects[webhook['project']]['owner']['id'] == user['id'] - )) - - response = delete_method(username, f'webhooks/{webhook_id}') + username, webhook_id = next( + ( + (user["username"], webhook["id"]) + for user in users + for webhook in webhooks + if webhook["type"] == "project" + and webhook["organization"] is None + and projects[webhook["project"]]["owner"]["id"] == user["id"] + ) + ) + + response = delete_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}') + response = get_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NOT_FOUND - @pytest.mark.parametrize('privilege', ['user', 'business']) - def test_webhook_owner_can_delete_project_webhook(self, privilege, find_users, - webhooks, projects): + @pytest.mark.parametrize("privilege", ["user", "business"]) + def test_webhook_owner_can_delete_project_webhook( + self, privilege, find_users, webhooks, projects + ): users = find_users(privilege=privilege) - username, webhook_id = next(( - (user['username'], webhook['id']) - for user in users - for webhook in webhooks - if webhook['type'] == 'project' - and webhook['organization'] is None - and webhook['owner']['id'] == user['id'] - )) - - response = delete_method(username, f'webhooks/{webhook_id}') + username, webhook_id = next( + ( + (user["username"], webhook["id"]) + for user in users + for webhook in webhooks + if webhook["type"] == "project" + and webhook["organization"] is None + and webhook["owner"]["id"] == user["id"] + ) + ) + + response = delete_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}') + response = get_method(username, f"webhooks/{webhook_id}") assert response.status_code == HTTPStatus.NOT_FOUND - @pytest.mark.parametrize('role, allow', [ - ('owner', True), ('maintainer', True), - ('worker', False), ('supervisor', False) - ]) - def test_member_can_delete_org_webhook(self, role, allow, find_users, organizations, - webhooks): - org_webhooks = [w for w in webhooks if w['type'] == 'organization'] + @pytest.mark.parametrize( + "role, allow", + [("owner", True), ("maintainer", True), ("worker", False), ("supervisor", False)], + ) + def test_member_can_delete_org_webhook(self, role, allow, find_users, organizations, webhooks): + org_webhooks = [w for w in webhooks if w["type"] == "organization"] print(org_webhooks) - username, org_id, webhook_id = next(( - (user['username'], org['id'], webhook['id']) - for org in organizations - for webhook in org_webhooks - for user in find_users(role=role, org=org['id']) - if webhook['organization'] == org['id'] - )) + username, org_id, webhook_id = next( + ( + (user["username"], org["id"], webhook["id"]) + for org in organizations + for webhook in org_webhooks + for user in find_users(role=role, org=org["id"]) + if webhook["organization"] == org["id"] + ) + ) if not allow: - response = delete_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.FORBIDDEN else: - response = delete_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = get_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.NOT_FOUND - @pytest.mark.parametrize('role, allow', [ - ('owner', True), ('maintainer', True), - ('worker', False), ('supervisor', False) - ]) - def test_member_can_delete_project_webhook_in_org(self, role, allow, find_users, - organizations, projects, webhooks): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, org_id, webhook_id = next(( - (user['username'], webhook['organization'], webhook['id']) - for org in organizations - for user in find_users(role=role, org=org['id']) - for webhook in proj_webhooks - if webhook['organization'] - and webhook['organization'] == org['id'] - and projects[webhook['project']]['owner']['id'] != user['id'] - and webhook['owner']['id'] != user['id'] - )) + @pytest.mark.parametrize( + "role, allow", + [("owner", True), ("maintainer", True), ("worker", False), ("supervisor", False)], + ) + def test_member_can_delete_project_webhook_in_org( + self, role, allow, find_users, organizations, projects, webhooks + ): + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, org_id, webhook_id = next( + ( + (user["username"], webhook["organization"], webhook["id"]) + for org in organizations + for user in find_users(role=role, org=org["id"]) + for webhook in proj_webhooks + if webhook["organization"] + and webhook["organization"] == org["id"] + and projects[webhook["project"]]["owner"]["id"] != user["id"] + and webhook["owner"]["id"] != user["id"] + ) + ) if not allow: - response = delete_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.FORBIDDEN else: - response = delete_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = get_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.NOT_FOUND - @pytest.mark.parametrize('role', ['supervisor']) - def test_member_webhook_staff_can_delete_project_webhook_in_org(self, role, - find_users, organizations, projects, webhooks): - proj_webhooks = [w for w in webhooks if w['type'] == 'project'] - username, org_id, webhook_id = next(( - (user['username'], webhook['organization'], webhook['id']) - for org in organizations - for user in find_users(role=role, org=org['id']) - for webhook in proj_webhooks - if webhook['organization'] - and webhook['organization'] == org['id'] - and (projects[webhook['project']]['owner']['id'] == user['id'] - or webhook['owner']['id'] == user['id']) - )) - - response = delete_method(username, f'webhooks/{webhook_id}', org_id=org_id) + @pytest.mark.parametrize("role", ["supervisor"]) + def test_member_webhook_staff_can_delete_project_webhook_in_org( + self, role, find_users, organizations, projects, webhooks + ): + proj_webhooks = [w for w in webhooks if w["type"] == "project"] + username, org_id, webhook_id = next( + ( + (user["username"], webhook["organization"], webhook["id"]) + for org in organizations + for user in find_users(role=role, org=org["id"]) + for webhook in proj_webhooks + if webhook["organization"] + and webhook["organization"] == org["id"] + and ( + projects[webhook["project"]]["owner"]["id"] == user["id"] + or webhook["owner"]["id"] == user["id"] + ) + ) + ) + + response = delete_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.NO_CONTENT - response = get_method(username, f'webhooks/{webhook_id}', org_id=org_id) + response = get_method(username, f"webhooks/{webhook_id}", org_id=org_id) assert response.status_code == HTTPStatus.NOT_FOUND diff --git a/tests/python/shared/fixtures/data.py b/tests/python/shared/fixtures/data.py index e585af97..81c5091e 100644 --- a/tests/python/shared/fixtures/data.py +++ b/tests/python/shared/fixtures/data.py @@ -2,17 +2,20 @@ # # SPDX-License-Identifier: MIT -import pytest import json import os.path as osp + +import pytest + from shared.utils.config import ASSETS_DIR -CVAT_DB_DIR = osp.join(ASSETS_DIR, 'cvat_db') +CVAT_DB_DIR = osp.join(ASSETS_DIR, "cvat_db") + class Container: - def __init__(self, data, key='id'): + def __init__(self, data, key="id"): self.raw_data = data - self.map_data = { obj[key]: obj for obj in data } + self.map_data = {obj[key]: obj for obj in data} @property def raw(self): @@ -33,153 +36,186 @@ class Container: return self.raw_data[key] return self.map_data[key] -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def users(): - with open(osp.join(ASSETS_DIR, 'users.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "users.json")) as f: + return Container(json.load(f)["results"]) + -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def organizations(): - with open(osp.join(ASSETS_DIR, 'organizations.json')) as f: + with open(osp.join(ASSETS_DIR, "organizations.json")) as f: return Container(json.load(f)) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def memberships(): - with open(osp.join(ASSETS_DIR, 'memberships.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "memberships.json")) as f: + return Container(json.load(f)["results"]) + -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def tasks(): - with open(osp.join(ASSETS_DIR, 'tasks.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "tasks.json")) as f: + return Container(json.load(f)["results"]) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def projects(): - with open(osp.join(ASSETS_DIR, 'projects.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "projects.json")) as f: + return Container(json.load(f)["results"]) + -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def jobs(): - with open(osp.join(ASSETS_DIR, 'jobs.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "jobs.json")) as f: + return Container(json.load(f)["results"]) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def invitations(): - with open(osp.join(ASSETS_DIR, 'invitations.json')) as f: - return Container(json.load(f)['results'], key='key') + with open(osp.join(ASSETS_DIR, "invitations.json")) as f: + return Container(json.load(f)["results"], key="key") + -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def annotations(): - with open(osp.join(ASSETS_DIR, 'annotations.json')) as f: + with open(osp.join(ASSETS_DIR, "annotations.json")) as f: return json.load(f) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def cloud_storages(): - with open(osp.join(ASSETS_DIR, 'cloudstorages.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "cloudstorages.json")) as f: + return Container(json.load(f)["results"]) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def issues(): - with open(osp.join(ASSETS_DIR, 'issues.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "issues.json")) as f: + return Container(json.load(f)["results"]) + -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def webhooks(): - with open(osp.join(ASSETS_DIR, 'webhooks.json')) as f: - return Container(json.load(f)['results']) + with open(osp.join(ASSETS_DIR, "webhooks.json")) as f: + return Container(json.load(f)["results"]) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def users_by_name(users): - return {user['username']: user for user in users} + return {user["username"]: user for user in users} + -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def jobs_by_org(tasks, jobs): data = {} for job in jobs: - data.setdefault(tasks[job['task_id']]['organization'], []).append(job) - data[''] = data.pop(None, []) + data.setdefault(tasks[job["task_id"]]["organization"], []).append(job) + data[""] = data.pop(None, []) return data -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def projects_by_org(projects): data = {} for project in projects: - data.setdefault(project['organization'], []).append(project) - data[''] = data.pop(None, []) + data.setdefault(project["organization"], []).append(project) + data[""] = data.pop(None, []) return data -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def tasks_by_org(tasks): data = {} for task in tasks: - data.setdefault(task['organization'], []).append(task) - data[''] = data.pop(None, []) + data.setdefault(task["organization"], []).append(task) + data[""] = data.pop(None, []) return data -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def issues_by_org(tasks, jobs, issues): data = {} for issue in issues: - data.setdefault(tasks[jobs[issue['job']]['task_id']]['organization'], []).append(issue) - data[''] = data.pop(None, []) + data.setdefault(tasks[jobs[issue["job"]]["task_id"]]["organization"], []).append(issue) + data[""] = data.pop(None, []) return data -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def assignee_id(): def get_id(data): - if data.get('assignee') is not None: - return data['assignee']['id'] + if data.get("assignee") is not None: + return data["assignee"]["id"] + return get_id + def ownership(func): def wrap(user_id, resource_id): if resource_id is None: return False return func(user_id, resource_id) + return wrap -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def is_project_staff(projects, assignee_id): @ownership def check(user_id, pid): - return user_id == projects[pid]['owner']['id'] or \ - user_id == assignee_id(projects[pid]) + return user_id == projects[pid]["owner"]["id"] or user_id == assignee_id(projects[pid]) + return check -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def is_task_staff(tasks, is_project_staff, assignee_id): @ownership def check(user_id, tid): - return user_id == tasks[tid]['owner']['id'] or \ - user_id == assignee_id(tasks[tid]) or \ - is_project_staff(user_id, tasks[tid]['project_id']) + return ( + user_id == tasks[tid]["owner"]["id"] + or user_id == assignee_id(tasks[tid]) + or is_project_staff(user_id, tasks[tid]["project_id"]) + ) + return check -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def is_job_staff(jobs, is_task_staff, assignee_id): @ownership def check(user_id, jid): - return user_id == assignee_id(jobs[jid]) or \ - is_task_staff(user_id, jobs[jid]['task_id']) + return user_id == assignee_id(jobs[jid]) or is_task_staff(user_id, jobs[jid]["task_id"]) + return check -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def is_issue_staff(issues, jobs, assignee_id): @ownership def check(user_id, issue_id): - return user_id == issues[issue_id]['owner']['id'] or \ - user_id == assignee_id(issues[issue_id]) or \ - user_id == assignee_id(jobs[issues[issue_id]['job']]) + return ( + user_id == issues[issue_id]["owner"]["id"] + or user_id == assignee_id(issues[issue_id]) + or user_id == assignee_id(jobs[issues[issue_id]["job"]]) + ) + return check -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def is_issue_admin(issues, jobs, is_task_staff): @ownership def check(user_id, issue_id): - return is_task_staff(user_id, jobs[issues[issue_id]['job']]['task_id']) + return is_task_staff(user_id, jobs[issues[issue_id]["job"]]["task_id"]) + return check -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def find_users(test_db): def find(**kwargs): assert len(kwargs) > 0 @@ -188,115 +224,149 @@ def find_users(test_db): data = test_db kwargs = dict(filter(lambda a: a[1] is not None, kwargs.items())) for field, value in kwargs.items(): - if field.startswith('exclude_'): - field = field.split('_', maxsplit=1)[1] - exclude_rows = set(v['id'] for v in - filter(lambda a: a[field] == value, test_db)) - data = list(filter(lambda a: a['id'] not in exclude_rows, data)) + if field.startswith("exclude_"): + field = field.split("_", maxsplit=1)[1] + exclude_rows = set(v["id"] for v in filter(lambda a: a[field] == value, test_db)) + data = list(filter(lambda a: a["id"] not in exclude_rows, data)) else: data = list(filter(lambda a: a[field] == value, data)) return data + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def test_db(users, users_by_name, memberships): data = [] - fields = ['username', 'id', 'privilege', 'role', 'org', 'membership_id'] + fields = ["username", "id", "privilege", "role", "org", "membership_id"] + def add_row(**kwargs): data.append({field: kwargs.get(field) for field in fields}) for user in users: - for group in user['groups']: - add_row(username=user['username'], id=user['id'], privilege=group) + for group in user["groups"]: + add_row(username=user["username"], id=user["id"], privilege=group) for membership in memberships: - username = membership['user']['username'] - for group in users_by_name[username]['groups']: - add_row(username=username, role=membership['role'], privilege=group, - id=membership['user']['id'], org=membership['organization'], - membership_id=membership['id']) + username = membership["user"]["username"] + for group in users_by_name[username]["groups"]: + add_row( + username=username, + role=membership["role"], + privilege=group, + id=membership["user"]["id"], + org=membership["organization"], + membership_id=membership["id"], + ) return data -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def org_staff(memberships): def find(org_id): - if org_id in ['', None]: + if org_id in ["", None]: return set() else: - return set(m['user']['id'] for m in memberships - if m['role'] in ['maintainer', 'owner'] and m['user'] is not None - and m['organization'] == org_id) + return set( + m["user"]["id"] + for m in memberships + if m["role"] in ["maintainer", "owner"] + and m["user"] is not None + and m["organization"] == org_id + ) + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def is_org_member(memberships): def check(user_id, org_id): - if org_id in ['', None]: + if org_id in ["", None]: return True else: - return user_id in set(m['user']['id'] for m in memberships - if m['user'] is not None and m['organization'] == org_id) + return user_id in set( + m["user"]["id"] + for m in memberships + if m["user"] is not None and m["organization"] == org_id + ) + return check -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def find_job_staff_user(is_job_staff): def find(jobs, users, is_staff, wo_jobs=None): for job in jobs: - if wo_jobs is not None and job['id'] in wo_jobs: + if wo_jobs is not None and job["id"] in wo_jobs: continue for user in users: - if is_staff == is_job_staff(user['id'], job['id']): - return user['username'], job['id'] + if is_staff == is_job_staff(user["id"], job["id"]): + return user["username"], job["id"] return None, None + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def find_task_staff_user(is_task_staff): def find(tasks, users, is_staff, wo_tasks=None): for task in tasks: - if wo_tasks is not None and task['id'] in wo_tasks: + if wo_tasks is not None and task["id"] in wo_tasks: continue for user in users: - if is_staff == is_task_staff(user['id'], task['id']): - return user['username'], task['id'] + if is_staff == is_task_staff(user["id"], task["id"]): + return user["username"], task["id"] return None, None + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def find_issue_staff_user(is_issue_staff, is_issue_admin): def find(issues, users, is_staff, is_admin): for issue in issues: for user in users: - i_admin, i_staff = is_issue_admin(user['id'], issue['id']), is_issue_staff(user['id'], issue['id']) - if (is_admin is None and (i_staff or i_admin) == is_staff) \ - or (is_admin == i_admin and is_staff == i_staff): - return user['username'], issue['id'] + i_admin, i_staff = is_issue_admin(user["id"], issue["id"]), is_issue_staff( + user["id"], issue["id"] + ) + if (is_admin is None and (i_staff or i_admin) == is_staff) or ( + is_admin == i_admin and is_staff == i_staff + ): + return user["username"], issue["id"] return None, None + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def filter_jobs_with_shapes(annotations): def find(jobs): - return list(filter(lambda j: annotations['job'][str(j['id'])]['shapes'], jobs)) + return list(filter(lambda j: annotations["job"][str(j["id"])]["shapes"], jobs)) + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def filter_tasks_with_shapes(annotations): def find(tasks): - return list(filter(lambda t: annotations['task'][str(t['id'])]['shapes'], tasks)) + return list(filter(lambda t: annotations["task"][str(t["id"])]["shapes"], tasks)) + return find -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def jobs_with_shapes(jobs, filter_jobs_with_shapes): return filter_jobs_with_shapes(jobs) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def tasks_with_shapes(tasks, filter_tasks_with_shapes): return filter_tasks_with_shapes(tasks) -@pytest.fixture(scope='session') + +@pytest.fixture(scope="session") def admin_user(users): for user in users: if user["is_superuser"] and user["is_active"]: diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index d74a6bb0..06090bd3 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +import os import os.path as osp import re from http import HTTPStatus @@ -9,8 +10,8 @@ from subprocess import PIPE, CalledProcessError, run from time import sleep import pytest -import os import requests + from shared.utils.config import ASSETS_DIR, get_api_url CVAT_ROOT_DIR = __file__[: __file__.rfind(osp.join("tests", ""))] @@ -30,7 +31,7 @@ DC_FILES = [ for dc_file in ( "docker-compose.dev.yml", "tests/docker-compose.minio.yml", - "tests/docker-compose.webhook.yml" + "tests/docker-compose.webhook.yml", ) ] + CONTAINER_NAME_FILES @@ -95,12 +96,16 @@ def _run(command, capture_output=True): "Add `-s` option to see more details" ) + def _kube_get_server_pod_name(): output, _ = _run("kubectl get pods -l component=server -o jsonpath={.items[0].metadata.name}") return output + def _kube_get_db_pod_name(): - output, _ = _run("kubectl get pods -l app.kubernetes.io/name=postgresql -o jsonpath={.items[0].metadata.name}") + output, _ = _run( + "kubectl get pods -l app.kubernetes.io/name=postgresql -o jsonpath={.items[0].metadata.name}" + ) return output @@ -131,30 +136,35 @@ def kube_exec_cvat_db(command): def docker_restore_db(): - docker_exec_cvat_db( - "psql -U root -d postgres -v from=test_db -v to=cvat -f /tmp/restore.sql" - ) + docker_exec_cvat_db("psql -U root -d postgres -v from=test_db -v to=cvat -f /tmp/restore.sql") + def kube_restore_db(): kube_exec_cvat_db( - ["/bin/sh", "-c", "PGPASSWORD=cvat_postgresql_postgres psql -U postgres -d postgres -v from=test_db -v to=cvat -f /tmp/restore.sql"] + [ + "/bin/sh", + "-c", + "PGPASSWORD=cvat_postgresql_postgres psql -U postgres -d postgres -v from=test_db -v to=cvat -f /tmp/restore.sql", + ] ) + def running_containers(): return [cn for cn in _run("docker ps --format {{.Names}}")[0].split("\n") if cn] def dump_db(): - if 'test_cvat_server_1' not in running_containers(): + if "test_cvat_server_1" not in running_containers(): pytest.exit("CVAT is not running") with open(osp.join(CVAT_DB_DIR, "data.json"), "w") as f: try: - run( # nosec + run( # nosec "docker exec test_cvat_server_1 \ python manage.py dumpdata \ --indent 2 --natural-foreign \ --exclude=auth.permission --exclude=contenttypes".split(), - stdout=f, check=True + stdout=f, + check=True, ) except CalledProcessError: pytest.exit("Database dump failed.\n") @@ -162,15 +172,9 @@ def dump_db(): def create_compose_files(): for filename in CONTAINER_NAME_FILES: - with open(filename.replace(".tests.yml", ".yml"), "r") as dcf, open( - filename, "w" - ) as ndcf: + with open(filename.replace(".tests.yml", ".yml"), "r") as dcf, open(filename, "w") as ndcf: ndcf.writelines( - [ - line - for line in dcf.readlines() - if not re.match("^.+container_name.+$", line) - ] + [line for line in dcf.readlines() if not re.match("^.+container_name.+$", line)] ) @@ -195,6 +199,7 @@ def docker_restore_data_volumes(): ) docker_exec_cvat("tar --strip 3 -xjf /tmp/cvat_data.tar.bz2 -C /home/django/data/") + def kube_restore_data_volumes(): pod_name = _kube_get_server_pod_name() kube_cp( @@ -213,16 +218,15 @@ def start_services(rebuild=False): _run( f"docker-compose -p {PREFIX} " - + "--env-file " + osp.join(CVAT_ROOT_DIR, "tests", "python", "webhook_receiver", ".env") + + "--env-file " + + osp.join(CVAT_ROOT_DIR, "tests", "python", "webhook_receiver", ".env") + f" -f {' -f '.join(DC_FILES)} up -d " + "--build" * rebuild, capture_output=False, ) docker_restore_data_volumes() - docker_cp( - osp.join(CVAT_DB_DIR, "restore.sql"), f"{PREFIX}_cvat_db_1:/tmp/restore.sql" - ) + docker_cp(osp.join(CVAT_DB_DIR, "restore.sql"), f"{PREFIX}_cvat_db_1:/tmp/restore.sql") docker_cp(osp.join(CVAT_DB_DIR, "data.json"), f"{PREFIX}_cvat_server_1:/tmp/data.json") @@ -235,11 +239,13 @@ def services(request): dumpdb = request.config.getoption("--dumpdb") platform = request.config.getoption("--platform") - if platform == 'kube' and any((stop, start, rebuild, cleanup, dumpdb)): - raise Exception('''--platform=kube is not compatible with any of the other options - --stop-services --start-services --rebuild --cleanup --dumpdb''') + if platform == "kube" and any((stop, start, rebuild, cleanup, dumpdb)): + raise Exception( + """--platform=kube is not compatible with any of the other options + --stop-services --start-services --rebuild --cleanup --dumpdb""" + ) - if platform == 'local': + if platform == "local": if start and stop: raise Exception("--start-services and --stop-services are incompatible") @@ -258,7 +264,8 @@ def services(request): if stop: _run( f"docker-compose -p {PREFIX} " - + "--env-file " + osp.join(CVAT_ROOT_DIR, "tests", "python", "webhook_receiver", ".env") + + "--env-file " + + osp.join(CVAT_ROOT_DIR, "tests", "python", "webhook_receiver", ".env") + f" -f {' -f '.join(DC_FILES)} down -v", capture_output=False, ) @@ -273,22 +280,18 @@ def services(request): ) if start: - pytest.exit( - "All necessary containers have been created and started.", returncode=0 - ) + pytest.exit("All necessary containers have been created and started.", returncode=0) yield docker_restore_db() docker_exec_cvat_db("dropdb test_db") - elif platform == 'kube': + elif platform == "kube": kube_restore_data_volumes() server_pod_name = _kube_get_server_pod_name() db_pod_name = _kube_get_db_pod_name() - kube_cp( - osp.join(CVAT_DB_DIR, "restore.sql"), f"{db_pod_name}:/tmp/restore.sql" - ) + kube_cp(osp.join(CVAT_DB_DIR, "restore.sql"), f"{db_pod_name}:/tmp/restore.sql") kube_cp(osp.join(CVAT_DB_DIR, "data.json"), f"{server_pod_name}:/tmp/data.json") wait_for_server() @@ -296,7 +299,11 @@ def services(request): kube_exec_cvat("python manage.py loaddata /tmp/data.json") kube_exec_cvat_db( - ["/bin/sh", "-c", "PGPASSWORD=cvat_postgresql_postgres psql -U postgres -d postgres -v from=cvat -v to=test_db -f /tmp/restore.sql"] + [ + "/bin/sh", + "-c", + "PGPASSWORD=cvat_postgresql_postgres psql -U postgres -d postgres -v from=cvat -v to=test_db -f /tmp/restore.sql", + ] ) yield diff --git a/tests/python/shared/fixtures/util.py b/tests/python/shared/fixtures/util.py index 6d6c5aea..ac0135f7 100644 --- a/tests/python/shared/fixtures/util.py +++ b/tests/python/shared/fixtures/util.py @@ -4,6 +4,7 @@ import io import logging + import pytest diff --git a/tests/python/shared/utils/config.py b/tests/python/shared/utils/config.py index a3b2daf9..961114ff 100644 --- a/tests/python/shared/utils/config.py +++ b/tests/python/shared/utils/config.py @@ -3,51 +3,66 @@ # SPDX-License-Identifier: MIT import os.path as osp + import requests from cvat_sdk.api_client import ApiClient, Configuration -ROOT_DIR = __file__[:__file__.rfind(osp.join("utils", ""))] -ASSETS_DIR = osp.abspath(osp.join(ROOT_DIR, 'assets')) +ROOT_DIR = __file__[: __file__.rfind(osp.join("utils", ""))] +ASSETS_DIR = osp.abspath(osp.join(ROOT_DIR, "assets")) # Suppress the warning from Bandit about hardcoded passwords -USER_PASS = '!Q@W#E$R' # nosec -BASE_URL = 'http://localhost:8080' -API_URL = BASE_URL + '/api/' +USER_PASS = "!Q@W#E$R" # nosec +BASE_URL = "http://localhost:8080" +API_URL = BASE_URL + "/api/" # MiniIO settings -MINIO_KEY = 'minio_access_key' -MINIO_SECRET_KEY = 'minio_secret_key' # nosec -MINIO_ENDPOINT_URL = 'http://localhost:9000' +MINIO_KEY = "minio_access_key" +MINIO_SECRET_KEY = "minio_secret_key" # nosec +MINIO_ENDPOINT_URL = "http://localhost:9000" + def _to_query_params(**kwargs): - return '&'.join([f'{k}={v}' for k,v in kwargs.items()]) + return "&".join([f"{k}={v}" for k, v in kwargs.items()]) + def get_server_url(endpoint, **kwargs): - return BASE_URL + '/' + endpoint + '?' + _to_query_params(**kwargs) + return BASE_URL + "/" + endpoint + "?" + _to_query_params(**kwargs) + def get_api_url(endpoint, **kwargs): - return API_URL + endpoint + '?' + _to_query_params(**kwargs) + return API_URL + endpoint + "?" + _to_query_params(**kwargs) + def get_method(username, endpoint, **kwargs): return requests.get(get_api_url(endpoint, **kwargs), auth=(username, USER_PASS)) + def options_method(username, endpoint, **kwargs): return requests.options(get_api_url(endpoint, **kwargs), auth=(username, USER_PASS)) + def delete_method(username, endpoint, **kwargs): return requests.delete(get_api_url(endpoint, **kwargs), auth=(username, USER_PASS)) + def patch_method(username, endpoint, data, **kwargs): return requests.patch(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) + def post_method(username, endpoint, data, **kwargs): return requests.post(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) + def post_files_method(username, endpoint, data, files, **kwargs): - return requests.post(get_api_url(endpoint, **kwargs), data=data, files=files, auth=(username, USER_PASS)) + return requests.post( + get_api_url(endpoint, **kwargs), data=data, files=files, auth=(username, USER_PASS) + ) + def server_get(username, endpoint, **kwargs): return requests.get(get_server_url(endpoint, **kwargs), auth=(username, USER_PASS)) + def make_api_client(user: str, *, password: str = None) -> ApiClient: - return ApiClient(configuration=Configuration(host=BASE_URL, - username=user, password=password or USER_PASS)) + return ApiClient( + configuration=Configuration(host=BASE_URL, username=user, password=password or USER_PASS) + ) diff --git a/tests/python/shared/utils/dump_objects.py b/tests/python/shared/utils/dump_objects.py index aa7b99e4..a3202954 100644 --- a/tests/python/shared/utils/dump_objects.py +++ b/tests/python/shared/utils/dump_objects.py @@ -2,24 +2,35 @@ # # SPDX-License-Identifier: MIT -import os.path as osp -from config import get_method, ASSETS_DIR import json +import os.path as osp + +from config import ASSETS_DIR, get_method -if __name__ == '__main__': +if __name__ == "__main__": annotations = {} - for obj in ['user', 'project', 'task', 'job', 'organization', 'membership', - 'invitation', 'cloudstorage', 'issue', 'webhook']: - response = get_method('admin1', f'{obj}s', page_size='all') - with open(osp.join(ASSETS_DIR, f'{obj}s.json'), 'w') as f: + for obj in [ + "user", + "project", + "task", + "job", + "organization", + "membership", + "invitation", + "cloudstorage", + "issue", + "webhook", + ]: + response = get_method("admin1", f"{obj}s", page_size="all") + with open(osp.join(ASSETS_DIR, f"{obj}s.json"), "w") as f: json.dump(response.json(), f, indent=2, sort_keys=True) - if obj in ['job', 'task']: + if obj in ["job", "task"]: annotations[obj] = {} - for _obj in response.json()['results']: + for _obj in response.json()["results"]: oid = _obj["id"] - response = get_method('admin1', f'{obj}s/{oid}/annotations') + response = get_method("admin1", f"{obj}s/{oid}/annotations") annotations[obj][oid] = response.json() - with open(osp.join(ASSETS_DIR, f'annotations.json'), 'w') as f: + with open(osp.join(ASSETS_DIR, f"annotations.json"), "w") as f: json.dump(annotations, f, indent=2, sort_keys=True) diff --git a/tests/python/shared/utils/helpers.py b/tests/python/shared/utils/helpers.py index 3c93d4e2..872c7085 100644 --- a/tests/python/shared/utils/helpers.py +++ b/tests/python/shared/utils/helpers.py @@ -2,24 +2,26 @@ # # SPDX-License-Identifier: MIT +from io import BytesIO from typing import List + from PIL import Image -from io import BytesIO -def generate_image_file(filename='image.png', size=(50, 50)): +def generate_image_file(filename="image.png", size=(50, 50)): f = BytesIO() - image = Image.new('RGB', size=size) - image.save(f, 'jpeg') + image = Image.new("RGB", size=size) + image.save(f, "jpeg") f.name = filename f.seek(0) return f + def generate_image_files(count) -> List[BytesIO]: images = [] for i in range(count): - image = generate_image_file(f'{i}.jpeg') + image = generate_image_file(f"{i}.jpeg") images.append(image) return images diff --git a/tests/python/webhook_receiver/server.py b/tests/python/webhook_receiver/server.py index fe075196..255a4e1f 100644 --- a/tests/python/webhook_receiver/server.py +++ b/tests/python/webhook_receiver/server.py @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: MIT -import re import os +import re from http import HTTPStatus from http.server import BaseHTTPRequestHandler, HTTPServer