From ae36e8529afea5dd54608d6919efe67bad96f283 Mon Sep 17 00:00:00 2001 From: Rafik Nurmuhametov <113212617+raf-nr@users.noreply.github.com> Date: Wed, 2 Oct 2024 20:32:46 +0000 Subject: [PATCH] feat(tests): add integration tests for all api usage scenarios --- internal/rest/http/file/di.py | 8 ++- tests/datasets/university.txt | 9 +++ tests/integration/common_requests.py | 40 +++++++++++++ tests/integration/test_ping.py | 8 +++ .../integration/test_retrieve_dataset_info.py | 40 +++++++++++++ tests/integration/test_retrieve_task_info.py | 57 ++++++++++++++++++ tests/integration/test_set_profiling_task.py | 41 +++++++++++++ tests/integration/test_upload_dataset.py | 58 +++++++++++++++++++ 8 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 tests/datasets/university.txt create mode 100644 tests/integration/common_requests.py create mode 100644 tests/integration/test_ping.py create mode 100644 tests/integration/test_retrieve_dataset_info.py create mode 100644 tests/integration/test_retrieve_task_info.py create mode 100644 tests/integration/test_set_profiling_task.py create mode 100644 tests/integration/test_upload_dataset.py diff --git a/internal/rest/http/file/di.py b/internal/rest/http/file/di.py index 99911789..53126195 100644 --- a/internal/rest/http/file/di.py +++ b/internal/rest/http/file/di.py @@ -7,8 +7,12 @@ get_dataset_repo, ) from internal.uow import UnitOfWork -from internal.usecase.file import SaveFile, SaveDataset, CheckContentType -from internal.usecase.file.retrieve_dataset import RetrieveDataset +from internal.usecase.file import ( + SaveFile, + SaveDataset, + CheckContentType, + RetrieveDataset, +) from internal.usecase.file.save_dataset import DatasetRepo as SaveDatasetRepo from internal.usecase.file.retrieve_dataset import DatasetRepo as RetrieveDatasetRepo from internal.usecase.file.save_file import FileRepo, FileMetadataRepo diff --git a/tests/datasets/university.txt b/tests/datasets/university.txt new file mode 100644 index 00000000..c3afc981 --- /dev/null +++ b/tests/datasets/university.txt @@ -0,0 +1,9 @@ +Course,Classroom,Professor,Semester +Math,512,Dr. Smith,Fall +Physics,406,Dr. Green,Fall +English,208,Prof. Turner,Fall +History,209,Prof. Davis,Fall +Math,512,Dr. Smith,Spring +Physics,503,Dr. Gray,Spring +English,116,Prof. Turner,Spring +Biology,209,Prof. Light,Spring diff --git a/tests/integration/common_requests.py b/tests/integration/common_requests.py new file mode 100644 index 00000000..707b3872 --- /dev/null +++ b/tests/integration/common_requests.py @@ -0,0 +1,40 @@ +from uuid import UUID + +from fastapi.testclient import TestClient + +from internal.domain.task.value_objects import OneOfTaskConfig + + +def upload_csv_dataset( + client: TestClient, + file_name: str, + mime_type: str, + separator: str, + header: list[int], +) -> dict: + file_path = f"tests/datasets/{file_name}" + + with open(file_path, "rb") as file: + form_data = { + "separator": separator, + "header": header, + "file": (file_name, file, mime_type), + } + + response = client.post( + "api/file/csv", + files={"file": form_data["file"]}, + data={ + "separator": form_data["separator"], + "header": form_data["header"], + }, + ) + + return response + + +def set_task(client: TestClient, dataset_id: UUID, config: OneOfTaskConfig): + response = client.post( + "api/task/set", params={"dataset_id": dataset_id}, json=config.model_dump() + ) + return response diff --git a/tests/integration/test_ping.py b/tests/integration/test_ping.py new file mode 100644 index 00000000..6adbd88f --- /dev/null +++ b/tests/integration/test_ping.py @@ -0,0 +1,8 @@ +from fastapi.testclient import TestClient + + +def test_retrieve_task(client: TestClient): + response = client.get("api/common/ping") + + assert response.status_code == 200 + assert response.json() == "Pong!" diff --git a/tests/integration/test_retrieve_dataset_info.py b/tests/integration/test_retrieve_dataset_info.py new file mode 100644 index 00000000..8717b3c3 --- /dev/null +++ b/tests/integration/test_retrieve_dataset_info.py @@ -0,0 +1,40 @@ +from fastapi.testclient import TestClient +from uuid import UUID, uuid4 + +from internal.infrastructure.data_storage.relational.model.file import DatasetORM +from tests.integration.common_requests import upload_csv_dataset + + +def test_retrieve_dataset(client: TestClient, context): + file_name = "university_fd.csv" + file_path = f"tests/datasets/{file_name}" + mime_type = "text/csv" + separator = "," + header = [0] + + response = upload_csv_dataset(client, file_name, mime_type, separator, header) + assert response.status_code == 200 + + dataset_id = UUID(response.json()) + + response = client.post(f"api/file/dataset/{dataset_id}") + + assert response.status_code == 200 + + response_data = response.json() + assert response_data["id"] == str(dataset_id) + + dataset = context.postgres_context.get(DatasetORM, dataset_id) + assert dataset is not None + assert response_data["file_id"] == str(dataset.file_id) + assert response_data["separator"] == dataset.separator + assert response_data["header"] == dataset.header + + +def test_retrieve_non_existent_dataset(client: TestClient): + dataset_id = uuid4() # non existen dataset + + response = client.post(f"api/file/dataset/{dataset_id}") + + assert response.status_code == 404 + assert response.json()["detail"] == "Dataset not found" diff --git a/tests/integration/test_retrieve_task_info.py b/tests/integration/test_retrieve_task_info.py new file mode 100644 index 00000000..e027cd86 --- /dev/null +++ b/tests/integration/test_retrieve_task_info.py @@ -0,0 +1,57 @@ +import time +from fastapi.testclient import TestClient +from uuid import UUID, uuid4 + +from internal.domain.task.value_objects import FdTaskConfig +from internal.domain.task.value_objects.fd.algo_config import AidConfig +from internal.infrastructure.data_storage.relational.model.task import TaskORM +from tests.integration.common_requests import upload_csv_dataset, set_task + + +def test_retrieve_task(client: TestClient, context): + dataset_response = upload_csv_dataset( + client, "university_fd.csv", "text/csv", ".", [0] + ) + assert dataset_response.status_code == 200 + dataset_id = UUID(dataset_response.json()) + + algo_config = AidConfig(algo_name="aid", is_null_equal_null=True) + task_config = FdTaskConfig(primitive_name="fd", config=algo_config) + + task_response = set_task(client, dataset_id, task_config) + assert task_response.status_code == 200 + task_id = UUID(task_response.json()) + + time.sleep(1) + + response = client.get(f"api/task/{task_id}") + assert response.status_code == 200 + + response_data = response.json() + assert response_data["dataset_id"] == str(dataset_id) + + task = context.postgres_context.get(TaskORM, task_id) + assert task is not None + assert response_data["dataset_id"] == str(task.dataset_id) + assert response_data["status"] == task.status + assert response_data["config"] == task.config + assert response_data["result"] == task.result + assert response_data["raised_exception_name"] == task.raised_exception_name + assert response_data["failure_reason"] == task.failure_reason + assert response_data["traceback"] == task.traceback + + if response_data["status"] == "completed": + assert response_data["result"] is not None + if response_data["status"] == "failure": + assert response_data["raised_exception_name"] is not None + assert response_data["failure_reason"] is not None + assert response_data["traceback"] is not None + + +def test_retrieve_non_existent_task(client: TestClient): + task_id = uuid4() # non existen task + + response = client.get(f"api/task/{task_id}") + + assert response.status_code == 404 + assert response.json()["detail"] == "Task not found" diff --git a/tests/integration/test_set_profiling_task.py b/tests/integration/test_set_profiling_task.py new file mode 100644 index 00000000..2d9269f7 --- /dev/null +++ b/tests/integration/test_set_profiling_task.py @@ -0,0 +1,41 @@ +from fastapi.testclient import TestClient +from uuid import UUID, uuid4 + +from internal.domain.task.value_objects import FdTaskConfig +from internal.domain.task.value_objects.fd.algo_config import AidConfig +from internal.infrastructure.data_storage.relational.model.task import TaskORM +from tests.integration.common_requests import upload_csv_dataset, set_task + + +def test_set_profiling_task(client: TestClient, context): + dataset_response = upload_csv_dataset( + client, "university_fd.csv", "text/csv", ".", [0] + ) + assert dataset_response.status_code == 200 + dataset_id = UUID(dataset_response.json()) + + algo_config = AidConfig(algo_name="aid", is_null_equal_null=True) + task_config = FdTaskConfig(primitive_name="fd", config=algo_config) + + response = set_task(client, dataset_id, task_config) + + assert response.status_code == 200 + + task_id = UUID(response.json()) + + task_data = context.postgres_context.get(TaskORM, task_id) + + assert task_data is not None + assert task_data.config == task_config.model_dump() + assert task_data.dataset_id == dataset_id + + +def test_set_profiling_task_with_non_existent_dataset(client: TestClient): + dataset_id = uuid4() + algo_config = AidConfig(algo_name="aid", is_null_equal_null=True) + task_config = FdTaskConfig(primitive_name="fd", config=algo_config) + + response = set_task(client, dataset_id, task_config) + + assert response.status_code == 404 + assert response.json()["detail"] == "Dataset not found" diff --git a/tests/integration/test_upload_dataset.py b/tests/integration/test_upload_dataset.py new file mode 100644 index 00000000..97c2ead6 --- /dev/null +++ b/tests/integration/test_upload_dataset.py @@ -0,0 +1,58 @@ +import os +import pytest +from fastapi.testclient import TestClient + +from uuid import UUID + +from internal.infrastructure.data_storage.relational.model.file import DatasetORM +from tests.integration.common_requests import upload_csv_dataset + + +@pytest.mark.asyncio +async def test_upload_csv_dataset(client: TestClient, context, tmp_upload_dir): + file_name = "university_fd.csv" + file_path = f"tests/datasets/{file_name}" + mime_type = "text/csv" + separator = "," + header = [0] + + response = upload_csv_dataset(client, file_name, mime_type, separator, header) + + assert response.status_code == 200 + + dataset_id = UUID(response.json()) + + data = context.postgres_context.get(DatasetORM, dataset_id) + assert data is not None + assert data.id == dataset_id + assert data.separator == separator + assert data.header == header + assert data.related_tasks == [] + + file = data.file_metadata + assert file.original_file_name == "university_fd.csv" + assert file.mime_type == mime_type + + saved_file_path = os.path.join(tmp_upload_dir, str(file.file_name)) + assert os.path.exists(saved_file_path) + + with open(saved_file_path, "rb") as saved_file, open( + file_path, "rb" + ) as original_file: + saved_file_content = saved_file.read() + original_file_content = original_file.read() + assert saved_file_content == original_file_content + + +@pytest.mark.asyncio +async def test_upload_csv_dataset_with_incorrect_mime_type(client: TestClient): + file_name = "university.txt" + file_path = f"tests/datasets/{file_name}" + mime_type = "text/plain" + separator = "," + header = [0] + + response = upload_csv_dataset(client, file_name, mime_type, separator, header) + + assert response.status_code == 400 + assert response.json()["detail"] == "File is not CSV"