SurfSense/surfsense_backend/tests/integration/podcasts/test_task_failure.py
CREDO23 ca9bd28934 test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F)
Apply the same rename to surfsense_backend/tests: workspace_id fields/vars,
Workspace* classes/schemas, table name searchspaces -> workspaces in raw SQL,
and the API URL spellings -> /workspaces. Preserves the carve-out wire literals
tests assert (Celery task names, OTel key "search_space.id").
2026-06-26 18:36:46 +02:00

45 lines
1.4 KiB
Python

"""The task failure safety net (``mark_failed``) against a real database.
When a task body raises, ``mark_failed`` records the reason on the row. Its
contract has two halves worth securing: a still-running podcast moves to FAILED
with the reason, while one that already reached a terminal state is left exactly
as it was rather than forced. A missing row is a no-op, never a crash.
"""
from __future__ import annotations
import pytest
from app.podcasts.persistence import PodcastStatus
from app.podcasts.tasks import runtime
pytestmark = pytest.mark.integration
async def test_marking_failed_records_the_reason_on_a_running_podcast(
db_workspace, make_podcast, bind_task_session
):
podcast = await make_podcast(
workspace_id=db_workspace.id, status=PodcastStatus.DRAFTING
)
await runtime.mark_failed(podcast.id, "tts provider unavailable")
assert podcast.status == PodcastStatus.FAILED
assert podcast.error == "tts provider unavailable"
async def test_marking_failed_leaves_an_already_terminal_podcast_untouched(
db_workspace, make_podcast, bind_task_session
):
podcast = await make_podcast(
workspace_id=db_workspace.id, status=PodcastStatus.READY
)
await runtime.mark_failed(podcast.id, "too late")
assert podcast.status == PodcastStatus.READY
async def test_marking_a_missing_podcast_failed_is_a_no_op(bind_task_session):
await runtime.mark_failed(987654321, "gone") # must not raise