closed TG-1; git was inited;
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
"""State integration tests for AIS-catcher binary telemetry."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ais_hub.core.bus import EventBus
|
||||
from ais_hub.core.state import State
|
||||
from ais_hub.core.stats import Stats
|
||||
from ais_hub.parser.aiscatcher import (
|
||||
RssiIq,
|
||||
SignalEvent,
|
||||
SignalEventBatch,
|
||||
SlotBitmap,
|
||||
SlotDetail,
|
||||
SlotLevel,
|
||||
)
|
||||
|
||||
|
||||
def _make_state() -> State:
|
||||
stats = Stats()
|
||||
bus = EventBus(stats=stats, default_maxsize=64)
|
||||
return State(bus=bus, stats=stats)
|
||||
|
||||
|
||||
def test_rssi_iq_updates_state_and_publishes():
|
||||
state = _make_state()
|
||||
sub = state._bus.subscribe(maxsize=16)
|
||||
|
||||
state.apply_rssi_iq(RssiIq(power_a_db=-41.5, power_b_db=-43.0), ts=123.0)
|
||||
|
||||
assert state.radio_power == {
|
||||
"ts": 123.0,
|
||||
"power_a_db": -41.5,
|
||||
"power_b_db": -43.0,
|
||||
}
|
||||
assert not sub.empty()
|
||||
ev = sub.get_nowait()
|
||||
assert ev.type == "radio.update"
|
||||
assert ev.data["source"] == "aiscatcher_rssi"
|
||||
assert ev.data["power_a_db"] == -41.5
|
||||
|
||||
|
||||
def test_slot_bitmap_stored_per_channel():
|
||||
state = _make_state()
|
||||
snap = SlotBitmap(
|
||||
channel="A",
|
||||
utc_minute=28279310,
|
||||
slots_total=2250,
|
||||
occupied_count=100,
|
||||
noise_floor=0.0,
|
||||
threshold=0.0,
|
||||
slot0_unix_ms=28279310 * 60000,
|
||||
first_occupied_unix_ms=0,
|
||||
bitmap=bytes(282),
|
||||
)
|
||||
state.apply_slot_bitmap(snap, ts=50.0)
|
||||
|
||||
assert "A" in state.slot_occupancy
|
||||
occ = state.slot_occupancy["A"]
|
||||
assert occ["occupied_count"] == 100
|
||||
assert occ["slots_total"] == 2250
|
||||
assert occ["occupied_fraction"] == 100 / 2250
|
||||
# snapshot_slots exposes everything for REST
|
||||
snap_dict = state.snapshot_slots()
|
||||
assert snap_dict["occupancy"]["A"]["occupied_count"] == 100
|
||||
|
||||
|
||||
def test_slot_detail_stores_entries():
|
||||
state = _make_state()
|
||||
detail = SlotDetail(
|
||||
channel="B",
|
||||
utc_minute=1,
|
||||
slot0_unix_ms=60000,
|
||||
entries=[SlotLevel(slot=10, level_db=-70.0), SlotLevel(slot=2200, level_db=-80.0)],
|
||||
)
|
||||
state.apply_slot_detail(detail, ts=60.0)
|
||||
stored = state.slot_detail["B"]
|
||||
assert len(stored["entries"]) == 2
|
||||
assert stored["entries"][0] == {"slot": 10, "level_db": -70.0}
|
||||
|
||||
|
||||
def test_signal_event_creates_target_with_signal_fields():
|
||||
state = _make_state()
|
||||
batch = SignalEventBatch(
|
||||
channel="A",
|
||||
events=[
|
||||
SignalEvent(unix_ms=1_700_000_000_000, slot=42, mmsi=257_000_001, level_db=-75.0),
|
||||
],
|
||||
)
|
||||
state.apply_signal_events(batch, ts=1_700_000_000.0)
|
||||
|
||||
assert 257_000_001 in state.targets
|
||||
tgt = state.targets[257_000_001]
|
||||
assert tgt.last_signal_db == -75.0
|
||||
assert tgt.last_signal_slot == 42
|
||||
assert tgt.last_signal_channel == "A"
|
||||
# last_seen must be set from signal event if it's newer
|
||||
assert tgt.last_seen >= 1_700_000_000.0
|
||||
|
||||
# to_dict exposes signal block
|
||||
d = tgt.to_dict()
|
||||
assert d["signal"] == {
|
||||
"last_db": -75.0,
|
||||
"last_ts": 1_700_000_000.0,
|
||||
"last_slot": 42,
|
||||
"last_channel": "A",
|
||||
}
|
||||
|
||||
|
||||
def test_signal_event_older_does_not_overwrite():
|
||||
state = _make_state()
|
||||
mmsi = 111_222_333
|
||||
# first, newer event
|
||||
state.apply_signal_events(SignalEventBatch(
|
||||
channel="A",
|
||||
events=[SignalEvent(unix_ms=2_000_000_000_000, slot=1, mmsi=mmsi, level_db=-60.0)],
|
||||
), ts=2_000_000_000.0)
|
||||
# then, older event — must not clobber last_signal_db
|
||||
state.apply_signal_events(SignalEventBatch(
|
||||
channel="B",
|
||||
events=[SignalEvent(unix_ms=1_000_000_000_000, slot=99, mmsi=mmsi, level_db=-90.0)],
|
||||
), ts=2_000_000_001.0)
|
||||
|
||||
tgt = state.targets[mmsi]
|
||||
assert tgt.last_signal_db == -60.0
|
||||
assert tgt.last_signal_slot == 1
|
||||
assert tgt.last_signal_channel == "A"
|
||||
Reference in New Issue
Block a user