diff --git a/CHANGELOG.md b/CHANGELOG.md index 711172b9..0c8aea8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Task creation progressbar bug () - Removed Python dependency ``open3d`` which brought different issues to the building process - Analytics not accessible when https is enabled () -- Dataset import in an organization () +- Dataset import in an organization (, ) - Updated minimist npm package to v1.2.6 () ### Security diff --git a/tests/rest_api/assets/annotations.json b/tests/rest_api/assets/annotations.json index d68fc662..00b71b06 100644 --- a/tests/rest_api/assets/annotations.json +++ b/tests/rest_api/assets/annotations.json @@ -297,6 +297,49 @@ "tags": [], "tracks": [], "version": 0 + }, + "17": { + "shapes": [ + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 34, + "label_id": 16, + "occluded": false, + "points": [ + 106.36066411239153, + 85.1515964240134, + 240.08352490421748, + 241.26526181354166 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 35, + "label_id": 16, + "occluded": false, + "points": [ + 414.29522752496996, + 124.8035516093205, + 522.2641509433943, + 286.75693673695605 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 0 } }, "task": { @@ -585,6 +628,49 @@ "tags": [], "tracks": [], "version": 0 + }, + "13": { + "shapes": [ + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 34, + "label_id": 16, + "occluded": false, + "points": [ + 106.36066411239153, + 85.1515964240134, + 240.08352490421748, + 241.26526181354166 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 35, + "label_id": 16, + "occluded": false, + "points": [ + 414.29522752496996, + 124.8035516093205, + 522.2641509433943, + 286.75693673695605 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 0 } } } \ No newline at end of file diff --git a/tests/rest_api/assets/cvat_db/cvat_data.tar.bz2 b/tests/rest_api/assets/cvat_db/cvat_data.tar.bz2 index 021a0344..cb9f2f9e 100644 Binary files a/tests/rest_api/assets/cvat_db/cvat_data.tar.bz2 and b/tests/rest_api/assets/cvat_db/cvat_data.tar.bz2 differ diff --git a/tests/rest_api/assets/cvat_db/data.json b/tests/rest_api/assets/cvat_db/data.json index f138d871..f09c6d77 100644 --- a/tests/rest_api/assets/cvat_db/data.json +++ b/tests/rest_api/assets/cvat_db/data.json @@ -1413,7 +1413,7 @@ "pk": 1, "fields": { "password": "pbkdf2_sha256$260000$DevmxlmLwciP1P6sZs2Qag$U9DFtjTWx96Sk95qY6UXVcvpdQEP2LcoFBftk5D2RKY=", - "last_login": "2022-03-05T09:34:33.293Z", + "last_login": "2022-06-08T08:32:30.152Z", "is_superuser": true, "username": "admin1", "first_name": "Admin", @@ -2208,6 +2208,14 @@ "expire_date": "2022-03-31T07:22:55.934Z" } }, +{ + "model": "sessions.session", + "pk": "g5dq9vpt965l4v12hq2e2mtx3cyoofwi", + "fields": { + "session_data": ".eJxVjEEOwiAQRe_C2hAZ6BRcuvcMZGagtmogKe3KeHfbpAvd_vfef6tI6zLGteU5TkldlFGn341JnrnsID2o3KuWWpZ5Yr0r-qBN32rKr-vh_h2M1MatZtfjAJ6DdIQZhsw-gO2tSCc-9WiyBxc4kMdBMLnOIhMyuPMmWTDq8wXrITeF:1nyr78:_kk9OqBNFufSHoqDmlrR801u639WewL9v6cDAf-qtsY", + "expire_date": "2022-06-22T08:32:30.157Z" + } +}, { "model": "sessions.session", "pk": "gcz795933839j3g0t3rjgmikzkzlwse3", @@ -2288,6 +2296,14 @@ "expire_date": "2022-02-25T14:54:28.092Z" } }, +{ + "model": "authtoken.token", + "pk": "2d5bca87ec38cba82ad1da525431ec3a224385b6", + "fields": { + "user": 1, + "created": "2022-06-08T08:32:30.149Z" + } +}, { "model": "authtoken.token", "pk": "3952f1aea900fc3daa269473a71c41fac08858b5", @@ -2697,6 +2713,25 @@ "deleted_frames": "" } }, +{ + "model": "engine.data", + "pk": 12, + "fields": { + "chunk_size": 72, + "size": 5, + "image_quality": 70, + "start_frame": 0, + "stop_frame": 4, + "frame_filter": "", + "compressed_chunk_type": "imageset", + "original_chunk_type": "imageset", + "storage_method": "cache", + "storage": "local", + "cloud_storage": null, + "sorting_method": "lexicographical", + "deleted_frames": "" + } +}, { "model": "engine.video", "pk": 1, @@ -3587,6 +3622,61 @@ "height": 954 } }, +{ + "model": "engine.image", + "pk": 428, + "fields": { + "data": 12, + "path": "0.png", + "frame": 0, + "width": 974, + "height": 452 + } +}, +{ + "model": "engine.image", + "pk": 429, + "fields": { + "data": 12, + "path": "1.png", + "frame": 1, + "width": 783, + "height": 760 + } +}, +{ + "model": "engine.image", + "pk": 430, + "fields": { + "data": 12, + "path": "2.png", + "frame": 2, + "width": 528, + "height": 458 + } +}, +{ + "model": "engine.image", + "pk": 431, + "fields": { + "data": 12, + "path": "3.png", + "frame": 3, + "width": 520, + "height": 350 + } +}, +{ + "model": "engine.image", + "pk": 432, + "fields": { + "data": 12, + "path": "4.png", + "frame": 4, + "width": 569, + "height": 483 + } +}, { "model": "engine.project", "pk": 1, @@ -3629,6 +3719,20 @@ "organization": 2 } }, +{ + "model": "engine.project", + "pk": 4, + "fields": { + "name": "project4", + "owner": 1, + "assignee": null, + "bug_tracker": "", + "created_date": "2022-06-08T08:32:45.521Z", + "updated_date": "2022-06-08T08:33:20.759Z", + "status": "annotation", + "organization": 2 + } +}, { "model": "engine.task", "pk": 2, @@ -3797,6 +3901,27 @@ "organization": null } }, +{ + "model": "engine.task", + "pk": 13, + "fields": { + "project": 4, + "name": "task1_in_project4", + "mode": "annotation", + "owner": 1, + "assignee": null, + "bug_tracker": "", + "created_date": "2022-06-08T08:33:06.505Z", + "updated_date": "2022-06-08T08:33:20.808Z", + "overlap": 0, + "segment_size": 5, + "status": "annotation", + "data": 12, + "dimension": "2d", + "subset": "", + "organization": 2 + } +}, { "model": "engine.clientfile", "pk": 131, @@ -4445,6 +4570,46 @@ "file": "/home/django/data/data/11/raw/37.png" } }, +{ + "model": "engine.clientfile", + "pk": 429, + "fields": { + "data": 12, + "file": "/home/django/data/data/12/raw/4.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 430, + "fields": { + "data": 12, + "file": "/home/django/data/data/12/raw/0.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 431, + "fields": { + "data": 12, + "file": "/home/django/data/data/12/raw/1.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 432, + "fields": { + "data": 12, + "file": "/home/django/data/data/12/raw/3.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 433, + "fields": { + "data": 12, + "file": "/home/django/data/data/12/raw/2.png" + } +}, { "model": "engine.relatedfile", "pk": 1, @@ -4544,6 +4709,15 @@ "stop_frame": 10 } }, +{ + "model": "engine.segment", + "pk": 17, + "fields": { + "task": 13, + "start_frame": 0, + "stop_frame": 4 + } +}, { "model": "engine.job", "pk": 2, @@ -4654,6 +4828,17 @@ "state": "in progress" } }, +{ + "model": "engine.job", + "pk": 17, + "fields": { + "segment": 17, + "assignee": null, + "status": "annotation", + "stage": "annotation", + "state": "in progress" + } +}, { "model": "engine.label", "pk": 3, @@ -4784,6 +4969,26 @@ "color": "#2080c0" } }, +{ + "model": "engine.label", + "pk": 16, + "fields": { + "task": null, + "project": 4, + "name": "cat", + "color": "#6080c0" + } +}, +{ + "model": "engine.label", + "pk": 17, + "fields": { + "task": null, + "project": 4, + "name": "dog", + "color": "#406040" + } +}, { "model": "engine.attributespec", "pk": 1, @@ -5346,6 +5551,64 @@ "job": 16 } }, +{ + "model": "engine.jobcommit", + "pk": 63, + "fields": { + "scope": "create", + "owner": 1, + "timestamp": "2022-06-08T08:33:06.712Z", + "data": { + "stage": "annotation", + "state": "new", + "assignee": null + }, + "job": 17 + } +}, +{ + "model": "engine.jobcommit", + "pk": 64, + "fields": { + "scope": "create", + "owner": 1, + "timestamp": "2022-06-08T08:33:20.812Z", + "data": { + "stage": "annotation", + "state": "new", + "assignee": null + }, + "job": 17 + } +}, +{ + "model": "engine.jobcommit", + "pk": 65, + "fields": { + "scope": "create", + "owner": 1, + "timestamp": "2022-06-08T08:33:20.979Z", + "data": { + "stage": "annotation", + "state": "in progress", + "assignee": null + }, + "job": 17 + } +}, +{ + "model": "engine.jobcommit", + "pk": 66, + "fields": { + "scope": "update", + "owner": 1, + "timestamp": "2022-06-08T08:33:20.980Z", + "data": { + "state": "in progress" + }, + "job": 17 + } +}, { "model": "engine.labeledshape", "pk": 1, @@ -5506,6 +5769,38 @@ "rotation": 0.0 } }, +{ + "model": "engine.labeledshape", + "pk": 34, + "fields": { + "job": 17, + "label": 16, + "frame": 0, + "group": 0, + "source": "manual", + "type": "rectangle", + "occluded": false, + "z_order": 0, + "points": "[106.36066411239153, 85.1515964240134, 240.08352490421748, 241.26526181354166]", + "rotation": 0.0 + } +}, +{ + "model": "engine.labeledshape", + "pk": 35, + "fields": { + "job": 17, + "label": 16, + "frame": 1, + "group": 0, + "source": "manual", + "type": "rectangle", + "occluded": false, + "z_order": 0, + "points": "[414.29522752496996, 124.8035516093205, 522.2641509433943, 286.75693673695605]", + "rotation": 0.0 + } +}, { "model": "engine.profile", "pk": 1, diff --git a/tests/rest_api/assets/jobs.json b/tests/rest_api/assets/jobs.json index fbb9d2f5..1282226c 100644 --- a/tests/rest_api/assets/jobs.json +++ b/tests/rest_api/assets/jobs.json @@ -1,8 +1,39 @@ { - "count": 10, + "count": 11, "next": null, "previous": null, "results": [ + { + "assignee": null, + "bug_tracker": "", + "data_chunk_size": 72, + "data_compressed_chunk_type": "imageset", + "dimension": "2d", + "id": 17, + "labels": [ + { + "attributes": [], + "color": "#6080c0", + "id": 16, + "name": "cat" + }, + { + "attributes": [], + "color": "#406040", + "id": 17, + "name": "dog" + } + ], + "mode": "annotation", + "project_id": 4, + "stage": "annotation", + "start_frame": 0, + "state": "in progress", + "status": "annotation", + "stop_frame": 4, + "task_id": 13, + "url": "http://localhost:8080/api/jobs/17" + }, { "assignee": { "first_name": "Worker", diff --git a/tests/rest_api/assets/projects.json b/tests/rest_api/assets/projects.json index a0042fb0..3ad5e4b6 100644 --- a/tests/rest_api/assets/projects.json +++ b/tests/rest_api/assets/projects.json @@ -1,8 +1,45 @@ { - "count": 3, + "count": 4, "next": null, "previous": null, "results": [ + { + "assignee": null, + "bug_tracker": "", + "created_date": "2022-06-08T08:32:45.521000Z", + "dimension": "2d", + "id": 4, + "labels": [ + { + "attributes": [], + "color": "#6080c0", + "id": 16, + "name": "cat" + }, + { + "attributes": [], + "color": "#406040", + "id": 17, + "name": "dog" + } + ], + "name": "project4", + "organization": 2, + "owner": { + "first_name": "Admin", + "id": 1, + "last_name": "First", + "url": "http://localhost:8080/api/users/1", + "username": "admin1" + }, + "status": "annotation", + "task_subsets": [], + "tasks": [ + 13 + ], + "updated_date": "2022-06-08T08:33:20.759000Z", + "url": "http://localhost:8080/api/projects/4" + }, { "assignee": { "first_name": "User", diff --git a/tests/rest_api/assets/tasks.json b/tests/rest_api/assets/tasks.json index 12c3381d..dd4bd249 100644 --- a/tests/rest_api/assets/tasks.json +++ b/tests/rest_api/assets/tasks.json @@ -1,8 +1,68 @@ { - "count": 8, + "count": 9, "next": null, "previous": null, "results": [ + { + "assignee": null, + "bug_tracker": "", + "created_date": "2022-06-08T08:33:06.505000Z", + "data": 12, + "data_chunk_size": 72, + "data_compressed_chunk_type": "imageset", + "data_original_chunk_type": "imageset", + "dimension": "2d", + "id": 13, + "image_quality": 70, + "labels": [ + { + "attributes": [], + "color": "#6080c0", + "id": 16, + "name": "cat" + }, + { + "attributes": [], + "color": "#406040", + "id": 17, + "name": "dog" + } + ], + "mode": "annotation", + "name": "task1_in_project4", + "organization": 2, + "overlap": 0, + "owner": { + "first_name": "Admin", + "id": 1, + "last_name": "First", + "url": "http://localhost:8080/api/users/1", + "username": "admin1" + }, + "project_id": 4, + "segment_size": 5, + "segments": [ + { + "jobs": [ + { + "assignee": null, + "id": 17, + "stage": "annotation", + "state": "in progress", + "status": "annotation", + "url": "http://localhost:8080/api/jobs/17" + } + ], + "start_frame": 0, + "stop_frame": 4 + } + ], + "size": 5, + "status": "annotation", + "subset": "", + "updated_date": "2022-06-08T08:33:20.808000Z", + "url": "http://localhost:8080/api/tasks/13" + }, { "assignee": null, "bug_tracker": "", diff --git a/tests/rest_api/assets/users.json b/tests/rest_api/assets/users.json index 232616ba..9fda64e0 100644 --- a/tests/rest_api/assets/users.json +++ b/tests/rest_api/assets/users.json @@ -310,7 +310,7 @@ "is_active": true, "is_staff": true, "is_superuser": true, - "last_login": "2022-03-05T09:34:33.293000Z", + "last_login": "2022-06-08T08:32:30.152708Z", "last_name": "First", "url": "http://localhost:8080/api/users/1", "username": "admin1" diff --git a/tests/rest_api/conftest.py b/tests/rest_api/conftest.py index 671d47ad..b84513f7 100644 --- a/tests/rest_api/conftest.py +++ b/tests/rest_api/conftest.py @@ -39,6 +39,10 @@ def init_test_db(): def restore(): _run('docker exec cvat_db psql -U root -d postgres -v from=test_db -v to=cvat -f restore.sql') +@pytest.fixture(scope='function') +def restore_cvat_data(): + restore_data_volume() + class Container: def __init__(self, data, key='id'): self.raw_data = data @@ -243,7 +247,7 @@ def org_staff(memberships): return set() else: return set(m['user']['id'] for m in memberships - if m['role'] in ['maintainer', 'owner'] and m['user'] != None + if m['role'] in ['maintainer', 'owner'] and m['user'] is not None and m['organization'] == org_id) return find @@ -254,7 +258,7 @@ def is_org_member(memberships): return True else: return user_id in set(m['user']['id'] for m in memberships - if m['user'] != None and m['organization'] == org_id) + if m['user'] is not None and m['organization'] == org_id) return check @pytest.fixture(scope='module') diff --git a/tests/rest_api/test_jobs.py b/tests/rest_api/test_jobs.py index 7b72e167..be45a685 100644 --- a/tests/rest_api/test_jobs.py +++ b/tests/rest_api/test_jobs.py @@ -77,7 +77,7 @@ class TestGetJobs: class TestListJobs: def _test_list_jobs_200(self, user, data, **kwargs): - response = get_method(user, 'jobs', **kwargs, page_size=all) + response = get_method(user, 'jobs', **kwargs, page_size='all') assert response.status_code == HTTPStatus.OK assert DeepDiff(data, response.json()['results']) == {} diff --git a/tests/rest_api/test_projects.py b/tests/rest_api/test_projects.py index aa50ed54..4b32f554 100644 --- a/tests/rest_api/test_projects.py +++ b/tests/rest_api/test_projects.py @@ -2,11 +2,13 @@ # # SPDX-License-Identifier: MIT +import tempfile from http import HTTPStatus from itertools import groupby, product + import pytest -from .utils.config import get_method, post_method +from .utils.config import get_method, post_files_method, post_method class TestGetProjects: @@ -196,3 +198,47 @@ class TestPostProjects: 'name': f'test: worker {user["username"]} creating a project for his organization', } self._test_create_project_201(user['username'], spec, org_id=user['org']) + +@pytest.mark.usefixtures("restore") +@pytest.mark.usefixtures("restore_cvat_data") +class TestImportExportDatasetProject: + def _test_export_project(self, username, project_id, format_name): + while True: + response = get_method(username, f'projects/{project_id}/dataset', + format=format_name) + response.raise_for_status() + if response.status_code == HTTPStatus.CREATED: + break + + response = get_method(username, f'projects/{project_id}/dataset', + format=format_name, action='download') + assert response.status_code == HTTPStatus.OK + + return response + + def _test_import_project(self, username, project_id, format_name, data): + response = post_files_method(username, f'projects/{project_id}/dataset', data, + format=format_name) + assert response.status_code == HTTPStatus.ACCEPTED + + while True: + response = get_method(username, f'projects/{project_id}/dataset', action='import_status') + response.raise_for_status() + if response.status_code == HTTPStatus.CREATED: + break + + def test_can_import_dataset_in_org(self): + username = 'admin1' + project_id = 4 + + response = self._test_export_project(username, project_id, 'CVAT for images 1.1') + + tmp_file = tempfile.NamedTemporaryFile(suffix='.zip') + tmp_file.write(response.content) + tmp_file.seek(0) + + import_data = { + 'dataset_file': tmp_file, + } + + self._test_import_project(username, project_id, 'CVAT 1.1', import_data) diff --git a/tests/rest_api/utils/config.py b/tests/rest_api/utils/config.py index 2d4360fd..2bcaf603 100644 --- a/tests/rest_api/utils/config.py +++ b/tests/rest_api/utils/config.py @@ -36,5 +36,8 @@ def patch_method(username, endpoint, data, **kwargs): 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, **kwargs): + return requests.post(get_api_url(endpoint, **kwargs), files=data, auth=(username, USER_PASS)) + def server_get(username, endpoint, **kwargs): return requests.get(get_server_url(endpoint, **kwargs), auth=(username, USER_PASS))