"""Story audio cache maintenance tests.""" import os from datetime import datetime, timedelta, timezone from pathlib import Path import pytest from fastapi import HTTPException from sqlalchemy import select from app.core.config import settings from app.db.models import Story from app.services.generation_jobs import create_generation_job from app.services.story_service import generate_story_audio, prune_story_audio_cache pytestmark = pytest.mark.asyncio async def test_prune_story_audio_cache_removes_expired_audio( db_session, test_story, mock_tts_provider, monkeypatch, ): await generate_story_audio(test_story.id, test_story.user_id, db_session) cached_audio_path = Path(settings.story_audio_cache_dir) / f"story-{test_story.id}.mp3" assert cached_audio_path.is_file() old_time = datetime.now(timezone.utc) - timedelta(days=10) timestamp = old_time.timestamp() os.utime(cached_audio_path, (timestamp, timestamp)) monkeypatch.setattr(settings, "story_audio_cache_ttl_days", 7) result = await prune_story_audio_cache(db_session) assert result == {"scanned": 1, "pruned": 1, "repaired": 0} assert not cached_audio_path.exists() story = ( await db_session.execute(select(Story).where(Story.id == test_story.id)) ).scalar_one() assert story.audio_path is None assert story.audio_status == "not_requested" assert story.generation_status == "partial_ready" async def test_generate_story_audio_rejects_when_story_has_active_job( db_session, test_story, ): await create_generation_job( db_session, user_id=test_story.user_id, output_mode="asset_retry", input_type="audio", request_payload={"story_id": test_story.id}, story_id=test_story.id, ) with pytest.raises(HTTPException) as exc_info: await generate_story_audio(test_story.id, test_story.user_id, db_session) assert exc_info.value.status_code == 409 assert "已有运行中的任务" in str(exc_info.value.detail)