from datetime import UTC, datetime, timedelta import pytest from backend.app.models import ImageRecord pytestmark = pytest.mark.integration async def _seed(db, count: int = 3): base = datetime.now(UTC) for i in range(count): r = ImageRecord( path=f"/images/x/{i}.jpg", sha256=f"x{i:063d}", size_bytes=1, mime="image/jpeg", width=1, height=1, origin="imported_filesystem", integrity_status="unknown", ) r.created_at = base - timedelta(minutes=i) r.effective_date = r.created_at # no post → tracks created_at (0035) db.add(r) await db.flush() await db.commit() @pytest.mark.asyncio async def test_scroll_returns_images(client, db): await _seed(db) resp = await client.get("/api/gallery/scroll?limit=10") assert resp.status_code == 200 body = await resp.get_json() assert len(body["images"]) == 3 assert "next_cursor" in body assert "date_groups" in body @pytest.mark.asyncio async def test_scroll_rejects_bad_limit(client): resp = await client.get("/api/gallery/scroll?limit=notanumber") assert resp.status_code == 400 @pytest.mark.asyncio async def test_timeline_endpoint(client, db): await _seed(db) resp = await client.get("/api/gallery/timeline") assert resp.status_code == 200 body = await resp.get_json() assert sum(b["count"] for b in body) == 3 @pytest.mark.asyncio async def test_jump_requires_year_month(client): resp = await client.get("/api/gallery/jump") assert resp.status_code == 400 @pytest.mark.asyncio async def test_image_detail_404_when_missing(client): resp = await client.get("/api/gallery/image/99999") assert resp.status_code == 404 @pytest.mark.asyncio async def test_scroll_sort_param_reverses(client, db): await _seed(db, 3) newest = await (await client.get("/api/gallery/scroll?limit=10&sort=newest")).get_json() oldest = await (await client.get("/api/gallery/scroll?limit=10&sort=oldest")).get_json() ids_new = [i["id"] for i in newest["images"]] ids_old = [i["id"] for i in oldest["images"]] assert ids_old == list(reversed(ids_new)) @pytest.mark.asyncio async def test_scroll_media_param(client, db): await _seed(db, 2) # only image/jpeg seeded resp = await client.get("/api/gallery/scroll?limit=10&media=video") assert resp.status_code == 200 assert (await resp.get_json())["images"] == [] @pytest.mark.asyncio async def test_facets_endpoint(client, db): await _seed(db, 3) # filesystem images: no artist, no tags, no platform resp = await client.get("/api/gallery/facets") assert resp.status_code == 200 body = await resp.get_json() assert body["total"] == 3 assert body["untagged"] == 3 assert body["no_artist"] == 3 assert "platforms" in body assert body["date_min"] is not None assert body["date_max"] is not None @pytest.mark.asyncio async def test_facets_rejects_bad_date(client): resp = await client.get("/api/gallery/facets?date_from=notadate") assert resp.status_code == 400 @pytest.mark.asyncio async def test_scroll_untagged_param(client, db): await _seed(db, 2) resp = await client.get("/api/gallery/scroll?untagged=1&limit=10") assert resp.status_code == 200 assert len((await resp.get_json())["images"]) == 2 @pytest.mark.asyncio async def test_scroll_date_from_param(client, db): await _seed(db, 2) # all created ~now # A future date_from excludes everything. resp = await client.get("/api/gallery/scroll?date_from=2099-01-01&limit=10") assert resp.status_code == 200 assert (await resp.get_json())["images"] == []