86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
import importlib
|
|
import os
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
@pytest.fixture
|
|
def client(tmp_path):
|
|
os.environ["DB_PATH"] = str(tmp_path / "test.db")
|
|
os.environ["SYNC_TOKEN"] = "geheim"
|
|
from app import config, db, main
|
|
importlib.reload(config)
|
|
importlib.reload(db)
|
|
importlib.reload(main)
|
|
with TestClient(main.app) as c:
|
|
yield c
|
|
|
|
|
|
AUTH = {"Authorization": "Bearer geheim"}
|
|
|
|
|
|
def sync(client, since=0, **collections):
|
|
body = {"since": since, **collections}
|
|
r = client.post("/api/sync", json=body, headers=AUTH)
|
|
assert r.status_code == 200, r.text
|
|
return r.json()
|
|
|
|
|
|
def test_health_ohne_token(client):
|
|
assert client.get("/api/health").json() == {"ok": True}
|
|
|
|
|
|
def test_falscher_token(client):
|
|
assert client.post("/api/sync", json={}).status_code == 401
|
|
assert client.post("/api/sync", json={}, headers={"Authorization": "Bearer falsch"}).status_code == 401
|
|
assert client.get("/api/events").status_code == 401
|
|
|
|
|
|
def test_push_und_pull(client):
|
|
a = sync(client, events=[{"id": "e1", "updated": "2026-09-19T10:00:00.000Z", "title": "Zahnarzt"}])
|
|
assert a["cursor"] == 1
|
|
assert [e["id"] for e in a["events"]] == ["e1"]
|
|
|
|
# Anderes Gerät ohne Stand bekommt alles
|
|
b = sync(client)
|
|
assert [e["title"] for e in b["events"]] == ["Zahnarzt"]
|
|
assert b["cursor"] == 1
|
|
|
|
# Mit aktuellem Stand kommt nichts Neues
|
|
c = sync(client, since=1)
|
|
assert c["events"] == [] and c["cursor"] == 1
|
|
|
|
|
|
def test_neuester_gewinnt(client):
|
|
sync(client, todos=[{"id": "t1", "updated": "2026-09-19T10:00:00.000Z", "title": "alt"}])
|
|
sync(client, todos=[{"id": "t1", "updated": "2026-09-19T09:00:00.000Z", "title": "älter"}])
|
|
assert client.get("/api/todos", headers=AUTH).json()[0]["title"] == "alt"
|
|
r = sync(client, since=0, todos=[{"id": "t1", "updated": "2026-09-19T11:00:00.000Z", "title": "neu"}])
|
|
assert r["todos"][0]["title"] == "neu"
|
|
assert r["cursor"] == 2
|
|
|
|
|
|
def test_abgelehnte_aenderung_bekommt_serverstand(client):
|
|
sync(client, todos=[{"id": "t1", "updated": "2026-09-19T10:00:00.000Z", "title": "server"}])
|
|
r = sync(client, since=1, todos=[{"id": "t1", "updated": "2026-09-19T09:00:00.000Z", "title": "client"}])
|
|
assert [t["title"] for t in r["todos"]] == ["server"]
|
|
assert r["cursor"] == 1
|
|
|
|
|
|
def test_tombstone(client):
|
|
sync(client, notes=[{"id": "Plan.md", "updated": "2026-09-19T10:00:00.000Z", "content": "x"}])
|
|
r = sync(client, since=1, notes=[{"id": "Plan.md", "updated": "2026-09-19T10:05:00.000Z", "deleted": True}])
|
|
assert r["notes"][0]["deleted"] is True
|
|
assert client.get("/api/notes", headers=AUTH).json() == []
|
|
# Ein verspäteter älterer Stand belebt die Notiz nicht wieder
|
|
sync(client, notes=[{"id": "Plan.md", "updated": "2026-09-19T10:01:00.000Z", "content": "y"}])
|
|
assert client.get("/api/notes", headers=AUTH).json() == []
|
|
|
|
|
|
def test_seit_cursor_liefert_nur_neues(client):
|
|
sync(client, events=[{"id": "e1", "updated": "2026-09-19T10:00:00.000Z", "title": "a"}])
|
|
sync(client, events=[{"id": "e2", "updated": "2026-09-19T10:00:00.000Z", "title": "b"}])
|
|
r = sync(client, since=1)
|
|
assert [e["id"] for e in r["events"]] == ["e2"]
|