mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
240 lines
8.8 KiB
Python
240 lines
8.8 KiB
Python
|
|
"""Tests for Phase 2a coverage-bbox wiring.
|
||
|
|
|
||
|
|
Verifies that:
|
||
|
|
1. Each of the four simple adapters respects the `coverage` kwarg — derived
|
||
|
|
scope wins when coverage is provided, config field is the fallback when None.
|
||
|
|
2. EnvironmentalStore._coverage_for returns a dict for a valid bbox and None
|
||
|
|
for an empty bbox.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from unittest.mock import MagicMock
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from meshai.coverage import resolve_adapter_coverage
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Shared reference bbox (Magic Valley / south-central Idaho)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
IDAHO_BOX = [-116.5, 42.0, -112.0, 44.0]
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Helpers — derive the expected coverage dicts from the module itself
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
def _cov(adapter_name: str, bbox: list = None) -> dict | None:
|
||
|
|
return resolve_adapter_coverage(adapter_name, bbox or IDAHO_BOX, "native")
|
||
|
|
|
||
|
|
|
||
|
|
# ===========================================================================
|
||
|
|
# usgs_quake
|
||
|
|
# ===========================================================================
|
||
|
|
|
||
|
|
def _quake_cfg(bbox=None):
|
||
|
|
cfg = MagicMock()
|
||
|
|
cfg.feed_url = "https://example.test/feed.geojson"
|
||
|
|
cfg.min_magnitude = 2.5
|
||
|
|
cfg.bbox = bbox if bbox is not None else [-115.5, 42.0, -110.0, 45.2]
|
||
|
|
cfg.region = "magic_valley"
|
||
|
|
cfg.tick_seconds = 300
|
||
|
|
return cfg
|
||
|
|
|
||
|
|
|
||
|
|
def test_usgs_quake_coverage_wins():
|
||
|
|
"""When coverage is provided, adapter._bbox comes from coverage['bbox']."""
|
||
|
|
from meshai.env.usgs_quake import USGSQuakeAdapter
|
||
|
|
cov = _cov("usgs_quake")
|
||
|
|
assert cov is not None
|
||
|
|
adapter = USGSQuakeAdapter(_quake_cfg(), coverage=cov)
|
||
|
|
assert adapter._bbox == cov["bbox"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_usgs_quake_fallback_to_config():
|
||
|
|
"""When coverage=None, adapter._bbox falls back to config.bbox."""
|
||
|
|
from meshai.env.usgs_quake import USGSQuakeAdapter
|
||
|
|
cfg = _quake_cfg(bbox=[-115.5, 42.0, -110.0, 45.2])
|
||
|
|
adapter = USGSQuakeAdapter(cfg, coverage=None)
|
||
|
|
assert adapter._bbox == cfg.bbox
|
||
|
|
|
||
|
|
|
||
|
|
# ===========================================================================
|
||
|
|
# roads511
|
||
|
|
# ===========================================================================
|
||
|
|
|
||
|
|
def _roads_cfg(bbox=None):
|
||
|
|
cfg = MagicMock()
|
||
|
|
cfg.api_key = ""
|
||
|
|
cfg.base_url = ""
|
||
|
|
cfg.endpoints = ["/get/event"]
|
||
|
|
cfg.bbox = bbox if bbox is not None else [-115.0, 42.5, -111.0, 44.0]
|
||
|
|
cfg.tick_seconds = 300
|
||
|
|
return cfg
|
||
|
|
|
||
|
|
|
||
|
|
def test_roads511_coverage_wins():
|
||
|
|
"""When coverage is provided, adapter._bbox comes from coverage['bbox']."""
|
||
|
|
from meshai.env.roads511 import Roads511Adapter
|
||
|
|
cov = _cov("roads511")
|
||
|
|
assert cov is not None
|
||
|
|
adapter = Roads511Adapter(_roads_cfg(), coverage=cov)
|
||
|
|
assert adapter._bbox == cov["bbox"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_roads511_fallback_to_config():
|
||
|
|
"""When coverage=None, adapter._bbox falls back to config.bbox."""
|
||
|
|
from meshai.env.roads511 import Roads511Adapter
|
||
|
|
cfg = _roads_cfg(bbox=[-115.0, 42.5, -111.0, 44.0])
|
||
|
|
adapter = Roads511Adapter(cfg, coverage=None)
|
||
|
|
assert adapter._bbox == cfg.bbox
|
||
|
|
|
||
|
|
|
||
|
|
# ===========================================================================
|
||
|
|
# wzdx
|
||
|
|
# ===========================================================================
|
||
|
|
|
||
|
|
def _wzdx_cfg(states=None, bbox=None):
|
||
|
|
cfg = MagicMock()
|
||
|
|
cfg.api_key = ""
|
||
|
|
cfg.base_url = ""
|
||
|
|
cfg.registry_url = "https://example.test/registry.json"
|
||
|
|
cfg.registry_ttl = 21600
|
||
|
|
cfg.tick_seconds = 300
|
||
|
|
cfg.states = states if states is not None else ["ID"]
|
||
|
|
cfg.bbox = bbox if bbox is not None else []
|
||
|
|
return cfg
|
||
|
|
|
||
|
|
|
||
|
|
def test_wzdx_coverage_wins():
|
||
|
|
"""When coverage is provided, both _states and _bbox come from coverage."""
|
||
|
|
from meshai.env.wzdx import WZDxAdapter
|
||
|
|
cov = _cov("wzdx")
|
||
|
|
assert cov is not None
|
||
|
|
assert "states" in cov
|
||
|
|
assert "bbox" in cov
|
||
|
|
adapter = WZDxAdapter(_wzdx_cfg(), coverage=cov)
|
||
|
|
assert adapter._states == cov["states"]
|
||
|
|
assert adapter._bbox == cov["bbox"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_wzdx_fallback_to_config():
|
||
|
|
"""When coverage=None, _states and _bbox fall back to config fields."""
|
||
|
|
from meshai.env.wzdx import WZDxAdapter
|
||
|
|
cfg = _wzdx_cfg(states=["ID", "MT"], bbox=[-116.0, 42.0, -111.0, 45.0])
|
||
|
|
adapter = WZDxAdapter(cfg, coverage=None)
|
||
|
|
assert "ID" in adapter._states
|
||
|
|
assert "MT" in adapter._states
|
||
|
|
assert adapter._bbox == cfg.bbox
|
||
|
|
|
||
|
|
|
||
|
|
def test_wzdx_empty_coverage_states_wins():
|
||
|
|
"""Empty derived states list still wins over config (coverage governs)."""
|
||
|
|
from meshai.env.wzdx import WZDxAdapter
|
||
|
|
# Provide a bbox that maps to no states (unlikely but logically possible)
|
||
|
|
empty_states_cov = {"states": [], "bbox": [-1.0, 0.0, 1.0, 1.0]}
|
||
|
|
cfg = _wzdx_cfg(states=["ID"])
|
||
|
|
adapter = WZDxAdapter(cfg, coverage=empty_states_cov)
|
||
|
|
assert adapter._states == [] # coverage governs even when empty
|
||
|
|
|
||
|
|
|
||
|
|
# ===========================================================================
|
||
|
|
# avalanche
|
||
|
|
# ===========================================================================
|
||
|
|
|
||
|
|
def _avy_cfg(center_ids=None):
|
||
|
|
cfg = MagicMock()
|
||
|
|
cfg.center_ids = center_ids if center_ids is not None else ["SNFAC"]
|
||
|
|
cfg.tick_seconds = 1800
|
||
|
|
cfg.season_months = [12, 1, 2, 3, 4]
|
||
|
|
return cfg
|
||
|
|
|
||
|
|
|
||
|
|
def test_avalanche_coverage_wins():
|
||
|
|
"""When coverage is provided, adapter._center_ids comes from coverage['center_ids']."""
|
||
|
|
from meshai.env.avalanche import AvalancheAdapter
|
||
|
|
cov = _cov("avalanche")
|
||
|
|
assert cov is not None
|
||
|
|
assert "center_ids" in cov
|
||
|
|
adapter = AvalancheAdapter(_avy_cfg(), coverage=cov)
|
||
|
|
assert adapter._center_ids == cov["center_ids"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_avalanche_fallback_to_config():
|
||
|
|
"""When coverage=None, adapter._center_ids falls back to config.center_ids."""
|
||
|
|
from meshai.env.avalanche import AvalancheAdapter
|
||
|
|
cfg = _avy_cfg(center_ids=["SNFAC", "PAC"])
|
||
|
|
adapter = AvalancheAdapter(cfg, coverage=None)
|
||
|
|
assert adapter._center_ids == ["SNFAC", "PAC"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_avalanche_empty_coverage_center_ids_wins():
|
||
|
|
"""Empty derived center_ids list wins over config (coverage governs)."""
|
||
|
|
from meshai.env.avalanche import AvalancheAdapter
|
||
|
|
# A bbox in the Pacific would yield no centers
|
||
|
|
no_center_cov = {"center_ids": []}
|
||
|
|
cfg = _avy_cfg(center_ids=["SNFAC"])
|
||
|
|
adapter = AvalancheAdapter(cfg, coverage=no_center_cov)
|
||
|
|
assert adapter._center_ids == [] # coverage governs even when empty
|
||
|
|
|
||
|
|
|
||
|
|
# ===========================================================================
|
||
|
|
# EnvironmentalStore._coverage_for
|
||
|
|
# ===========================================================================
|
||
|
|
|
||
|
|
def _make_env_cfg(enabled=False):
|
||
|
|
"""Minimal EnvironmentalConfig mock with all adapters disabled."""
|
||
|
|
env_cfg = MagicMock()
|
||
|
|
for attr in ("nws", "swpc", "ducting", "fires", "avalanche", "usgs",
|
||
|
|
"usgs_quake", "traffic", "roads511", "wzdx", "satpass", "firms"):
|
||
|
|
sub = MagicMock()
|
||
|
|
sub.enabled = False
|
||
|
|
sub.feed_source = "central"
|
||
|
|
setattr(env_cfg, attr, sub)
|
||
|
|
env_cfg.nws_zones = []
|
||
|
|
return env_cfg
|
||
|
|
|
||
|
|
|
||
|
|
def test_coverage_for_returns_dict_for_valid_bbox():
|
||
|
|
"""_coverage_for returns a dict when coverage_bbox is a valid box."""
|
||
|
|
from meshai.env.store import EnvironmentalStore
|
||
|
|
env_cfg = _make_env_cfg()
|
||
|
|
store = EnvironmentalStore(config=env_cfg, coverage_bbox=IDAHO_BOX)
|
||
|
|
result = store._coverage_for("usgs_quake")
|
||
|
|
assert isinstance(result, dict)
|
||
|
|
assert "bbox" in result
|
||
|
|
assert result["bbox"] == IDAHO_BOX
|
||
|
|
|
||
|
|
|
||
|
|
def test_coverage_for_returns_none_for_empty_bbox():
|
||
|
|
"""_coverage_for returns None when coverage_bbox is empty."""
|
||
|
|
from meshai.env.store import EnvironmentalStore
|
||
|
|
env_cfg = _make_env_cfg()
|
||
|
|
store = EnvironmentalStore(config=env_cfg, coverage_bbox=[])
|
||
|
|
result = store._coverage_for("usgs_quake")
|
||
|
|
assert result is None
|
||
|
|
|
||
|
|
|
||
|
|
def test_coverage_for_avalanche_returns_center_ids():
|
||
|
|
"""_coverage_for('avalanche') returns center_ids for a valid Idaho box."""
|
||
|
|
from meshai.env.store import EnvironmentalStore
|
||
|
|
env_cfg = _make_env_cfg()
|
||
|
|
store = EnvironmentalStore(config=env_cfg, coverage_bbox=IDAHO_BOX)
|
||
|
|
result = store._coverage_for("avalanche")
|
||
|
|
assert result is not None
|
||
|
|
assert "center_ids" in result
|
||
|
|
assert isinstance(result["center_ids"], list)
|
||
|
|
# SNFAC (Sawtooth) covers south-central Idaho — should be in the result
|
||
|
|
assert "SNFAC" in result["center_ids"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_coverage_for_wzdx_returns_states_and_bbox():
|
||
|
|
"""_coverage_for('wzdx') returns both states and bbox."""
|
||
|
|
from meshai.env.store import EnvironmentalStore
|
||
|
|
env_cfg = _make_env_cfg()
|
||
|
|
store = EnvironmentalStore(config=env_cfg, coverage_bbox=IDAHO_BOX)
|
||
|
|
result = store._coverage_for("wzdx")
|
||
|
|
assert result is not None
|
||
|
|
assert "states" in result and "bbox" in result
|
||
|
|
assert "ID" in result["states"]
|