Wire AIS end to end: telemetry ingestion + live map overlay
node-26#9, same shape as the ADS-B commit. Adds POST /telemetry/ais (same node-key auth, same org_id-stamped upsert-by-key pattern, this time by mmsi into a new `vessels` collection) and its docInMyOrg() firestore rule. Frontend gets useVessels() (mirrors useAircraft(), longer staleness window since AIS position reports are minutes apart, not seconds) and an opt-in "Vessels" map overlay. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5537b095df
commit
3d2b722c64
@@ -58,3 +58,37 @@ def test_node_upload_skips_entries_missing_icao():
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"ok": True, "count": 0}
|
||||
mock_set.assert_not_awaited()
|
||||
|
||||
|
||||
def test_ais_service_token_without_node_id_is_rejected():
|
||||
_override({"service": True})
|
||||
resp = client.post("/telemetry/ais", json={"vessels": []})
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_ais_node_upload_upserts_and_stamps_org_id():
|
||||
_override({"node": True, "node_id": "node-1"})
|
||||
with patch.object(telemetry.fstore, "doc_get_cached", AsyncMock(return_value={"org_id": "org-A"})), \
|
||||
patch.object(telemetry.fstore, "doc_set", AsyncMock()) as mock_set:
|
||||
resp = client.post("/telemetry/ais", json={
|
||||
"vessels": [{"mmsi": "123456789", "name": "MV TEST", "lat": 41.0, "lon": -73.9}],
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"ok": True, "count": 1}
|
||||
mock_set.assert_awaited_once()
|
||||
(collection, doc_id, doc), kwargs = mock_set.await_args
|
||||
assert collection == "vessels"
|
||||
assert doc_id == "123456789"
|
||||
assert doc["node_id"] == "node-1"
|
||||
assert doc["org_id"] == "org-A"
|
||||
assert kwargs.get("merge") is True
|
||||
|
||||
|
||||
def test_ais_node_upload_skips_entries_missing_mmsi():
|
||||
_override({"node": True, "node_id": "node-1"})
|
||||
with patch.object(telemetry.fstore, "doc_get_cached", AsyncMock(return_value=None)), \
|
||||
patch.object(telemetry.fstore, "doc_set", AsyncMock()) as mock_set:
|
||||
resp = client.post("/telemetry/ais", json={"vessels": [{"mmsi": ""}]})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"ok": True, "count": 0}
|
||||
mock_set.assert_not_awaited()
|
||||
|
||||
Reference in New Issue
Block a user