Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 178 additions & 1 deletion backend/tests/test_api/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,33 @@

import pytest
from application_factory import create_app
from core.constants import BEARER_TOKEN_TYPE
from core.constants import BEARER_TOKEN_TYPE, ProjectVisibility, RenderStatus
from dependencies.auth import get_auth_user_by_access_token
from fastapi import FastAPI
from fastapi.testclient import TestClient
from schemas.file import FileResponse
from schemas.project import (
ProjectBase,
ProjectFullResponse,
ProjectResponse,
ProjectResponseList,
ProjectWithRenderFileFullResponse,
ProjectWithRenderFileResponse,
ProjectWithRenderResponse,
)
from schemas.render import (
RenderBase,
RenderFullResponse,
RenderResponse,
RenderWithFileFullResponse,
RenderWithFileResponse,
)
from schemas.tag import TagResponse, TagResponseList
from schemas.token import TokenInfo
from schemas.user import UserFullResponse, UserResponse
from services.auth import AuthService
from services.file_uploader import FileUploader
from services.projects.project_pagination import ProjectPaginationService
from services.tag import TagService
from services.user import UserService

Expand Down Expand Up @@ -120,6 +137,166 @@ def user_service() -> UserService:
return user_service


@pytest.fixture(scope="function")
def render_base() -> RenderBase:
return RenderBase(
width=1000,
height=1000,
samples=100,
denoiser=True,
gpu=True,
)


@pytest.fixture(scope="function")
def render_response(render_base: RenderBase) -> RenderResponse:
return RenderResponse(
id=1,
file_id=None,
**render_base.model_dump(),
)


@pytest.fixture(scope="function")
def render_full_response(render_response: RenderResponse) -> RenderFullResponse:
return RenderFullResponse(
url=None,
**render_response.model_dump(),
)


@pytest.fixture(scope="function")
def render_with_file_full_response(
render_full_response: RenderFullResponse,
) -> RenderWithFileFullResponse:
return RenderWithFileFullResponse(
file=None,
**render_full_response.model_dump(),
)


@pytest.fixture(scope="function")
def project_base() -> ProjectBase:
return ProjectBase(
name="project_name",
description="description",
source_file_id=1,
)


@pytest.fixture(scope="function")
def project_response(
project_base: ProjectBase,
) -> ProjectResponse:
return ProjectResponse(
visibility=ProjectVisibility.public,
status=RenderStatus.completed,
user_id=1,
render_id=None,
id=1,
**project_base.model_dump(),
)


@pytest.fixture(scope="function")
def project_full_response(
project_response: ProjectResponse,
) -> ProjectFullResponse:
return ProjectFullResponse(
url="test_url",
**project_response.model_dump(),
)


@pytest.fixture(scope="function")
def project_with_render_file_full_response(
project_full_response: ProjectFullResponse,
render_with_file_full_response: RenderWithFileFullResponse,
) -> ProjectWithRenderFileFullResponse:
return ProjectWithRenderFileFullResponse(
render=render_with_file_full_response,
**project_full_response.model_dump(),
)


@pytest.fixture(scope="function")
def project_with_render_response(
render_response: RenderResponse,
project_response: ProjectResponse,
) -> ProjectWithRenderResponse:
return ProjectWithRenderResponse(
render=render_response,
**project_response.model_dump(),
)


@pytest.fixture(scope="function")
def render_with_file_response(
render_response: RenderResponse,
) -> RenderWithFileResponse:
return RenderWithFileResponse(
file=None,
**render_response.model_dump(),
)


@pytest.fixture(scope="function")
def project_with_render_file_response(
project_response: ProjectResponse,
render_with_file_response: RenderWithFileResponse,
) -> ProjectWithRenderFileResponse:
return ProjectWithRenderFileResponse(
render=render_with_file_response,
**project_response.model_dump(),
)


@pytest.fixture(scope="function")
def project_service(
project_with_render_file_full_response: ProjectWithRenderFileFullResponse,
project_with_render_response: ProjectWithRenderResponse,
project_with_render_file_response: ProjectWithRenderFileResponse,
) -> TagService:
project_service = AsyncMock()
project_service.get_by_id = AsyncMock(
return_value=project_with_render_file_full_response,
)
project_service.create_project = AsyncMock(
return_value=project_with_render_response,
)
project_service.partial_update_project = AsyncMock(
return_value=project_with_render_file_response,
)
project_service.delete_by_id = AsyncMock(return_value=None)
return project_service


@pytest.fixture(scope="function")
def project_response_list(project_response: ProjectResponse) -> ProjectResponseList:
return ProjectResponseList(
project_list=[project_response],
size=10,
page=1,
)


