"""Tests for the BGP collector + event location services.""" from __future__ import annotations import pytest from app.services import bgp_collector_locations from app.services.bgp_collector_locations import ( RIPE_RIS_COLLECTOR_COORDS, collect_bgp_collector_location_candidates, iter_known_collector_names, resolve_bgp_collector_location, ) from app.services.bgp_event_locations import ( resolve_bgp_event_geo_dict, resolve_bgp_event_location, ) def test_legacy_dict_view_preserves_backward_compatible_keys(): rrc00 = RIPE_RIS_COLLECTOR_COORDS["rrc00"] assert rrc00["city"] == "Amsterdam" assert rrc00["country"] == "Netherlands" assert rrc00["latitude"] == pytest.approx(52.3676) assert rrc00["longitude"] == pytest.approx(4.9041) # New richer fields layered on top. assert rrc00["precision"] == "city" assert rrc00["source"] == "legacy_seed" assert rrc00["needs_confirmation"] is True def test_every_legacy_collector_present(): expected = { "rrc00", "rrc01", "rrc03", "rrc04", "rrc05", "rrc06", "rrc07", "rrc10", "rrc11", "rrc12", "rrc13", "rrc14", "rrc15", "rrc16", "rrc18", "rrc19", "rrc20", "rrc21", "rrc22", "rrc23", "rrc24", "rrc25", "rrc26", } assert set(iter_known_collector_names()) == expected def test_resolve_bgp_collector_returns_stored_location(): result = resolve_bgp_collector_location("rrc12") assert result.location is not None assert result.location.city == "Frankfurt" assert result.location.country == "Germany" assert result.location.precision == "city" assert result.location.source == "legacy_seed" assert result.location.needs_confirmation is True def test_resolve_unknown_bgp_collector_returns_diagnostic(monkeypatch): monkeypatch.setattr(bgp_collector_locations, "_geocode_online", lambda q: None) result = resolve_bgp_collector_location("rrc-doesnotexist") assert result.location is None assert result.diagnostic is not None assert result.diagnostic.failure_reason def test_collect_bgp_collector_candidates_uses_stored_context_without_registry(monkeypatch): bgp_collector_locations._geocode_online.cache_clear() def _fake_geocode(query): assert "CIXP" in query or "Geneva" in query return { "lat": "46.2044", "lon": "6.1432", "display_name": "Geneva, Switzerland", "address": {"city": "Geneva", "country": "Switzerland"}, } monkeypatch.setattr(bgp_collector_locations, "_geocode_online", _fake_geocode) candidates, attempted = collect_bgp_collector_location_candidates( collector="rrc04", ) assert attempted, "stored context should feed online query attempts" assert candidates, "online geocoding should produce at least one candidate" best = candidates[0] assert best.source == "nominatim_online_geocode" assert best.needs_confirmation is True assert all(candidate.source != "local_registry" for candidate in candidates) def test_collect_bgp_collector_candidates_uses_nominatim_when_registry_misses(monkeypatch): bgp_collector_locations._geocode_online.cache_clear() def _fake_geocode(query): if "Lyon" not in query and "France-IX" not in query and "FR-IX" not in query: return None return { "lat": "45.764", "lon": "4.8357", "display_name": "Lyon, Auvergne-Rhône-Alpes, France", "address": {"city": "Lyon", "country": "France"}, } monkeypatch.setattr(bgp_collector_locations, "_geocode_online", _fake_geocode) candidates, attempted = collect_bgp_collector_location_candidates( collector="rrc-mystery", city="Lyon", country="France", ) assert attempted, "Nominatim plan should run" online = [c for c in candidates if c.source == "nominatim_online_geocode"] assert online, "online resolver must produce a candidate when registry misses" assert online[0].needs_confirmation is True # ── BGP event resolver ───────────────────────────────────────────── def test_event_resolver_inherits_from_owning_collector(): geo = resolve_bgp_event_geo_dict("rrc25") assert geo["city"] == "Amsterdam" assert geo["country"] == "Netherlands" assert geo["source"] == "inherited_from_collector" assert geo["precision"] == "city" def test_event_resolver_does_not_match_unrelated_collectors(): """Regression: passing operator=RIPE NCC must NOT make every collector match.""" rrc12 = resolve_bgp_event_geo_dict("rrc12") rrc25 = resolve_bgp_event_geo_dict("rrc25") assert rrc12["city"] == "Frankfurt" assert rrc25["city"] == "Amsterdam" assert rrc12["latitude"] != rrc25["latitude"] def test_event_resolver_uses_source_coordinates_when_present(): geo = resolve_bgp_event_geo_dict( "rrc12", source_latitude=12.34, source_longitude=56.78, ) assert geo["latitude"] == pytest.approx(12.34) assert geo["longitude"] == pytest.approx(56.78) assert geo["precision"] == "precise" assert geo["source"] == "source_coordinates" def test_event_resolver_returns_empty_for_unknown_collector_without_source_coords(): geo = resolve_bgp_event_geo_dict("rrc-doesnotexist") assert geo == {} def test_event_resolver_full_result_carries_diagnostic_on_miss(): result = resolve_bgp_event_location(collector="rrc-doesnotexist") assert result.location is None assert result.diagnostic is not None