Files
PolyWeather/tests/test_realtime_event_store.py
T

89 lines
2.9 KiB
Python

import sqlite3
from datetime import datetime, timezone
from src.database.db_manager import DBManager
from web.realtime_event_store import RealtimeEventStore
from web.realtime_patch_schema import normalize_observation_patch
def _event(city: str, temp: float, source: str = "metar"):
return normalize_observation_patch(
{
"city": city,
"changes": {
"temp": temp,
"obs_time": "2026-05-26T08:15:00Z",
"source": source,
},
}
)
def test_event_store_appends_monotonic_revisions_and_replays_by_city(tmp_path):
db_path = str(tmp_path / "polyweather.db")
DBManager._initialized_paths.clear()
store = RealtimeEventStore(db_path=db_path)
taipei = store.append_event(_event("taipei", 31.2))
seoul = store.append_event(_event("seoul", 27.8))
taipei_next = store.append_event(_event("taipei", 31.5))
assert taipei["revision"] == 1
assert seoul["revision"] == 2
assert taipei_next["revision"] == 3
assert store.latest_revision() == 3
replay = store.replay_events(cities={"taipei"}, since_revision=1, limit=10)
assert [event["revision"] for event in replay] == [3]
assert replay[0]["city"] == "taipei"
assert replay[0]["payload"]["temp"] == 31.5
def test_event_store_cleanup_uses_short_replay_retention(tmp_path):
db_path = str(tmp_path / "polyweather.db")
DBManager._initialized_paths.clear()
store = RealtimeEventStore(db_path=db_path)
old_event = store.append_event(_event("taipei", 30.0))
fresh_event = store.append_event(_event("taipei", 31.0))
with sqlite3.connect(db_path) as conn:
conn.execute(
"UPDATE observation_patch_events SET created_at = ? WHERE revision = ?",
("2026-05-26T00:00:00+00:00", old_event["revision"]),
)
conn.execute(
"UPDATE observation_patch_events SET created_at = ? WHERE revision = ?",
("2026-05-26T11:30:00+00:00", fresh_event["revision"]),
)
conn.commit()
deleted = store.cleanup_old_events(
retention_hours=6,
now=datetime(2026, 5, 26, 12, 0, tzinfo=timezone.utc),
)
assert deleted == 1
replay = store.replay_events(cities={"taipei"}, since_revision=0, limit=10)
assert [event["revision"] for event in replay] == [fresh_event["revision"]]
def test_event_store_reports_replay_gap_when_limit_is_exceeded(tmp_path):
db_path = str(tmp_path / "polyweather.db")
DBManager._initialized_paths.clear()
store = RealtimeEventStore(db_path=db_path)
for temp in [30.0, 30.5, 31.0]:
store.append_event(_event("hong kong", temp, source="hko"))
replay = store.replay_events(cities={"hong kong"}, since_revision=0, limit=2)
assert len(replay) == 2
assert store.replay_requires_resync(
cities={"hong kong"},
since_revision=0,
replay_count=len(replay),
limit=2,
)