Merge commit '7ce409c580' into dev

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-06-16 22:48:14 -07:00
commit 0fe650fd8e
27 changed files with 510 additions and 134 deletions

View file

@ -120,6 +120,9 @@ class FakeStorageBackend:
async def open_stream(self, key: str) -> AsyncIterator[bytes]:
yield self.objects.get(key, b"audio-bytes")
async def exists(self, key: str) -> bool:
return key in self.objects
async def delete(self, key: str) -> None:
self.deleted.append(key)
@ -214,7 +217,7 @@ def build_spec(
slot=1, name="Guest", role=SpeakerRole.GUEST, voice_id=voice_ids[1]
),
],
duration=DurationTarget(min_minutes=10, max_minutes=20),
duration=DurationTarget(min_seconds=600, max_seconds=1200),
)

View file

@ -76,7 +76,7 @@ async def test_quota_denial_fails_the_podcast_without_a_transcript(
async def _deny(**_kwargs):
raise QuotaInsufficientError(
usage_type="podcast_generation",
balance_micros=0,
balance_micros=5_000_000,
remaining_micros=0,
)
yield # pragma: no cover - unreachable, satisfies the CM protocol

View file

@ -48,6 +48,22 @@ async def test_public_stream_serves_audio_via_storage_key(
assert resp.content == b"public-audio"
async def test_public_stream_404_when_object_missing(
client, db_session, db_search_space, db_user, fake_storage
):
await _snapshot(
db_session,
search_space_id=db_search_space.id,
user=db_user,
token="tok-gone",
podcasts=[{"original_id": 556, "storage_key": "podcasts/gone.mp3"}],
)
resp = await client.get("/api/v1/public/tok-gone/podcasts/556/stream")
assert resp.status_code == 404
async def test_public_stream_404_when_podcast_absent_from_snapshot(
client, db_session, db_search_space, db_user
):

View file

@ -1,8 +1,7 @@
"""Streaming a podcast's rendered audio over HTTP.
A ready podcast streams its bytes from the storage backend; a podcast with no
stored audio returns 404. Storage is an in-memory backend (the object store is a
system boundary).
A ready podcast streams its bytes; an in-flight one is 409, a stored-but-missing
object is 404. Storage is an in-memory backend (the object store is a boundary).
"""
from __future__ import annotations
@ -31,11 +30,23 @@ async def test_stream_serves_stored_audio(
assert resp.content == b"the-audio"
async def test_stream_404_when_no_audio(client, db_search_space, make_podcast):
async def test_stream_409_while_in_flight(client, db_search_space, make_podcast):
podcast = await make_podcast(
search_space_id=db_search_space.id, status=PodcastStatus.DRAFTING
)
resp = await client.get(f"{BASE}/{podcast.id}/stream")
assert resp.status_code == 409
async def test_stream_404_when_object_missing(
client, db_search_space, make_podcast, fake_storage
):
podcast = await make_podcast(
search_space_id=db_search_space.id, status=PodcastStatus.READY
)
resp = await client.get(f"{BASE}/{podcast.id}/stream")
assert resp.status_code == 404