from __future__ import annotations """Coverage for backend integration helper modules.""" from contextlib import contextmanager from types import SimpleNamespace import httpx import pytest from atlas_portal import ariadne_client, db, k8s, mailer, migrate from atlas_portal.app_factory import create_app class DummyResponse: """Small httpx-like response for helper tests.""" def __init__(self, payload=None, *, status_code: int = 200, text: str = "", headers=None) -> None: self._payload = payload if payload is not None else {} self.status_code = status_code self.text = text self.headers = headers or {} def json(self): """Return the configured JSON payload.""" if isinstance(self._payload, BaseException): raise self._payload return self._payload def raise_for_status(self) -> None: """Raise for non-success responses like httpx does.""" if self.status_code >= 400: raise httpx.HTTPStatusError("bad status", request=None, response=None) def test_migrate_main_delegates_to_db(monkeypatch) -> None: calls: list[str] = [] monkeypatch.setattr(migrate, "run_migrations", lambda: calls.append("run")) migrate.main() assert calls == ["run"] def test_mailer_validates_configuration_and_sends(monkeypatch) -> None: sent: list[tuple[str, str]] = [] class DummySMTP: def __init__(self, host, port, timeout): self.host = host self.port = port self.timeout = timeout def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def starttls(self) -> None: sent.append(("starttls", "")) def login(self, username, password) -> None: sent.append(("login", f"{username}:{password}")) def send_message(self, message) -> None: sent.append(("send", message["To"])) monkeypatch.setattr(mailer.settings, "SMTP_HOST", "") with pytest.raises(mailer.MailerError): mailer.send_text_email(to_addr="a@example.dev", subject="Subject", body="Body") monkeypatch.setattr(mailer.settings, "SMTP_HOST", "smtp.example.dev") monkeypatch.setattr(mailer.settings, "SMTP_PORT", 587) monkeypatch.setattr(mailer.settings, "SMTP_USE_TLS", False) monkeypatch.setattr(mailer.settings, "SMTP_STARTTLS", True) monkeypatch.setattr(mailer.settings, "SMTP_USERNAME", "user") monkeypatch.setattr(mailer.settings, "SMTP_PASSWORD", "pw") monkeypatch.setattr(mailer.smtplib, "SMTP", DummySMTP) mailer.send_text_email(to_addr="a@example.dev", subject="Subject", body="Body") assert ("starttls", "") in sent assert ("login", "user:pw") in sent assert ("send", "a@example.dev") in sent body = mailer.access_request_verification_body(request_code="REQ", verify_url="https://verify.example.dev") assert "REQ" in body and "https://verify.example.dev" in body def test_mailer_reports_missing_recipient_and_send_errors(monkeypatch) -> None: class FailingSMTP: def __init__(self, *args, **kwargs): pass def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def send_message(self, message) -> None: raise OSError("offline") with pytest.raises(mailer.MailerError, match="missing recipient"): mailer.send_text_email(to_addr="", subject="Subject", body="Body") monkeypatch.setattr(mailer.settings, "SMTP_HOST", "smtp.example.dev") monkeypatch.setattr(mailer.settings, "SMTP_USE_TLS", True) monkeypatch.setattr(mailer.settings, "SMTP_STARTTLS", False) monkeypatch.setattr(mailer.settings, "SMTP_USERNAME", "") monkeypatch.setattr(mailer.smtplib, "SMTP_SSL", FailingSMTP) with pytest.raises(mailer.MailerError, match="failed to send email"): mailer.send_text_email(to_addr="a@example.dev", subject="Subject", body="Body") def test_k8s_get_and_post_json(monkeypatch) -> None: calls: list[tuple[str, str, object]] = [] class DummyClient: def __init__(self, **kwargs): calls.append(("init", "", kwargs)) def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def get(self, url): calls.append(("get", url, None)) return DummyResponse({"kind": "Pod"}) def post(self, url, json=None): calls.append(("post", url, json)) return DummyResponse({"kind": "Job"}) monkeypatch.setattr(k8s, "_read_service_account", lambda: ("token", "/ca.crt")) monkeypatch.setattr(k8s.httpx, "Client", DummyClient) assert k8s.get_json("/api/v1/pods") == {"kind": "Pod"} assert k8s.post_json("/apis/batch/v1/jobs", {"metadata": {"name": "job"}}) == {"kind": "Job"} assert calls[1][0] == "get" assert calls[2][0] == "init" assert calls[3][0] == "post" def test_k8s_service_account_and_bad_json(monkeypatch, tmp_path) -> None: sa_path = tmp_path / "sa" sa_path.mkdir() monkeypatch.setattr(k8s, "_SA_PATH", sa_path) with pytest.raises(RuntimeError, match="token missing"): k8s._read_service_account() (sa_path / "token").write_text(" ") (sa_path / "ca.crt").write_text("ca") with pytest.raises(RuntimeError, match="token empty"): k8s._read_service_account() (sa_path / "token").write_text("token") assert k8s._read_service_account() == ("token", str(sa_path / "ca.crt")) class BadClient: def __init__(self, **kwargs): pass def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def get(self, url): return DummyResponse([]) def post(self, url, json=None): return DummyResponse([]) monkeypatch.setattr(k8s.httpx, "Client", BadClient) with pytest.raises(RuntimeError, match="unexpected kubernetes response"): k8s.get_json("/api/v1/pods") with pytest.raises(RuntimeError, match="unexpected kubernetes response"): k8s.post_json("/api/v1/pods", {}) def test_ariadne_proxy_paths(monkeypatch) -> None: monkeypatch.setattr(ariadne_client.settings, "ARIADNE_URL", "") assert not ariadne_client.enabled() with pytest.raises(ariadne_client.AriadneError): ariadne_client.request_raw("GET", "/health") class DummyClient: def __init__(self, timeout): self.timeout = timeout def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def request(self, method, url, headers=None, json=None, params=None): assert headers == {"Authorization": "Bearer token"} return DummyResponse({"ok": True}) monkeypatch.setattr(ariadne_client.settings, "ARIADNE_URL", "https://ariadne.example.dev") monkeypatch.setattr(ariadne_client.httpx, "Client", DummyClient) app = create_app() with app.test_request_context(headers={"Authorization": "Bearer token"}): response = ariadne_client.request_raw("POST", "/path", payload={"a": 1}) assert response.json() == {"ok": True} flask_response, status = ariadne_client.proxy("POST", "/path") assert status == 200 assert flask_response.get_json() == {"ok": True} def test_ariadne_error_and_proxy_fallback_paths(monkeypatch) -> None: class ServerErrorClient: def __init__(self, timeout): pass def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def request(self, method, url, headers=None, json=None, params=None): return DummyResponse({"error": "upstream"}, status_code=503) monkeypatch.setattr(ariadne_client.settings, "ARIADNE_URL", "https://ariadne.example.dev") monkeypatch.setattr(ariadne_client.httpx, "Client", ServerErrorClient) app = create_app() with app.test_request_context(): assert ariadne_client.request_raw("GET", "/health").status_code == 503 attempts = {"count": 0} class FailingClient: def __init__(self, timeout): pass def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def request(self, method, url, headers=None, json=None, params=None): attempts["count"] += 1 raise httpx.RequestError("offline") monkeypatch.setattr(ariadne_client.settings, "ARIADNE_RETRY_COUNT", 2) monkeypatch.setattr(ariadne_client.settings, "ARIADNE_RETRY_BACKOFF_SEC", 0) monkeypatch.setattr(ariadne_client.httpx, "Client", FailingClient) with app.test_request_context(): with pytest.raises(ariadne_client.AriadneError): ariadne_client.request_raw("GET", "/health") assert attempts["count"] == 2 with app.test_request_context(): monkeypatch.setattr(ariadne_client, "request_raw", lambda *a, **k: (_ for _ in ()).throw(ariadne_client.AriadneError("down", 504))) response, status = ariadne_client.proxy("GET", "/health") assert status == 504 assert response.get_json()["error"] == "down" monkeypatch.setattr(ariadne_client, "request_raw", lambda *a, **k: DummyResponse(ValueError("bad json"), text="plain", status_code=502)) response, status = ariadne_client.proxy("GET", "/health") assert status == 502 assert response.get_json()["error"] == "plain" def test_db_pool_and_migration_paths(monkeypatch) -> None: executed: list[tuple[str, object]] = [] class DummyConn: row_factory = None def execute(self, query, params=None): executed.append((str(query), params)) if "pg_try_advisory_lock" in str(query): return SimpleNamespace(fetchone=lambda: {"pg_try_advisory_lock": True}) return SimpleNamespace(fetchone=lambda: None) @contextmanager def fake_connect(): yield DummyConn() monkeypatch.setattr(db.settings, "PORTAL_DATABASE_URL", "") assert not db.configured() with pytest.raises(RuntimeError): db._get_pool() with pytest.raises(RuntimeError): with db.connect(): pass monkeypatch.setattr(db.settings, "PORTAL_DATABASE_URL", "postgres://portal") monkeypatch.setattr(db.settings, "PORTAL_RUN_MIGRATIONS", True) monkeypatch.setattr(db, "connect", fake_connect) monkeypatch.setattr(db, "_release_advisory_lock", lambda conn, lock_id: executed.append(("release", lock_id))) db.run_migrations() db.ensure_schema() assert any("CREATE TABLE IF NOT EXISTS access_requests" in query for query, _ in executed) assert ("release", db.MIGRATION_LOCK_ID) in executed def test_db_pool_connect_and_lock_edge_paths(monkeypatch) -> None: class DummyPool: def __init__(self, **kwargs): self.kwargs = kwargs @contextmanager def connection(self): yield SimpleNamespace(row_factory=None) monkeypatch.setattr(db.settings, "PORTAL_DATABASE_URL", "postgres://portal") monkeypatch.setattr(db, "ConnectionPool", DummyPool) monkeypatch.setattr(db, "_pool", None) assert db.configured() pool = db._get_pool() assert pool.kwargs["conninfo"] == "postgres://portal" assert "statement_timeout" in db._pool_kwargs()["options"] with db.connect() as conn: assert conn.row_factory is db.dict_row assert db._get_pool() is pool tuple_conn = SimpleNamespace(execute=lambda *a, **k: SimpleNamespace(fetchone=lambda: (0,))) assert not db._try_advisory_lock(tuple_conn, 1) class BadConn: def execute(self, *args, **kwargs): raise RuntimeError("ignore") db._release_advisory_lock(BadConn(), 1) def test_db_migration_lock_skip(monkeypatch) -> None: @contextmanager def fake_connect(): yield SimpleNamespace(execute=lambda *a, **k: SimpleNamespace(fetchone=lambda: {"pg_try_advisory_lock": False})) monkeypatch.setattr(db.settings, "PORTAL_DATABASE_URL", "postgres://portal") monkeypatch.setattr(db.settings, "PORTAL_RUN_MIGRATIONS", True) monkeypatch.setattr(db, "connect", fake_connect) db.run_migrations()