160 lines
5.4 KiB
Python
160 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib
|
|
|
|
|
|
preflight = importlib.import_module("scripts.postgres_dev_preflight")
|
|
|
|
|
|
def test_run_preflight_rejects_non_postgres_database_url(monkeypatch):
|
|
monkeypatch.setenv("SCHEMA_MANAGEMENT_MODE", "migrations")
|
|
|
|
results = preflight.run_preflight(
|
|
database_url="sqlite:///./mvp_cc.db",
|
|
base_url=None,
|
|
require_rabbitmq=False,
|
|
)
|
|
|
|
assert len(results) == 1
|
|
assert results[0].name == "database_url"
|
|
assert results[0].ok is False
|
|
|
|
|
|
def test_run_preflight_requires_migrations_mode(monkeypatch):
|
|
monkeypatch.setenv("SCHEMA_MANAGEMENT_MODE", "legacy")
|
|
|
|
results = preflight.run_preflight(
|
|
database_url="postgresql://mvp:mvp@localhost:5432/mvpcc",
|
|
base_url=None,
|
|
require_rabbitmq=False,
|
|
)
|
|
|
|
assert [item.name for item in results] == ["database_url", "schema_management_mode"]
|
|
assert results[-1].ok is False
|
|
|
|
|
|
def test_run_preflight_passes_with_http_and_rabbitmq(monkeypatch):
|
|
monkeypatch.setenv("SCHEMA_MANAGEMENT_MODE", "migrations")
|
|
monkeypatch.setenv("EVENT_BUS_ENABLED", "1")
|
|
monkeypatch.setenv("EVENT_BUS_URL", "amqp://guest:guest@localhost:5672/")
|
|
|
|
monkeypatch.setattr(
|
|
preflight,
|
|
"_check_tcp_endpoint",
|
|
lambda name, url, default_port: preflight.CheckResult(name, True, f"{default_port} ok"),
|
|
)
|
|
monkeypatch.setattr(
|
|
preflight,
|
|
"_check_database_connection",
|
|
lambda database_url: preflight.CheckResult("database_connection", True, "SELECT 1 succeeded"),
|
|
)
|
|
monkeypatch.setattr(
|
|
preflight,
|
|
"_check_schema_migrations",
|
|
lambda database_url: preflight.CheckResult("schema_migrations", True, "applied=18/18"),
|
|
)
|
|
monkeypatch.setattr(
|
|
preflight,
|
|
"_http_preflight_checks",
|
|
lambda base_url: [
|
|
preflight.CheckResult("gateway_health", True, "status=200"),
|
|
preflight.CheckResult("auth_health", True, "status=200"),
|
|
],
|
|
)
|
|
|
|
results = preflight.run_preflight(
|
|
database_url="postgresql://mvp:mvp@localhost:5432/mvpcc",
|
|
base_url="http://127.0.0.1:8080",
|
|
require_rabbitmq=False,
|
|
)
|
|
|
|
assert all(item.ok for item in results)
|
|
assert any(item.name == "rabbitmq_tcp" for item in results)
|
|
assert any(item.name == "gateway_health" for item in results)
|
|
|
|
|
|
def test_main_returns_nonzero_when_preflight_fails(monkeypatch, capsys):
|
|
monkeypatch.setattr(
|
|
preflight,
|
|
"run_preflight",
|
|
lambda **kwargs: [preflight.CheckResult("database_connection", False, "boom")],
|
|
)
|
|
monkeypatch.setattr(
|
|
preflight.argparse.ArgumentParser,
|
|
"parse_args",
|
|
lambda self: type(
|
|
"Args",
|
|
(),
|
|
{
|
|
"env_file": [],
|
|
"database_url": "postgresql://mvp:mvp@localhost:5432/mvpcc",
|
|
"base_url": "",
|
|
"require_rabbitmq": False,
|
|
"json": False,
|
|
},
|
|
)(),
|
|
)
|
|
|
|
exit_code = preflight.main()
|
|
output = capsys.readouterr().out
|
|
|
|
assert exit_code == 1
|
|
assert "[FAIL] PostgreSQL dev preflight failed" in output
|
|
|
|
|
|
def test_http_preflight_uses_admin_login_token_for_read_checks(monkeypatch):
|
|
monkeypatch.setenv("ALLOW_LEGACY_HEADER_AUTH", "0")
|
|
monkeypatch.setenv("EVENT_BUS_ENABLED", "0")
|
|
monkeypatch.setenv("ASTERISK_BRIDGE_ENABLED", "0")
|
|
monkeypatch.setattr(preflight, "issue_app_token", lambda **kwargs: "ops-token")
|
|
|
|
recorded_headers = {}
|
|
|
|
class FakeResponse:
|
|
def __init__(self, status_code, payload):
|
|
self.status_code = status_code
|
|
self._payload = payload
|
|
|
|
def json(self):
|
|
return self._payload
|
|
|
|
class FakeClient:
|
|
def __init__(self, *args, **kwargs):
|
|
pass
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc, tb):
|
|
return False
|
|
|
|
def get(self, path, headers=None):
|
|
if path == "/health":
|
|
return FakeResponse(200, {"status": "ok"})
|
|
if path == "/registry":
|
|
return FakeResponse(200, {"services": {name: {} for name in preflight.REQUIRED_PROXY_HEALTH_SERVICES}})
|
|
if path.startswith("/proxy/") and path.endswith("/health"):
|
|
return FakeResponse(200, {"status": "ok"})
|
|
if path in {
|
|
"/proxy/routing/queues",
|
|
"/proxy/voice/integrations/voice/events?limit=1",
|
|
"/proxy/whatsapp/integrations/whatsapp/threads",
|
|
}:
|
|
recorded_headers[path] = dict(headers or {})
|
|
return FakeResponse(200, [])
|
|
raise AssertionError(f"Unexpected GET path: {path}")
|
|
|
|
def post(self, path, json=None):
|
|
if path == "/proxy/auth/auth/login":
|
|
return FakeResponse(200, {"access_token": "login-token"})
|
|
raise AssertionError(f"Unexpected POST path: {path}")
|
|
|
|
monkeypatch.setattr(preflight.httpx, "Client", FakeClient)
|
|
|
|
results = preflight._http_preflight_checks("http://127.0.0.1:18080")
|
|
|
|
assert all(item.ok for item in results)
|
|
assert recorded_headers["/proxy/routing/queues"] == {"Authorization": "Bearer login-token"}
|
|
assert recorded_headers["/proxy/voice/integrations/voice/events?limit=1"] == {"Authorization": "Bearer login-token"}
|
|
assert recorded_headers["/proxy/whatsapp/integrations/whatsapp/threads"] == {"Authorization": "Bearer login-token"}
|