"""Tests for NodeAgent._check_control_plane_health() transition-only emission. Regression coverage for the event-flood fix: the VPS control-plane HTTP probe used to emit service_healthy every single cycle it was reachable, which was part of the same flood as check_containers()'s per-service confirmation. """ from __future__ import annotations from unittest.mock import MagicMock import node_agent def run_probe(agent, monkeypatch, *, status=200, raise_exc=None): """Run _check_control_plane_health() with urlopen mocked, capturing emitted events.""" emitted = [] def fake_emit(event_type, severity, service, message, payload=None): emitted.append((event_type, severity, service, message, payload or {})) monkeypatch.setattr(agent, "emit_event", fake_emit) if raise_exc is not None: def fake_urlopen(*a, **kw): raise raise_exc else: resp = MagicMock() resp.status = status def fake_urlopen(*a, **kw): return resp monkeypatch.setattr("urllib.request.urlopen", fake_urlopen) agent._check_control_plane_health() return emitted def test_reachable_emits_service_healthy(agent, monkeypatch): events = run_probe(agent, monkeypatch, status=200) assert len(events) == 1 assert events[0][0] == "service_healthy" assert events[0][2] == "control-plane" def test_reachable_second_cycle_is_silent(agent, monkeypatch): run_probe(agent, monkeypatch, status=200) events = run_probe(agent, monkeypatch, status=200) assert events == [] def test_unreachable_reemits_service_unhealthy_every_cycle(agent, monkeypatch): """service_unhealthy is a real fault signal — must stay unconditional.""" run_probe(agent, monkeypatch, status=200) events = run_probe(agent, monkeypatch, raise_exc=OSError("connection refused")) assert events[0][0] == "service_unhealthy" events = run_probe(agent, monkeypatch, raise_exc=OSError("connection refused")) assert events[0][0] == "service_unhealthy" def test_recovery_after_unreachable_reemits_service_healthy(agent, monkeypatch): run_probe(agent, monkeypatch, raise_exc=OSError("connection refused")) events = run_probe(agent, monkeypatch, status=200) assert len(events) == 1 assert events[0][0] == "service_healthy"