213 lines
6.5 KiB
Python
213 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from cpv3.modules.files.models import File
|
|
from cpv3.modules.projects.models import Project
|
|
from cpv3.modules.tasks.schemas import TaskSubmitResponse
|
|
from cpv3.modules.tasks.service import TaskService
|
|
from cpv3.modules.users.models import User
|
|
|
|
pytest.importorskip("greenlet")
|
|
|
|
|
|
@pytest.fixture
|
|
async def workflow_project(test_db_session: AsyncSession, test_user: User) -> Project:
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
owner_id=test_user.id,
|
|
name="Workflow Project",
|
|
description="Typed workflow test project",
|
|
language="ru",
|
|
status="DRAFT",
|
|
is_active=True,
|
|
)
|
|
test_db_session.add(project)
|
|
await test_db_session.commit()
|
|
await test_db_session.refresh(project)
|
|
return project
|
|
|
|
|
|
@pytest.fixture
|
|
async def source_file(
|
|
test_db_session: AsyncSession,
|
|
test_user: User,
|
|
workflow_project: Project,
|
|
) -> File:
|
|
file = File(
|
|
id=uuid.uuid4(),
|
|
owner_id=test_user.id,
|
|
project_id=workflow_project.id,
|
|
original_filename="source.mp4",
|
|
path="users/test/source.mp4",
|
|
storage_backend="S3",
|
|
mime_type="video/mp4",
|
|
size_bytes=1024,
|
|
file_format="mp4",
|
|
is_uploaded=True,
|
|
is_deleted=False,
|
|
)
|
|
test_db_session.add(file)
|
|
await test_db_session.commit()
|
|
await test_db_session.refresh(file)
|
|
return file
|
|
|
|
|
|
class TestProjectWorkspaceEndpoints:
|
|
async def test_get_workspace_returns_default_state(
|
|
self,
|
|
auth_client: AsyncClient,
|
|
workflow_project: Project,
|
|
) -> None:
|
|
response = await auth_client.get(f"/api/projects/{workflow_project.id}/workspace")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["project_id"] == str(workflow_project.id)
|
|
assert data["revision"] == 0
|
|
assert data["version"] == 1
|
|
assert data["phase"] == "INGEST"
|
|
assert data["current_screen"] == "upload"
|
|
assert data["source_file_id"] is None
|
|
assert data["active_job"] is None
|
|
assert data["workspace_view"] == {
|
|
"used_file_ids": [],
|
|
"selected_file_id": None,
|
|
}
|
|
|
|
async def test_get_workspace_forbidden_for_other_users_project(
|
|
self,
|
|
auth_client: AsyncClient,
|
|
test_db_session: AsyncSession,
|
|
other_user: User,
|
|
) -> None:
|
|
foreign_project = Project(
|
|
id=uuid.uuid4(),
|
|
owner_id=other_user.id,
|
|
name="Other Project",
|
|
description=None,
|
|
language="ru",
|
|
status="DRAFT",
|
|
is_active=True,
|
|
)
|
|
test_db_session.add(foreign_project)
|
|
await test_db_session.commit()
|
|
|
|
response = await auth_client.get(f"/api/projects/{foreign_project.id}/workspace")
|
|
|
|
assert response.status_code == 403
|
|
|
|
async def test_set_source_file_action_updates_workspace(
|
|
self,
|
|
auth_client: AsyncClient,
|
|
workflow_project: Project,
|
|
source_file: File,
|
|
) -> None:
|
|
response = await auth_client.post(
|
|
f"/api/projects/{workflow_project.id}/workflow/actions",
|
|
json={
|
|
"type": "SET_SOURCE_FILE",
|
|
"revision": 0,
|
|
"file_id": str(source_file.id),
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["revision"] == 1
|
|
assert data["phase"] == "VERIFY"
|
|
assert data["current_screen"] == "verify"
|
|
assert data["source_file_id"] == str(source_file.id)
|
|
assert data["workspace_view"] == {
|
|
"used_file_ids": [str(source_file.id)],
|
|
"selected_file_id": str(source_file.id),
|
|
}
|
|
|
|
async def test_action_returns_conflict_on_stale_revision(
|
|
self,
|
|
auth_client: AsyncClient,
|
|
workflow_project: Project,
|
|
source_file: File,
|
|
) -> None:
|
|
first_response = await auth_client.post(
|
|
f"/api/projects/{workflow_project.id}/workflow/actions",
|
|
json={
|
|
"type": "SET_SOURCE_FILE",
|
|
"revision": 0,
|
|
"file_id": str(source_file.id),
|
|
},
|
|
)
|
|
assert first_response.status_code == 200
|
|
|
|
response = await auth_client.post(
|
|
f"/api/projects/{workflow_project.id}/workflow/actions",
|
|
json={
|
|
"type": "RESET_SOURCE_FILE",
|
|
"revision": 0,
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 409
|
|
|
|
async def test_start_media_convert_action_sets_active_job(
|
|
self,
|
|
auth_client: AsyncClient,
|
|
workflow_project: Project,
|
|
source_file: File,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
async def fake_submit_media_convert(
|
|
self,
|
|
*,
|
|
requester: User,
|
|
request,
|
|
) -> TaskSubmitResponse:
|
|
assert requester.id == workflow_project.owner_id
|
|
assert request.file_key == source_file.path
|
|
assert request.project_id == workflow_project.id
|
|
return TaskSubmitResponse(
|
|
job_id=uuid.UUID("00000000-0000-4000-a000-000000000123"),
|
|
webhook_url=("http://test/api/tasks/webhook/00000000-0000-4000-a000-000000000123/"),
|
|
status="PENDING",
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
TaskService,
|
|
"submit_media_convert",
|
|
fake_submit_media_convert,
|
|
)
|
|
|
|
set_source_response = await auth_client.post(
|
|
f"/api/projects/{workflow_project.id}/workflow/actions",
|
|
json={
|
|
"type": "SET_SOURCE_FILE",
|
|
"revision": 0,
|
|
"file_id": str(source_file.id),
|
|
},
|
|
)
|
|
assert set_source_response.status_code == 200
|
|
|
|
response = await auth_client.post(
|
|
f"/api/projects/{workflow_project.id}/workflow/actions",
|
|
json={
|
|
"type": "START_MEDIA_CONVERT",
|
|
"revision": 1,
|
|
"output_format": "mp4",
|
|
"out_folder": "output_files",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["revision"] == 2
|
|
assert data["phase"] == "VERIFY"
|
|
assert data["current_screen"] == "verify"
|
|
assert data["active_job"] == {
|
|
"job_id": "00000000-0000-4000-a000-000000000123",
|
|
"job_type": "MEDIA_CONVERT",
|
|
}
|