88 lines
3.1 KiB
Python
88 lines
3.1 KiB
Python
"""API-Routen: Lesen + Scan-Start über httpx/ASGITransport (gleicher Event-Loop wie
|
|
create_task und der DB-Write-Lock — fastapi.TestClient wäre die Loop-Falle)."""
|
|
import asyncio
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
import config
|
|
import scan_dienst
|
|
|
|
|
|
@pytest.fixture
|
|
async def client(gescanntes_repo, monkeypatch, tmp_path):
|
|
wurzel, git = gescanntes_repo
|
|
datei = tmp_path / "projekte.txt"
|
|
datei.write_text(f"{wurzel}\n{tmp_path}/tot\n")
|
|
monkeypatch.setattr(config, "PROJEKTE_DATEI", datei)
|
|
scan_dienst._laeufe.clear()
|
|
from server import app
|
|
transport = httpx.ASGITransport(app=app)
|
|
async with httpx.AsyncClient(transport=transport, base_url="http://test") as c:
|
|
yield c, wurzel, git
|
|
|
|
|
|
async def test_projektliste(client):
|
|
c, wurzel, _ = client
|
|
r = await c.get("/api/projekte")
|
|
assert r.status_code == 200
|
|
eintraege = {p["name"]: p for p in r.json()}
|
|
assert eintraege["mini"]["hat_planer"] is True
|
|
assert eintraege["mini"]["drift"] == []
|
|
assert eintraege["mini"]["scan_laeuft"] is False
|
|
assert "fehler" in eintraege["tot"]
|
|
|
|
|
|
async def test_projekt_detail(client):
|
|
c, _, _ = client
|
|
r = await c.get("/api/projekte/mini")
|
|
daten = r.json()
|
|
assert daten["kern"]["titel"] == "mini"
|
|
assert daten["bereiche"] and daten["bereiche"][0]["features"]
|
|
assert "rechner.py::addiere" in daten["einheiten"]
|
|
assert daten["doku_ordnung"]
|
|
assert (await c.get("/api/projekte/gibtsnicht")).status_code == 404
|
|
|
|
|
|
async def test_einheit_mit_code(client):
|
|
c, _, _ = client
|
|
r = await c.get("/api/projekte/mini/einheit", params={"id": "rechner.py::addiere"})
|
|
e = r.json()
|
|
assert "return a + b" in e["code"]
|
|
assert e["veraltet"] is False
|
|
assert (await c.get("/api/projekte/mini/einheit", params={"id": "x.py::y"})).status_code == 404
|
|
|
|
|
|
async def test_drift_nach_commit(client):
|
|
c, wurzel, git = client
|
|
(wurzel / "rechner.py").write_text((wurzel / "rechner.py").read_text() + "\nX9 = 9\n")
|
|
git("add", "-A")
|
|
git("commit", "-m", "drift")
|
|
r = await c.get("/api/projekte")
|
|
mini = next(p for p in r.json() if p["name"] == "mini")
|
|
assert mini["drift"] == ["rechner.py"]
|
|
e = (await c.get("/api/projekte/mini/einheit", params={"id": "rechner.py::addiere"})).json()
|
|
assert e["veraltet"] is True
|
|
|
|
|
|
async def test_scan_starten_und_pollen(client):
|
|
c, _, _ = client
|
|
r = await c.post("/api/projekte/mini/scan", json={"art": "rescan"})
|
|
assert r.json()["status"] == "gestartet"
|
|
doppel = await c.post("/api/projekte/mini/scan", json={"art": "rescan"})
|
|
assert doppel.json()["status"] in ("laeuft", "gestartet") # idempotent, nie Doppellauf
|
|
for _ in range(100):
|
|
s = (await c.get("/api/projekte/mini/scan-status")).json()
|
|
if not s["laeuft"]:
|
|
break
|
|
await asyncio.sleep(0.1)
|
|
assert s["ergebnis"]["status"] in ("ok", "unveraendert")
|
|
|
|
|
|
async def test_scan_409_bei_dirty_tree(client):
|
|
c, wurzel, _ = client
|
|
(wurzel / "schmutz.py").write_text("X = 1\n")
|
|
r = await c.post("/api/projekte/mini/scan", json={"art": "scan"})
|
|
assert r.status_code == 409
|
|
assert "uncommittete" in r.json()["detail"]
|