37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
|
|
"""VesselAPI daily snapshot store — as-of DVR + UTC-day purge (no DB)."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
|
||
|
|
from vesselapi import pick_poll_at, snapshot_as_of, utc_day_start
|
||
|
|
|
||
|
|
|
||
|
|
def test_utc_day_start_floors_to_midnight_utc():
|
||
|
|
now = datetime(2026, 8, 29, 15, 30, 12, tzinfo=timezone.utc)
|
||
|
|
assert utc_day_start(now) == datetime(2026, 8, 29, 0, 0, tzinfo=timezone.utc)
|
||
|
|
|
||
|
|
|
||
|
|
def test_pick_poll_at_returns_latest_snapshot_at_or_before_as_of():
|
||
|
|
t1 = datetime(2026, 8, 29, 0, 0, tzinfo=timezone.utc)
|
||
|
|
t2 = datetime(2026, 8, 29, 4, 48, tzinfo=timezone.utc)
|
||
|
|
t3 = datetime(2026, 8, 29, 9, 36, tzinfo=timezone.utc)
|
||
|
|
as_of = datetime(2026, 8, 29, 6, 0, tzinfo=timezone.utc)
|
||
|
|
assert pick_poll_at([t1, t2, t3], as_of) == t2
|
||
|
|
assert pick_poll_at([t1, t2, t3], t1) == t1
|
||
|
|
assert pick_poll_at([t1, t2, t3], datetime(2026, 8, 28, 23, tzinfo=timezone.utc)) is None
|
||
|
|
|
||
|
|
|
||
|
|
def test_snapshot_as_of_returns_the_matching_poll_only():
|
||
|
|
t1 = datetime(2026, 8, 29, 0, 0, tzinfo=timezone.utc)
|
||
|
|
t2 = datetime(2026, 8, 29, 4, 48, tzinfo=timezone.utc)
|
||
|
|
rows = [
|
||
|
|
{"id": "1", "poll_at": t1, "lat": 26.5, "lon": 56.0},
|
||
|
|
{"id": "2", "poll_at": t1, "lat": 26.6, "lon": 56.1},
|
||
|
|
{"id": "1", "poll_at": t2, "lat": 26.7, "lon": 56.2},
|
||
|
|
]
|
||
|
|
out = snapshot_as_of(rows, datetime(2026, 8, 29, 6, 0, tzinfo=timezone.utc))
|
||
|
|
assert {r["id"] for r in out} == {"1"}
|
||
|
|
assert out[0]["lat"] == 26.7
|
||
|
|
assert all(r["poll_at"] == t2 for r in out)
|