from datetime import UTC, datetime from app.models.earth_interactable import EarthInteractable from app.services import earth_interactables def make_interactable(**overrides): values = { "id": "poi-1", "layer": "places", "kind": "note", "label": "Test POI", "description": "A point on Earth", "latitude": 30.25, "longitude": 120.15, "altitude": None, "revision": 3, "properties": {"owner": "test"}, "is_deleted": False, "created_at": datetime(2026, 5, 22, 1, 0, tzinfo=UTC), "updated_at": datetime(2026, 5, 22, 1, 5, tzinfo=UTC), "deleted_at": None, } values.update(overrides) return EarthInteractable(**values) def test_interactable_event_uses_object_delta_contract(): record = make_interactable() event = earth_interactables.build_interactable_event( action="updated", record=record, ) assert event["entity"] == "interactable" assert event["action"] == "updated" assert event["layer"] == "places" assert event["layers"] == ["interactables"] assert event["ids"] == ["poi-1"] assert event["revision"] == 3 assert event["item"]["latitude"] == 30.25 assert event["item"]["properties"] == {"owner": "test"} def test_interactable_geojson_omits_deleted_records(): active = make_interactable(id="active") deleted = make_interactable(id="deleted", is_deleted=True) payload = earth_interactables.interactables_to_geojson([active, deleted]) assert payload["type"] == "FeatureCollection" assert [feature["id"] for feature in payload["features"]] == ["active"] assert payload["features"][0]["geometry"] == { "type": "Point", "coordinates": [120.15, 30.25], } def test_interactable_cache_invalidation_clears_layer_and_all(monkeypatch): patterns = [] def fake_delete_pattern(pattern): patterns.append(pattern) return 1 monkeypatch.setattr( earth_interactables.earth_layer_cache, "delete_pattern", fake_delete_pattern, ) deleted = earth_interactables.invalidate_interactable_cache("places") assert deleted == 2 assert patterns == [ "earth:layer:v1:interactables:interactable_layer:places*", "earth:layer:v1:interactables:interactable_layer:all*", ]