mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-08-09 12:16:01 +02:00
Add tests for native map layer overrides.
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
"""Tests for daemon-driven native layer overrides.
|
||||
|
||||
Overrides are an additive map that merges on top of the operator's
|
||||
``active_layers`` state. They gate fetchers via ``is_any_active`` and are
|
||||
merged into the four ``data.py`` serving paths, but they never enter
|
||||
``active_layers`` itself and are never persisted by the frontend.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from services.fetchers._store import (
|
||||
active_layers,
|
||||
clear_layer_overrides,
|
||||
effective_layers,
|
||||
get_layer_overrides,
|
||||
is_any_active,
|
||||
set_layer_overrides,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _restore_layer_state():
|
||||
"""Overrides and operator state must not leak between tests."""
|
||||
before = dict(active_layers)
|
||||
clear_layer_overrides()
|
||||
yield
|
||||
clear_layer_overrides()
|
||||
active_layers.clear()
|
||||
active_layers.update(before)
|
||||
|
||||
|
||||
class TestStoreAccessors:
|
||||
def test_override_activates_layer_the_operator_turned_off(self):
|
||||
active_layers["military"] = False
|
||||
assert is_any_active("military") is False
|
||||
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
|
||||
assert is_any_active("military") is True
|
||||
assert get_layer_overrides() == {"military": True}
|
||||
|
||||
def test_override_does_not_mutate_operator_state(self):
|
||||
active_layers["military"] = False
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
|
||||
assert active_layers["military"] is False
|
||||
assert effective_layers()["military"] is True
|
||||
|
||||
def test_override_expires_after_ttl(self):
|
||||
import time as _time
|
||||
|
||||
active_layers["military"] = False
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
assert is_any_active("military") is True
|
||||
|
||||
later = _time.monotonic() + 121
|
||||
with patch("services.fetchers._store.time.monotonic", return_value=later):
|
||||
assert get_layer_overrides() == {}
|
||||
assert is_any_active("military") is False
|
||||
|
||||
# Expiry is sticky — the map was cleared, not merely hidden.
|
||||
assert get_layer_overrides() == {}
|
||||
|
||||
def test_clear_restores_operator_view(self):
|
||||
active_layers["military"] = False
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
assert is_any_active("military") is True
|
||||
|
||||
clear_layer_overrides()
|
||||
|
||||
assert get_layer_overrides() == {}
|
||||
assert is_any_active("military") is False
|
||||
|
||||
def test_unknown_keys_are_rejected(self):
|
||||
accepted = set_layer_overrides({"military": True, "not_a_layer": True}, 120)
|
||||
|
||||
assert accepted == {"military": True}
|
||||
assert "not_a_layer" not in get_layer_overrides()
|
||||
assert "not_a_layer" not in effective_layers()
|
||||
|
||||
def test_ttl_is_capped(self):
|
||||
active_layers["military"] = False
|
||||
set_layer_overrides({"military": True}, 10_000_000)
|
||||
|
||||
import time as _time
|
||||
|
||||
later = _time.monotonic() + 3601
|
||||
with patch("services.fetchers._store.time.monotonic", return_value=later):
|
||||
assert get_layer_overrides() == {}
|
||||
|
||||
def test_empty_override_map_is_a_no_op(self):
|
||||
assert get_layer_overrides() == {}
|
||||
assert effective_layers() == dict(active_layers)
|
||||
|
||||
def test_setting_bumps_active_layers_version(self):
|
||||
from services.fetchers._store import get_active_layers_version
|
||||
|
||||
before = get_active_layers_version()
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
assert get_active_layers_version() > before
|
||||
|
||||
mid = get_active_layers_version()
|
||||
clear_layer_overrides()
|
||||
assert get_active_layers_version() > mid
|
||||
|
||||
|
||||
class TestServingPaths:
|
||||
"""The audit finding: ~70 payload filters read the local ``active_layers``.
|
||||
|
||||
Gating the fetcher is not enough — the response builder must see the
|
||||
merged map too, or the payload is stripped on the way out.
|
||||
"""
|
||||
|
||||
def test_bootstrap_critical_includes_overridden_layer(self, client):
|
||||
active_layers["military"] = False
|
||||
with patch(
|
||||
"services.fetchers._store.get_latest_data_subset_refs",
|
||||
side_effect=lambda *keys: {k: ([{"id": "x"}] if k == "military_flights" else None) for k in keys},
|
||||
):
|
||||
off = client.get("/api/bootstrap/critical").json()
|
||||
assert off["military_flights"] == []
|
||||
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
on = client.get("/api/bootstrap/critical").json()
|
||||
|
||||
assert on["military_flights"] == [{"id": "x"}]
|
||||
|
||||
def test_fast_path_includes_overridden_layer(self, client):
|
||||
active_layers["military"] = False
|
||||
with patch(
|
||||
"services.fetchers._store.get_latest_data_subset_refs",
|
||||
side_effect=lambda *keys: {k: ([{"id": "x"}] if k == "military_flights" else None) for k in keys},
|
||||
):
|
||||
off = client.get("/api/live-data/fast").json()
|
||||
assert off["military_flights"] == []
|
||||
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
on = client.get("/api/live-data/fast").json()
|
||||
|
||||
assert on["military_flights"] == [{"id": "x"}]
|
||||
|
||||
def test_slow_path_includes_overridden_layer(self, client):
|
||||
active_layers["volcanoes"] = False
|
||||
with patch(
|
||||
"services.fetchers._store.get_latest_data_subset_refs",
|
||||
side_effect=lambda *keys: {k: ([{"id": "v"}] if k == "volcanoes" else None) for k in keys},
|
||||
):
|
||||
off = client.get("/api/live-data/slow").json()
|
||||
assert off["volcanoes"] == []
|
||||
|
||||
set_layer_overrides({"volcanoes": True}, 120)
|
||||
on = client.get("/api/live-data/slow").json()
|
||||
|
||||
assert on["volcanoes"] == [{"id": "v"}]
|
||||
|
||||
def test_no_overrides_leaves_payload_unchanged(self, client):
|
||||
active_layers["military"] = True
|
||||
with patch(
|
||||
"services.fetchers._store.get_latest_data_subset_refs",
|
||||
side_effect=lambda *keys: {k: ([{"id": "x"}] if k == "military_flights" else None) for k in keys},
|
||||
):
|
||||
baseline = client.get("/api/bootstrap/critical").json()
|
||||
clear_layer_overrides()
|
||||
again = client.get("/api/bootstrap/critical").json()
|
||||
|
||||
assert baseline == again
|
||||
|
||||
def test_write_path_never_sees_overrides(self, client):
|
||||
"""POST /api/layers writes operator state; overrides must not bleed in."""
|
||||
active_layers["military"] = False
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
|
||||
r = client.post("/api/layers", json={"layers": {"cctv": True}})
|
||||
assert r.status_code == 200
|
||||
|
||||
assert active_layers["military"] is False
|
||||
assert active_layers["cctv"] is True
|
||||
|
||||
|
||||
class TestRoutes:
|
||||
def test_get_layers_reports_state_and_overrides(self, client):
|
||||
r = client.get("/api/layers")
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["overrides"] == {}
|
||||
assert body["layers"]["military"] == active_layers["military"]
|
||||
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
assert client.get("/api/layers").json()["overrides"] == {"military": True}
|
||||
|
||||
def test_put_override_route(self, client):
|
||||
r = client.put(
|
||||
"/api/ai/layer-overrides",
|
||||
json={"layers": {"military": True}, "ttl_seconds": 120},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["ok"] is True
|
||||
assert body["overrides"] == {"military": True}
|
||||
assert body["ignored"] == []
|
||||
assert get_layer_overrides() == {"military": True}
|
||||
|
||||
def test_put_reports_ignored_keys(self, client):
|
||||
r = client.put(
|
||||
"/api/ai/layer-overrides",
|
||||
json={"layers": {"military": True, "not_a_layer": True}, "ttl_seconds": 120},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["ignored"] == ["not_a_layer"]
|
||||
assert body["overrides"] == {"military": True}
|
||||
|
||||
def test_get_override_route(self, client):
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
r = client.get("/api/ai/layer-overrides")
|
||||
assert r.status_code == 200
|
||||
assert r.json() == {"ok": True, "overrides": {"military": True}}
|
||||
|
||||
def test_delete_override_route(self, client):
|
||||
set_layer_overrides({"military": True}, 120)
|
||||
r = client.delete("/api/ai/layer-overrides")
|
||||
assert r.status_code == 200
|
||||
assert r.json()["ok"] is True
|
||||
assert get_layer_overrides() == {}
|
||||
|
||||
def test_unsigned_remote_put_is_rejected(self, remote_client):
|
||||
r = remote_client.put(
|
||||
"/api/ai/layer-overrides",
|
||||
json={"layers": {"military": True}, "ttl_seconds": 120},
|
||||
)
|
||||
assert r.status_code == 403
|
||||
assert get_layer_overrides() == {}
|
||||
Reference in New Issue
Block a user