mirror of
https://github.com/zvx-echo6/central.git
synced 2026-08-26 17:31:39 +00:00
v0.14.0: multi-bbox monitoring areas (config.monitoring_areas set-union filter)
Generalize the single config.system bbox into a named config.monitoring_areas list with set-union semantics (kept if geometry intersects ANY area; no-geom always kept; empty list keeps everything). Migration 042 seeds 'default' from the existing bounds (49.0/41.8/-111/-117.5); old monitor_* columns preserved for v0.14.1. Archive + supervisor both apply the list. GUI /monitoring-area gains list/create/update/delete + multi-rectangle map.
This commit is contained in:
parent
3f1fec9846
commit
c2864a94ce
13 changed files with 792 additions and 237 deletions
|
|
@ -20,10 +20,14 @@ from central.monitoring_area import (
|
|||
MonitoringArea,
|
||||
build_geom_json,
|
||||
classify_geom,
|
||||
classify_geom_areas,
|
||||
load_monitoring_area,
|
||||
load_monitoring_areas,
|
||||
)
|
||||
|
||||
IDAHO = MonitoringArea(north=44.5, south=41.8, east=-111.0, west=-117.5)
|
||||
# A second, disjoint area to exercise set-union semantics (the NYC metro box).
|
||||
NYC_BOX = MonitoringArea(north=41.0, south=40.3, east=-73.5, west=-74.5)
|
||||
|
||||
|
||||
def _pt(lon, lat):
|
||||
|
|
@ -117,6 +121,55 @@ class TestClassifyGeom:
|
|||
assert classify_geom(json.dumps({"type": "Nonsense"}), IDAHO) == "invalid-geom"
|
||||
|
||||
|
||||
class TestClassifyGeomAreas:
|
||||
"""v0.14.0 set-union: keep if the geometry intersects ANY area."""
|
||||
|
||||
def test_empty_list_keeps_everything(self):
|
||||
assert classify_geom_areas(_pt(-74.0, 40.7), []) == "no-area"
|
||||
|
||||
def test_null_geom_always_kept(self):
|
||||
assert classify_geom_areas(None, [IDAHO]) == "null-geom"
|
||||
assert classify_geom_areas(None, []) == "null-geom"
|
||||
|
||||
def test_single_area_matches_single_bbox_behavior(self):
|
||||
# Same verdicts as the legacy single-area classify_geom for a 1-list.
|
||||
assert classify_geom_areas(_pt(-114.0, 43.5), [IDAHO]) == "in-bounds"
|
||||
assert classify_geom_areas(_pt(-74.0, 40.7), [IDAHO]) == "out-of-bounds"
|
||||
|
||||
def test_kept_if_in_either_area(self):
|
||||
# Boise -> IDAHO; NYC -> NYC_BOX. Union keeps both.
|
||||
assert classify_geom_areas(_pt(-114.0, 43.5), [IDAHO, NYC_BOX]) == "in-bounds"
|
||||
assert classify_geom_areas(_pt(-74.0, 40.7), [IDAHO, NYC_BOX]) == "in-bounds"
|
||||
|
||||
def test_dropped_only_when_outside_every_area(self):
|
||||
# London is in neither box.
|
||||
assert classify_geom_areas(_pt(-0.13, 51.5), [IDAHO, NYC_BOX]) == "out-of-bounds"
|
||||
|
||||
def test_invalid_geom_fails_open(self):
|
||||
assert classify_geom_areas("{bad json", [IDAHO]) == "invalid-geom"
|
||||
|
||||
def test_overlapping_areas_still_in_bounds(self):
|
||||
overlap = MonitoringArea(north=44.0, south=42.0, east=-112.0, west=-118.0)
|
||||
assert classify_geom_areas(_pt(-114.0, 43.0), [IDAHO, overlap]) == "in-bounds"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestLoadMonitoringAreas:
|
||||
async def test_returns_all_rows_as_areas(self):
|
||||
conn = MagicMock()
|
||||
conn.fetch = AsyncMock(return_value=[
|
||||
{"north": 44.5, "south": 41.8, "east": -111.0, "west": -117.5},
|
||||
{"north": 41.0, "south": 40.3, "east": -73.5, "west": -74.5},
|
||||
])
|
||||
areas = await load_monitoring_areas(conn)
|
||||
assert areas == [IDAHO, NYC_BOX]
|
||||
|
||||
async def test_empty_table_returns_empty_list(self):
|
||||
conn = MagicMock()
|
||||
conn.fetch = AsyncMock(return_value=[])
|
||||
assert await load_monitoring_areas(conn) == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestLoadMonitoringArea:
|
||||
async def test_returns_area_when_all_columns_set(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue