"""The startup gate that stands in for Swarm's missing `depends_on`. Swarm ignores `depends_on`, so the container races its own database on every cold deploy. Under supervisord a program that fails three times goes FATAL and stays there, so losing that race does not self-heal the way it did when Swarm restarted a failed task — it leaves a running container with a dead application inside it. """ from __future__ import annotations import pytest from backend.app.scripts import wait_for_deps as w def test_it_waits_for_both_postgres_and_redis(monkeypatch): monkeypatch.setenv("DB_HOST", "postgres") monkeypatch.setenv("DB_PORT", "5432") monkeypatch.setenv("CELERY_BROKER_URL", "redis://redis:6379/0") assert w.targets() == [ ("postgres", ("postgres", 5432)), ("redis", ("redis", 6379)), ] def test_the_targets_come_from_the_same_env_the_app_reads(monkeypatch): """A gate that checks a different host than the application connects to is worse than no gate — it would pass while the app still cannot reach its database.""" monkeypatch.setenv("DB_HOST", "10.0.0.5") monkeypatch.setenv("DB_PORT", "6543") monkeypatch.setenv("CELERY_BROKER_URL", "redis://broker.internal:6380/2") assert w.targets() == [ ("postgres", ("10.0.0.5", 6543)), ("redis", ("broker.internal", 6380)), ] def test_a_broker_url_without_a_port_falls_back_to_the_default(monkeypatch): monkeypatch.delenv("DB_HOST", raising=False) monkeypatch.setenv("CELERY_BROKER_URL", "redis://redis/0") assert w.targets() == [("redis", ("redis", 6379))] def test_nothing_configured_is_not_an_error(monkeypatch): """`shell` and one-off runs are legitimate. Refusing to start would make this gate the reason a debugging container will not boot.""" monkeypatch.delenv("DB_HOST", raising=False) monkeypatch.delenv("CELERY_BROKER_URL", raising=False) assert w.targets() == [] assert w.main([]) == 0 def test_it_returns_as_soon_as_the_port_accepts(monkeypatch): attempts = {"n": 0} def accepts(host, port): attempts["n"] += 1 return attempts["n"] >= 3 monkeypatch.setattr(w, "_accepts", accepts) monkeypatch.setattr(w.time, "sleep", lambda _: None) assert w.wait("postgres", "h", 5432, deadline=float("inf")) is True assert attempts["n"] == 3 def test_it_gives_up_at_the_deadline_rather_than_hanging(monkeypatch): """A wait with no deadline is a bug (rule 156). A container that never starts and never says why is the shape this must not have.""" monkeypatch.setattr(w, "_accepts", lambda h, p: False) monkeypatch.setattr(w.time, "sleep", lambda _: None) clock = iter([0.0, 0.0, 99.0]) assert w.wait( "postgres", "h", 5432, deadline=10.0, now=lambda: next(clock), ) is False def test_a_dependency_that_never_comes_up_fails_the_boot(monkeypatch): monkeypatch.setenv("DB_HOST", "postgres") monkeypatch.delenv("CELERY_BROKER_URL", raising=False) monkeypatch.setattr(w, "_accepts", lambda h, p: False) monkeypatch.setattr(w.time, "sleep", lambda _: None) assert w.main(["--timeout", "0"]) == 1