agnes-the-ai-analyst/tests/test_admin_server_config_placeholder.py
ZdenekSrotyr f0494ef356 test(admin): #160 RED tests for BQ test-connection + server-config placeholder
Two new test files driving the next commit's admin UI work.

tests/test_admin_bigquery_test_connection.py — POST
/api/admin/bigquery/test-connection (admin-only health probe). 6 cases:
- success → 200 with ok=true + resolved billing_project / data_project
  / elapsed_ms
- not_configured → 400 with the typed BqAccessError detail surface
- cross_project_forbidden (USER_PROJECT_DENIED simulation) → 502
- 10s timeout → 504 with kind="timeout" (best-effort cancel_job)
- non-admin caller → 403
- unauthenticated → 401

The endpoint matters for the operator side of the reporter's loop —
admin saves data_source.bigquery in /admin/server-config, clicks
"Test connection", gets typed structured feedback BEFORE any analyst
hits a query failure.

tests/test_admin_server_config_placeholder.py — `billing_project`
field-spec must carry `placeholder_from: ["data_source", "bigquery",
"project"]` so the JS template can resolve and inject
"(defaults to <project>)" greyed under the input when the operator
hasn't set billing_project explicitly. This makes the existing
"billing falls back to data" rule (connectors/bigquery/access.py:
339-340) visible in the UI.

7 RED on the current branch (endpoint and placeholder_from key both
absent). GREEN landing in the next commit.
2026-05-04 10:31:35 +02:00

29 lines
1.2 KiB
Python

"""GET /api/admin/server-config exposes `placeholder_from` for fields
whose UI placeholder should resolve to another config value at render
time. Used by `data_source.bigquery.billing_project` to surface its
fallback to `data_source.bigquery.project` (see
connectors/bigquery/access.py:339-340).
Closes part of #160 §4.7.5.
"""
from __future__ import annotations
def _auth(token: str) -> dict:
return {"Authorization": f"Bearer {token}"}
def test_billing_project_field_carries_placeholder_from(seeded_app):
"""The known-fields registry must mark billing_project's
placeholder_from path so the JS template can resolve and inject
`(defaults to <project>)` at render time."""
c = seeded_app["client"]
token = seeded_app["admin_token"]
r = c.get("/api/admin/server-config", headers=_auth(token))
assert r.status_code == 200, r.json()
fields = r.json()["known_fields"]["data_source"]["bigquery"]["fields"]
assert "billing_project" in fields
spec = fields["billing_project"]
assert spec.get("placeholder_from") == [
"data_source", "bigquery", "project",
], f"expected placeholder_from path; got {spec.get('placeholder_from')!r}"