import pytest from backend.app import create_app from backend.app.models import Artist, DownloadEvent, Source pytestmark = pytest.mark.integration @pytest.fixture async def app(): return create_app() @pytest.fixture async def client(app): async with app.test_client() as c: yield c @pytest.fixture async def seed(db): artist = Artist(name="Alice", slug="alice") db.add(artist) await db.flush() source = Source( artist_id=artist.id, platform="patreon", url="https://patreon.com/alice", enabled=True, config_overrides={}, ) db.add(source) await db.flush() events = [ DownloadEvent( source_id=source.id, status="ok", files_count=3, bytes_downloaded=100000, metadata_={ "run_stats": {"downloaded_count": 3, "skipped_count": 1, "quarantined_count": 0}, "duration_seconds": 10.5, "error_type": None, }, ), DownloadEvent( source_id=source.id, status="error", error="auth failed", metadata_={ "run_stats": {"downloaded_count": 0, "skipped_count": 0, "quarantined_count": 0}, "duration_seconds": 2.1, "error_type": "auth_error", }, ), ] db.add_all(events) await db.commit() return artist, source, events @pytest.mark.asyncio async def test_list_returns_newest_first(client, seed): resp = await client.get("/api/downloads") assert resp.status_code == 200 body = await resp.get_json() assert len(body) == 2 assert body[0]["id"] > body[1]["id"] assert body[0]["summary"]["error_type"] == "auth_error" assert body[0]["artist_name"] == "Alice" @pytest.mark.asyncio async def test_list_filter_by_status(client, seed): resp = await client.get("/api/downloads?status=ok") body = await resp.get_json() assert all(r["status"] == "ok" for r in body) @pytest.mark.asyncio async def test_list_filter_by_source_id(client, seed): _, source, _ = seed resp = await client.get(f"/api/downloads?source_id={source.id}") body = await resp.get_json() assert all(r["source_id"] == source.id for r in body) @pytest.mark.asyncio async def test_list_rejects_invalid_status(client): resp = await client.get("/api/downloads?status=bogus") assert resp.status_code == 400 @pytest.mark.asyncio async def test_list_before_keyset(client, seed): _, _, events = seed middle_id = events[0].id resp = await client.get(f"/api/downloads?before={middle_id}") body = await resp.get_json() assert all(r["id"] < middle_id for r in body) @pytest.mark.asyncio async def test_detail_returns_full_metadata(client, seed): _, _, events = seed target = events[1] resp = await client.get(f"/api/downloads/{target.id}") assert resp.status_code == 200 body = await resp.get_json() assert body["metadata"]["error_type"] == "auth_error" assert body["metadata"]["duration_seconds"] == 2.1 @pytest.mark.asyncio async def test_detail_404(client): resp = await client.get("/api/downloads/99999") assert resp.status_code == 404