@pytest.fixture(scope="function")
def project_pagination_service(
project_response_list: ProjectResponseList,
) -> ProjectPaginationService:
project_pagination_service = AsyncMock()
project_pagination_service.get_user_projects = AsyncMock(
return_value=project_response_list,
)
project_pagination_service.get_public_projects = AsyncMock(
return_value=project_response_list,
)
project_pagination_service.get_user_public_projects = AsyncMock(
return_value=project_response_list,
)
return project_pagination_service


@pytest.fixture(scope="function")
def tag_service() -> TagService:
tag_service = AsyncMock()
Expand Down
Empty file.
164 changes: 164 additions & 0 deletions backend/tests/test_api/test_api_v1/test_projects/test_details_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import pytest
from core.exceptions.auth import PermissionDeniedError
from core.exceptions.base import NotFoundError
from core.exceptions.file import FileIdNotFoundError
from core.exceptions.project import ProjectIdNotFoundError
from core.exceptions.user import UserIdNotFoundError
from dependencies.services import get_project_service
from fastapi import FastAPI, status
from fastapi.testclient import TestClient
from schemas.project import ProjectPartialUpdate
from services.projects.project import ProjectService

from tests.test_api.utils import get_result_json


@pytest.fixture(scope="function")
def partial_update_project_data() -> ProjectPartialUpdate:
return ProjectPartialUpdate(
name="project_name",
description="description",
)


class TestGetProjectEndpoint:
url = "/api/v1/projects/{project_id}"

def test_get_project_valid(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
url = self.url.format(project_id=1)
response = auth_client.get(url)
response_data = response.json()
assert response.status_code == status.HTTP_200_OK
assert response_data == get_result_json(project_service, "get_by_id")

@pytest.mark.parametrize(
"not_found_error",
[
ProjectIdNotFoundError(1),
UserIdNotFoundError(1),
],
)
def test_get_project_not_found_error(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
not_found_error: NotFoundError,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
project_service.get_by_id.side_effect = not_found_error
url = self.url.format(project_id=1)
response = auth_client.get(url)
response_data = response.json()
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response_data["message"] == not_found_error.detail

def test_get_project_permission_denied_error(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
permission_denied_error = PermissionDeniedError()
project_service.get_by_id.side_effect = permission_denied_error
url = self.url.format(project_id=1)
response = auth_client.get(url)
response_data = response.json()
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert response_data["message"] == permission_denied_error.detail


class TestPartialUpdateProjectEndpoint:
url = "/api/v1/projects/{project_id}"

def test_partial_update_project_valid(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
partial_update_project_data: ProjectPartialUpdate,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
url = self.url.format(project_id=1)
response = auth_client.patch(url, json=partial_update_project_data.model_dump())
response_data = response.json()
assert response.status_code == status.HTTP_200_OK
assert response_data == get_result_json(
project_service,
"partial_update_project",
)

def test_partial_update_project_file_not_found_error(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
partial_update_project_data: ProjectPartialUpdate,
) -> None:
file_not_found_error = FileIdNotFoundError(1)
application.dependency_overrides[get_project_service] = lambda: project_service
project_service.partial_update_project.side_effect = file_not_found_error
url = self.url.format(project_id=1)
response = auth_client.patch(url, json=partial_update_project_data.model_dump())
response_data = response.json()
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response_data["message"] == file_not_found_error.detail


class TestDeleteProjectEndpoint:
url = "/api/v1/projects/{project_id}"

def test_delete_project_valid(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
url = self.url.format(project_id=1)
response = auth_client.delete(url)
assert response.status_code == status.HTTP_204_NO_CONTENT

@pytest.mark.parametrize(
"not_found_error",
[
ProjectIdNotFoundError(1),
UserIdNotFoundError(1),
],
)
def test_delete_project_not_found_error(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
not_found_error: NotFoundError,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
project_service.delete_by_id.side_effect = not_found_error
url = self.url.format(project_id=1)
response = auth_client.delete(url)
response_data = response.json()
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response_data["message"] == not_found_error.detail

def test_delete_project_permission_denied_error(
self,
application: FastAPI,
auth_client: TestClient,
project_service: ProjectService,
) -> None:
application.dependency_overrides[get_project_service] = lambda: project_service
permission_denied_error = PermissionDeniedError()
project_service.delete_by_id.side_effect = permission_denied_error
url = self.url.format(project_id=1)
response = auth_client.delete(url)
response_data = response.json()
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert response_data["message"] == permission_denied_error.detail
Loading
Loading