import pytest from backend.app import create_app from backend.app.models import Artist 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 artist(db): a = Artist(name="Alice", slug="alice") db.add(a) await db.commit() return a @pytest.mark.asyncio async def test_platforms_endpoint(client): resp = await client.get("/api/sources/platforms") assert resp.status_code == 200 body = await resp.get_json() assert "patreon" in body["platforms"] @pytest.mark.asyncio async def test_create_list_get_delete(client, artist): create = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "patreon", "url": "https://patreon.com/alice", }) assert create.status_code == 201 created = await create.get_json() assert created["artist_name"] == "Alice" sid = created["id"] listing = await client.get("/api/sources") assert listing.status_code == 200 assert len(await listing.get_json()) == 1 filtered = await client.get(f"/api/sources?artist_id={artist.id}") assert filtered.status_code == 200 assert len(await filtered.get_json()) == 1 one = await client.get(f"/api/sources/{sid}") assert one.status_code == 200 assert (await one.get_json())["id"] == sid deleted = await client.delete(f"/api/sources/{sid}") assert deleted.status_code == 204 assert (await client.get(f"/api/sources/{sid}")).status_code == 404 @pytest.mark.asyncio async def test_create_rejects_unknown_platform(client, artist): resp = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "myspace", "url": "https://m/x", }) assert resp.status_code == 400 body = await resp.get_json() assert body["error"] == "unknown_platform" assert "known" in body @pytest.mark.asyncio async def test_create_rejects_bad_config(client, artist): resp = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "patreon", "url": "https://p/a", "config_overrides": [1, 2, 3], }) assert resp.status_code == 400 assert (await resp.get_json())["error"] == "invalid_config" @pytest.mark.asyncio async def test_create_rejects_empty_url(client, artist): resp = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "patreon", "url": " ", }) assert resp.status_code == 400 assert (await resp.get_json())["error"] == "empty_url" @pytest.mark.asyncio async def test_create_rejects_unknown_artist(client): resp = await client.post("/api/sources", json={ "artist_id": 99999, "platform": "patreon", "url": "https://p/a", }) assert resp.status_code == 404 @pytest.mark.asyncio async def test_create_duplicate_returns_409_with_existing_id(client, artist): a = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "patreon", "url": "https://p/a", }) first = (await a.get_json())["id"] b = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "patreon", "url": "https://p/a", }) assert b.status_code == 409 body = await b.get_json() assert body["error"] == "duplicate" assert body["existing_id"] == first @pytest.mark.asyncio async def test_patch_updates_fields(client, artist): create = await client.post("/api/sources", json={ "artist_id": artist.id, "platform": "patreon", "url": "https://p/a", }) sid = (await create.get_json())["id"] patch = await client.patch(f"/api/sources/{sid}", json={"enabled": False}) assert patch.status_code == 200 assert (await patch.get_json())["enabled"] is False @pytest.mark.asyncio async def test_get_404(client): assert (await client.get("/api/sources/99999")).status_code == 404 @pytest.mark.asyncio async def test_patch_404(client): assert (await client.patch("/api/sources/99999", json={"enabled": False})).status_code == 404 @pytest.mark.asyncio async def test_delete_404(client): assert (await client.delete("/api/sources/99999")).status_code == 404