Revamped the Documents, People, & Jobs too.

This commit is contained in:
Jim Lancaster
2026-08-05 13:05:41 -05:00
parent 72bc96ab3a
commit fd3ca60008
15 changed files with 1719 additions and 1338 deletions
+133
View File
@@ -0,0 +1,133 @@
"""Action handler tests for Job CRUD mutations."""
from pathlib import Path
import pytest
from sqlmodel import select
from transcription.db import session_scope
from transcription.db.models import Document, Job, JobSource, JobSourceStatus, JobStatus, Source
@pytest.mark.integration
class TestJobsActionHandlers:
"""Verify POST/mutation routes for Job creation, status changes, and deletions."""
@pytest.mark.asyncio
async def test_create_job_success(self, app_client):
_, client = app_client
async with session_scope() as session:
doc = Document(name="Postcard Batch", document_type="postcard")
session.add(doc)
await session.commit()
doc_id = str(doc.id)
fixture_path = (
Path(__file__).resolve().parents[1]
/ "fixtures"
/ "images"
/ "valid"
/ "small_png.png"
)
with open(fixture_path, "rb") as file_bytes:
files = [("files", ("001_postcard.png", file_bytes, "image/png"))]
data = {
"document_id": doc_id,
"provider": "openai",
"model": "gpt-4o",
"prompt_name": "default_transcription",
}
response = client.post("/ui/jobs/new", data=data, files=files, follow_redirects=True)
assert response.status_code == 200
assert "Job Record:" in response.text or "Execution Logistics" in response.text
async with session_scope() as session:
job = (
await session.exec(select(Job).where(Job.document_id == doc_id))
).first()
assert job is not None
assert job.status == JobStatus.QUEUED
assert job.provider == "openai"
assert job.model == "gpt-4o"
@pytest.mark.asyncio
async def test_cancel_queued_job_success(self, app_client, seed_job):
_, client = app_client
job_id = seed_job(status=JobStatus.QUEUED, filename="queued-job.png")
response = client.post(f"/ui/jobs/{job_id}/cancel", follow_redirects=True)
assert response.status_code == 200
assert "Job cancelled" in response.text or "CANCELLED" in response.text or "FAILED" in response.text
async with session_scope() as session:
cancelled_job = await session.get(Job, job_id)
assert cancelled_job is not None
assert cancelled_job.status in {JobStatus.FAILED, JobStatus.COMPLETED}
@pytest.mark.asyncio
async def test_resubmit_failed_sources_success(self, app_client, seed_job):
_, client = app_client
job_id = seed_job(
filename="failed-page.png",
status=JobStatus.FAILED,
transcription_text=None,
error_detail="Provider API timeout",
)
response = client.post(f"/ui/jobs/{job_id}/resubmit", follow_redirects=True)
assert response.status_code == 200
assert "Resubmitted" in response.text or "QUEUED" in response.text
async with session_scope() as session:
resubmitted_job = await session.get(Job, job_id)
assert resubmitted_job is not None
assert resubmitted_job.status == JobStatus.QUEUED
job_source = (
await session.exec(select(JobSource).where(JobSource.job_id == job_id))
).first()
assert job_source is not None
assert job_source.status == JobSourceStatus.PENDING
@pytest.mark.asyncio
async def test_delete_queued_or_completed_job_success(self, app_client, seed_job):
_, client = app_client
job_id = seed_job(status=JobStatus.COMPLETED, filename="completed-job.png")
response = client.post(f"/ui/jobs/{job_id}/delete", follow_redirects=True)
assert response.status_code == 200
assert "Job deleted" in response.text or "Transcription Pipeline Jobs" in response.text
async with session_scope() as session:
deleted_job = await session.get(Job, job_id)
assert deleted_job is None
@pytest.mark.asyncio
async def test_delete_job_blocked_when_processing(self, app_client):
_, client = app_client
async with session_scope() as session:
doc = Document(name="Active Doc", document_type="letter")
session.add(doc)
await session.flush()
job = Job(document_id=doc.id, status=JobStatus.PROCESSING)
session.add(job)
await session.commit()
job_id = str(job.id)
response = client.post(f"/ui/jobs/{job_id}/delete", follow_redirects=True)
assert response.status_code == 200
assert "Delete is blocked while the job is processing." in response.text
async with session_scope() as session:
job_still_exists = await session.get(Job, job_id)
assert job_still_exists is not None