"""API integration smoke tests (need the local database with ingested data; skipped otherwise).""" from __future__ import annotations import asyncio import httpx import pytest from satelliteindex.api.main import app from satelliteindex.db import connection, dispose, fetch_val pytestmark = pytest.mark.asyncio async def _db_ready() -> bool: try: async with connection() as conn: return int(await fetch_val(conn, "select count(*) from satellites")) > 1000 except Exception: # noqa: BLE001 return False finally: await dispose() @pytest.fixture(scope="module") def has_db() -> bool: return asyncio.run(_db_ready()) @pytest.fixture async def client(has_db): if not has_db: pytest.skip("database not available / not ingested") async with app.router.lifespan_context(app): transport = httpx.ASGITransport(app=app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as c: yield c async def test_health(client): r = await client.get("/api/v1/health") assert r.status_code == 200 and r.json()["components"]["database"]["status"] == "ok" async def test_satellite_detail_and_position(client): r = await client.get("/api/v1/satellites/25544") assert r.status_code == 200 d = r.json()["data"] assert d["norad_id"] == 25544 and d["object_type"] == "STATION" and d["orbit_class"] == "LEO" assert d["live"] is None or 350 < d["live"]["altitude_km"] < 460 r = await client.get("/api/v1/satellites/25544/position") assert r.status_code == 200 and "lat" in r.json()["data"] r = await client.get(f"/api/v1/satellites/{d['slug']}") assert r.status_code == 200 r = await client.get("/api/v1/satellites/does-not-exist-0") assert r.status_code == 404 and "error" in r.json() async def test_search_and_list(client): r = await client.get("/api/v1/search", params={"q": "ISS"}) assert r.status_code == 200 hits = r.json()["data"]["results"] assert any(h["entity_type"] == "satellite" and "ISS" in h["title"] for h in hits) r = await client.get("/api/v1/satellites", params={"constellation": "starlink", "status": "ACTIVE", "page_size": 5}) body = r.json() assert r.status_code == 200 and body["pagination"]["total"] > 1000 and len(body["data"]) == 5 async def test_stats_and_positions(client): r = await client.get("/api/v1/stats") assert r.status_code == 200 and int(r.json()["data"]["global"]["active_satellites"]) > 5000 r = await client.get("/api/v1/orbit/positions") assert r.status_code == 200 snap = r.json()["data"] assert snap["count"] > 5000 and len(snap["pos"]) == snap["count"] * 6 async def test_admin_requires_token(client): r = await client.get("/api/v1/admin/overview") assert r.status_code == 401