central/tests
malice 81a2c30fdb
v0.10.8: discriminate Nats-Msg-Id by event.category to prevent incident+perimeter dedup collision (#96)
JetStream's 2-min per-stream duplicate window keys on Nats-Msg-Id alone --
the subject is NOT part of the dedup key. So when wfigs_incidents and
wfigs_perimeters published envelopes for the same Summit Creek IRWIN
{6B1C6EB1-30F7-4613-9C58-4801DC8FD822} within seconds of each other on
2026-06-07, the second publish was silently dropped: supervisor logged
'Published event' for both, but CENTRAL_FIRE's last_seq advanced by 25
instead of 26.

Root cause: cloudevents_wire.wrap_event returned event.id verbatim as
msg_id, and both wfigs adapters use the bare IRWIN GUID as event.id.

Fix: synthesize msg_id as f'{event.id}:{event.category}' in wrap_event.
Categories already differ ('fire.incident.X' vs 'fire.perimeter.X') so
this is a natural and load-bearing discriminator. envelope['id'] stays
the bare event.id per CloudEvents spec, so subscribers that key off the
payload id field are unaffected. Adapter-side event.id construction
unchanged.

Backward compatibility: this is a one-time msg_id-shape change. The
JetStream 2-min dedup window is per-(event-id, category) starting now
instead of per-event-id. For events still in the dedup window at the
moment of the deploy under the OLD shape, their first post-deploy
publish under the NEW shape is a fresh msg_id and lands normally -- no
collision risk. Quake and other single-class adapters get a no-op shape
change (their category is constant per adapter, so dedup still catches
genuine same-id duplicates).

Tests:
- test_required_fields_present updated for the new assertion.
- New test_msgid_disambiguates_incident_vs_perimeter_same_guid regression
  guard with the real Summit Creek IRWIN -- assert the two msg_ids differ
  and match the expected shape exactly.
- New parametrize test_msgid_shape_is_id_colon_category over 5
  categories covering multi-class (fire.incident, fire.perimeter) and
  single-class (quake, wx.alert, hydro) adapters.

Full sweep: 1028 passed, 0 failures (+6 from this PR), ruff clean.

Deploy: NOT an output-shape change to envelope payload, no published_ids
flush needed. Squash-merge -> tag v0.10.8 -> pull on central -> restart
central-supervisor. Verify by forcing a Summit Creek republish and
confirming both .incident.id.cassia AND .perimeter.id.cassia land
post-deploy with the same IRWIN.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 01:12:22 -06:00
..
fixtures v0.10.3: rip out state_511_atis adapter (superseded by itd_511 v0.10.0; Castle Rock legacy shape EOL per sister-site discovery) (#88) 2026-06-06 14:44:00 -06:00
__init__.py scaffold: initial repository structure 2026-05-15 19:16:24 +00:00
conftest.py feat(nwis): site + stats enrichment — named location + WaterWatch normalcy band (v0.8.0) 2026-05-25 15:30:19 +00:00
README.md chore: normalize line endings to LF 2026-05-16 22:26:12 +00:00
test_adapters.py fix(4-1): resolve api_key alias from per-adapter settings, not class attr 2026-05-19 23:08:11 +00:00
test_api_key_resolver.py fix(4-1): resolve api_key alias from per-adapter settings, not class attr 2026-05-19 23:08:11 +00:00
test_api_keys.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_apply_enrichment_coordless.py fix(3-M.b): apply_enrichment always attaches _enriched for declared adapters 2026-05-21 04:04:25 +00:00
test_archive_bbox_filter.py v0.10.2: monitoring-area bbox enforced at supervisor publish (was archive-only) (#PR_NUMBER_PLACEHOLDER) 2026-06-05 20:34:10 -06:00
test_archive_multi_stream.py feat(2-E.5): single-source-of-truth stream registry 2026-05-19 07:37:01 +00:00
test_audit.py feat(gui): add auth core, setup gate, and first-run operator creation 2026-05-17 05:30:49 +00:00
test_auth.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_backend_settings_schema.py fix(3-L.5): per-backend settings schemas (fixes build_enrichers TypeError) 2026-05-20 23:10:10 +00:00
test_bootstrap_config.py chore: housekeeping - orphan branch + three stale tests (#22) 2026-05-17 18:14:58 -06:00
test_config_source.py chore(M-b): clear get_settings lru_cache in test fixtures (fixes order-dependent crypto failures + 3 latent siblings) 2026-05-21 15:51:51 +00:00
test_config_store.py chore(M-b): clear get_settings lru_cache in test fixtures (fixes order-dependent crypto failures + 3 latent siblings) 2026-05-21 15:51:51 +00:00
test_consumer_doc.py v0.10.3: rip out state_511_atis adapter (superseded by itd_511 v0.10.0; Castle Rock legacy shape EOL per sister-site discovery) (#88) 2026-06-06 14:44:00 -06:00
test_crypto.py chore: normalize line endings to LF 2026-05-16 22:26:12 +00:00
test_csrf_handler.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_csrf_race_condition.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_dashboard.py feat(2-E.5): single-source-of-truth stream registry 2026-05-19 07:37:01 +00:00
test_dedup_mixin.py fix(wzdx): drop 'unknown' direction from subject + extract dedup mixin (v0.9.1) 2026-05-25 21:18:21 +00:00
test_enrichment_config_plumbing.py fix(3-L.5): per-backend settings schemas (fixes build_enrichers TypeError) 2026-05-20 23:10:10 +00:00
test_enrichment_framework.py feat(3-J): enrichment framework + GeocoderEnricher + NoOpBackend + FIRMS pilot 2026-05-20 04:39:49 +00:00
test_enrichment_locations_coverage.py feat(gui-bugs): fix eonet dashboard exception + out-of-range map bbox 2026-05-24 22:38:13 +00:00
test_enrichment_mile_marker.py v0.10.6: extract mile_marker from itd_511 comment field as _enriched.mile_marker (#94) 2026-06-07 21:38:04 -06:00
test_eonet.py v0.9.20: regional subject routing on quake / fire / hydro / disaster adapters 2026-05-27 23:50:30 -06:00
test_events_adapter_column.py docs: add test database setup, restore geom to test fixture 2026-05-17 18:26:48 +00:00
test_events_bbox_guard.py feat(map-rework): fit-to-results, marker clustering, map-filter toggle, shape/opacity encoding (v0.7.2) 2026-05-25 01:20:04 +00:00
test_events_feed.py feat(api): add paginated events feed JSON endpoint (#25) 2026-05-17 22:31:00 -06:00
test_events_feed_frontend.py v0.10.3: rip out state_511_atis adapter (superseded by itd_511 v0.10.0; Castle Rock legacy shape EOL per sister-site discovery) (#88) 2026-06-06 14:44:00 -06:00
test_events_filtering.py Hide tombstones from default events view + show-removed toggle (v0.9.11) 2026-05-26 22:14:38 +00:00
test_events_pagination.py feat(layout-pagination): collapse legend, stabilize rows, real offset paginator (v0.7.3) 2026-05-25 02:04:23 +00:00
test_events_retention.py v0.9.13: per-stream archived-events retention sweep 2026-05-27 02:31:11 +00:00
test_fire_fused.py v0.9.14: fused FIRMS+WFIGS fire view 2026-05-27 03:49:30 +00:00
test_firms.py v0.10.2: monitoring-area bbox enforced at supervisor publish (was archive-only) (#PR_NUMBER_PLACEHOLDER) 2026-06-05 20:34:10 -06:00
test_form_descriptors.py refactor(wizard): generic adapter handling with Literal types 2026-05-19 00:38:06 +00:00
test_gdacs.py fix(2-E): use canonical removed-event subject pattern 2026-05-19 07:08:15 +00:00
test_geocoder_enricher.py feat(3-J): enrichment framework + GeocoderEnricher + NoOpBackend + FIRMS pilot 2026-05-20 04:39:49 +00:00
test_gui_adapter_edit.py v0.10.3: rip out state_511_atis adapter (superseded by itd_511 v0.10.0; Castle Rock legacy shape EOL per sister-site discovery) (#88) 2026-06-06 14:44:00 -06:00
test_gui_scaffold.py fix(tests): update tests for lazy app loading and 302 redirect 2026-05-17 06:14:25 +00:00
test_inciweb.py fix(2-C): wire dedup into poll loop, add conditional fetch 2026-05-19 03:53:10 +00:00
test_itd_511.py v0.10.6: extract mile_marker from itd_511 comment field as _enriched.mile_marker (#94) 2026-06-07 21:38:04 -06:00
test_itd_511_cameras.py v0.10.0: ITD 511 official API adapter (events + advisories + cameras) (#85) 2026-06-03 22:36:26 -06:00
test_migrate.py v0.9.18: reconcile schema_migrations drift + add --check drift detection 2026-05-27 06:40:38 +00:00
test_models.py v0.10.8: discriminate Nats-Msg-Id by event.category to prevent incident+perimeter dedup collision (#96) 2026-06-08 01:12:22 -06:00
test_monitoring_area.py v0.10.2: monitoring-area bbox enforced at supervisor publish (was archive-only) (#PR_NUMBER_PLACEHOLDER) 2026-06-05 20:34:10 -06:00
test_navi_backend.py feat(3-K.5): operator-settable EnrichmentConfig (config plumbing) 2026-05-20 18:52:22 +00:00
test_nominatim_backend.py feat(3-K): real geocoder backends + producer-doc reframe + consumer-doc enrichment 2026-05-20 16:10:44 +00:00
test_nwis.py v0.9.20: regional subject routing on quake / fire / hydro / disaster adapters 2026-05-27 23:50:30 -06:00
test_nwis_enrichment.py feat(nwis): site + stats enrichment — named location + WaterWatch normalcy band (v0.8.0) 2026-05-25 15:30:19 +00:00
test_nws_normalization.py v0.10.7: fix NWS SAME state-FIPS parse + 5-digit ANSI county form (#95) 2026-06-08 00:30:13 -06:00
test_photon_backend.py feat(3-K): real geocoder backends + producer-doc reframe + consumer-doc enrichment 2026-05-20 16:10:44 +00:00
test_preview_hook.py fix(2-G.5): preview_for_settings contract in adapter docstring + distinguish [] from None 2026-05-19 17:55:39 +00:00
test_producer_doc.py feat(3-K): real geocoder backends + producer-doc reframe + consumer-doc enrichment 2026-05-20 16:10:44 +00:00
test_region_picker.py feat(gui): generic adapter edit form 2026-05-18 23:16:37 +00:00
test_requires_api_key.py fix(2-A3b): complete error-render path, fix link, add supervisor tests 2026-05-19 02:17:29 +00:00
test_resend.py v0.10.5.2: fix BY_START_TIME feedback loop in Re-send (snapshot last_seq boundary) (#93) 2026-06-06 22:36:04 -06:00
test_session_auth.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_setup_gate.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_stream_registry.py feat(2-E.5): single-source-of-truth stream registry 2026-05-19 07:37:01 +00:00
test_streams.py feat(gui): implement first-run setup wizard (1b-8) (#24) 2026-05-17 22:06:22 -06:00
test_subject_helpers.py v0.9.20: regional subject routing on quake / fire / hydro / disaster adapters 2026-05-27 23:50:30 -06:00
test_supervisor_hotreload.py chore(lint-cleanup): remove 10 pre-existing ruff issues in 4 test files 2026-05-21 18:20:18 +00:00
test_supervisor_integration.py chore(lint-cleanup): remove 10 pre-existing ruff issues in 4 test files 2026-05-21 18:20:18 +00:00
test_supervisor_publish_filter.py v0.10.2: monitoring-area bbox enforced at supervisor publish (was archive-only) (#PR_NUMBER_PLACEHOLDER) 2026-06-05 20:34:10 -06:00
test_swpc.py feat(2-D): add NOAA SWPC space weather adapters (alerts, kindex, protons) 2026-05-19 05:55:29 +00:00
test_telemetry_separation.py v0.10.3: rip out state_511_atis adapter (superseded by itd_511 v0.10.0; Castle Rock legacy shape EOL per sister-site discovery) (#88) 2026-06-06 14:44:00 -06:00
test_tomtom_flow.py v0.10.2: monitoring-area bbox enforced at supervisor publish (was archive-only) (#PR_NUMBER_PLACEHOLDER) 2026-06-05 20:34:10 -06:00
test_tomtom_flow_passthrough.py feat(tomtom_flow): Navi passthrough endpoint /api/traffic/flow (v0.9.4) 2026-05-26 00:04:02 +00:00
test_tomtom_incidents.py fix(gui): generic model_list editor for list-of-model adapters + TomTom bbox validation & quota (v0.9.9) 2026-05-26 05:57:34 +00:00
test_usgs_quake.py v0.9.20: regional subject routing on quake / fire / hydro / disaster adapters 2026-05-27 23:50:30 -06:00
test_wfigs.py v0.10.4: switch wfigs_incidents to non-Current endpoint w/ WF active-only filter (resurrects IMT-managed fires like Blue Ridge) (#89) 2026-06-06 18:10:16 -06:00
test_wizard.py fix(wizard): eliminate all hardcoded field.name branches 2026-05-19 01:01:56 +00:00
test_wzdx.py WZDx: poll-time state allowlist with Idaho-region default (v0.9.17) 2026-05-27 05:57:57 +00:00

Central Tests

Test Database

Some tests (notably test_config_store.py) require a real PostgreSQL database. By default, tests connect to:

postgresql://central_test:testpass@localhost/central_test

If your test database uses different credentials, set the CENTRAL_TEST_DB_DSN environment variable:

export CENTRAL_TEST_DB_DSN="postgresql://myuser:mypass@localhost/mydb"
uv run pytest tests/test_config_store.py