"""The image's healthcheck picks its check from the role it is running. What this protects is the DISPATCH, not the probes. Each probe is a couple of lines around a urllib call or a celery ping; the thing that can quietly go wrong is a container being asked the wrong question — a consolidated one checked as if it were web-only would report healthy with every worker dead, which is precisely the failure mode consolidation creates. """ from __future__ import annotations import pytest from backend.app.scripts import healthcheck as hc @pytest.fixture def calls(monkeypatch): """Record which probes ran, without running any of them.""" seen = [] def _stub(name, ok=True): def run(): seen.append(name) return (ok, "" if ok else f"{name} said no") return run monkeypatch.setattr(hc, "_web_ok", _stub("web")) monkeypatch.setattr(hc, "_lanes_ok", _stub("lanes")) monkeypatch.setattr(hc, "_this_node_ok", _stub("node")) return seen def _role(monkeypatch, value): monkeypatch.setattr(hc, "current_role", lambda: value) def test_the_consolidated_role_checks_both_halves(monkeypatch, calls): """`all` is the reason this file exists. Web alone would pass on a container whose every worker had died, and docker can no longer see those workers as separate services to notice for us.""" _role(monkeypatch, "all") assert hc.main() == 0 assert calls == ["web", "lanes"] def test_web_is_not_asked_about_lanes(monkeypatch, calls): """A web container runs no lanes, so asking would fail it for the absence of something it was never meant to have.""" _role(monkeypatch, "web") assert hc.main() == 0 assert calls == ["web"] @pytest.mark.parametrize("role", ["worker", "scheduler", "ml-worker"]) def test_a_celery_role_pings_itself_and_nothing_else(monkeypatch, calls, role): """No HTTP — these serve no port, and a web probe would fail every one of them.""" _role(monkeypatch, role) assert hc.main() == 0 assert calls == ["node"] @pytest.mark.parametrize("role", ["shell", "bash", "alembic"]) def test_one_shot_roles_have_nothing_to_check(monkeypatch, calls, role): _role(monkeypatch, role) assert hc.main() == 0 assert calls == [] def test_an_unrecorded_role_passes_rather_than_inventing_a_verdict( monkeypatch, calls, ): """The entrypoint did not run — someone used `--entrypoint` or a bare command. A check that cannot tell what it is looking at must not assert that the thing is broken (snippet #3969).""" _role(monkeypatch, None) assert hc.main() == 0 assert calls == [] def test_an_unknown_role_passes_too(monkeypatch, calls): """A role added to entrypoint.sh and not here is a gap in this file, not evidence the container is unhealthy.""" _role(monkeypatch, "something-new") assert hc.main() == 0 assert calls == [] def test_a_failing_probe_fails_the_check(monkeypatch): """The guard has to be able to fail (rule 167) — every test above asserts a 0, so one of them has to prove 0 is not all it can return.""" monkeypatch.setattr(hc, "current_role", lambda: "web") monkeypatch.setattr(hc, "_web_ok", lambda: (False, "web unreachable")) assert hc.main() == 1 def test_the_lane_half_can_fail_the_consolidated_role(monkeypatch): """The half that only the consolidated role has, and the half that actually broke on run 7319 — web answered while three of four lanes read as absent.""" monkeypatch.setattr(hc, "current_role", lambda: "all") monkeypatch.setattr(hc, "_web_ok", lambda: (True, "")) monkeypatch.setattr( hc, "_lanes_ok", lambda: (False, "lanes not answering: ml, worker"), ) assert hc.main() == 1 def test_the_role_is_read_from_the_file_the_entrypoint_writes(monkeypatch, tmp_path): """The contract between entrypoint.sh and this module. It is a file rather than an env var because the HEALTHCHECK exec inherits the container's environment, not whatever the entrypoint set at runtime.""" path = tmp_path / "fc-role" path.write_text("all\n") monkeypatch.delenv("FC_ROLE", raising=False) monkeypatch.setattr(hc, "ROLE_FILE", str(path)) assert hc.current_role() == "all" def test_a_missing_role_file_reads_as_unknown_not_as_a_crash(monkeypatch, tmp_path): monkeypatch.delenv("FC_ROLE", raising=False) monkeypatch.setattr(hc, "ROLE_FILE", str(tmp_path / "nope")) assert hc.current_role() is None