mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-16 15:40:12 +01:00
173 lines
5.7 KiB
Python
173 lines
5.7 KiB
Python
import os
|
|
import importlib
|
|
import types
|
|
import pytest
|
|
from starlette.testclient import TestClient
|
|
|
|
from code.deck_builder.summary_telemetry import _reset_metrics_for_test, record_partner_summary
|
|
|
|
fastapi = pytest.importorskip("fastapi") # skip tests if FastAPI isn't installed
|
|
|
|
|
|
def load_app_with_env(**env: str) -> types.ModuleType:
|
|
for key in (
|
|
"SHOW_LOGS",
|
|
"SHOW_DIAGNOSTICS",
|
|
"SHOW_SETUP",
|
|
"SHOW_COMMANDERS",
|
|
"ENABLE_THEMES",
|
|
"ENABLE_PWA",
|
|
"ENABLE_PRESETS",
|
|
"APP_VERSION",
|
|
"THEME",
|
|
):
|
|
os.environ.pop(key, None)
|
|
for k, v in env.items():
|
|
os.environ[k] = v
|
|
import code.web.app as app_module # type: ignore
|
|
importlib.reload(app_module)
|
|
return app_module
|
|
|
|
|
|
def test_healthz_ok_and_request_id_header():
|
|
app_module = load_app_with_env()
|
|
client = TestClient(app_module.app)
|
|
r = client.get("/healthz")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data.get("status") in {"ok", "degraded"}
|
|
assert "uptime_seconds" in data
|
|
assert r.headers.get("X-Request-ID")
|
|
|
|
|
|
def test_404_renders_html_when_accept_html():
|
|
app_module = load_app_with_env()
|
|
client = TestClient(app_module.app)
|
|
r = client.get("/this-does-not-exist", headers={"Accept": "text/html"})
|
|
assert r.status_code == 404
|
|
body = r.text.lower()
|
|
assert "page not found" in body
|
|
assert "go home" in body
|
|
assert r.headers.get("X-Request-ID")
|
|
|
|
|
|
def test_htmx_http_exception_returns_json_with_request_id():
|
|
app_module = load_app_with_env(SHOW_DIAGNOSTICS="1")
|
|
client = TestClient(app_module.app)
|
|
r = client.get("/diagnostics/trigger-error", headers={"HX-Request": "true"})
|
|
assert r.status_code == 418
|
|
data = r.json()
|
|
assert data.get("error") is True
|
|
assert data.get("status") == 418
|
|
assert data.get("request_id")
|
|
assert r.headers.get("X-Request-ID")
|
|
|
|
|
|
def test_unhandled_exception_returns_500_json_with_request_id():
|
|
app_module = load_app_with_env(SHOW_DIAGNOSTICS="1")
|
|
# Configure client to not re-raise server exceptions so we can assert the 500 response
|
|
client = TestClient(app_module.app, raise_server_exceptions=False)
|
|
r = client.get("/diagnostics/trigger-error?kind=unhandled", headers={"HX-Request": "true"})
|
|
assert r.status_code == 500
|
|
data = r.json()
|
|
assert data.get("error") is True
|
|
assert data.get("status") == 500
|
|
assert data.get("request_id")
|
|
assert r.headers.get("X-Request-ID")
|
|
|
|
|
|
def test_status_sys_summary_and_flags():
|
|
app_module = load_app_with_env(
|
|
SHOW_LOGS="1",
|
|
SHOW_DIAGNOSTICS="1",
|
|
SHOW_SETUP="1",
|
|
SHOW_COMMANDERS="1",
|
|
ENABLE_THEMES="1",
|
|
ENABLE_PWA="1",
|
|
ENABLE_PRESETS="1",
|
|
APP_VERSION="testver",
|
|
THEME="dark",
|
|
)
|
|
client = TestClient(app_module.app)
|
|
r = client.get("/status/sys")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data.get("version") == "testver"
|
|
assert isinstance(data.get("uptime_seconds"), int)
|
|
assert isinstance(data.get("server_time_utc"), str)
|
|
flags = data.get("flags") or {}
|
|
assert flags.get("SHOW_LOGS") is True
|
|
assert flags.get("SHOW_DIAGNOSTICS") is True
|
|
assert flags.get("SHOW_SETUP") is True
|
|
assert flags.get("SHOW_COMMANDERS") is True
|
|
# Theme-related flags
|
|
assert flags.get("ENABLE_THEMES") is True
|
|
assert flags.get("ENABLE_PWA") is True
|
|
assert flags.get("ENABLE_PRESETS") is True
|
|
assert flags.get("DEFAULT_THEME") == "dark"
|
|
|
|
|
|
def test_commanders_nav_hidden_when_flag_disabled():
|
|
app_module = load_app_with_env(SHOW_COMMANDERS="0")
|
|
client = TestClient(app_module.app)
|
|
r = client.get("/")
|
|
assert r.status_code == 200
|
|
body = r.text
|
|
assert '<a href="/commanders"' not in body
|
|
|
|
|
|
def test_commanders_nav_visible_by_default():
|
|
app_module = load_app_with_env()
|
|
client = TestClient(app_module.app)
|
|
r = client.get("/")
|
|
assert r.status_code == 200
|
|
body = r.text
|
|
assert '<a href="/commanders"' in body
|
|
|
|
|
|
def test_partner_metrics_endpoint_reports_color_sources():
|
|
app_module = load_app_with_env(SHOW_DIAGNOSTICS="1")
|
|
_reset_metrics_for_test()
|
|
record_partner_summary(
|
|
{
|
|
"primary": "Tana, the Bloodsower",
|
|
"secondary": "Nadir Kraken",
|
|
"names": ["Tana, the Bloodsower", "Nadir Kraken"],
|
|
"partner_mode": "partner",
|
|
"combined": {
|
|
"partner_mode": "partner",
|
|
"color_identity": ["G", "U"],
|
|
"color_code": "GU",
|
|
"color_label": "Simic (GU)",
|
|
"color_sources": [
|
|
{"color": "G", "providers": [{"name": "Tana, the Bloodsower", "role": "primary"}]},
|
|
{"color": "U", "providers": [{"name": "Nadir Kraken", "role": "partner"}]},
|
|
],
|
|
"color_delta": {
|
|
"added": ["U"],
|
|
"removed": [],
|
|
"primary": ["G"],
|
|
"secondary": ["U"],
|
|
},
|
|
"secondary_role": "partner",
|
|
"secondary_role_label": "Partner commander",
|
|
},
|
|
}
|
|
)
|
|
|
|
client = TestClient(app_module.app)
|
|
resp = client.get("/status/partner_metrics")
|
|
assert resp.status_code == 200
|
|
payload = resp.json()
|
|
assert payload.get("ok") is True
|
|
metrics = payload.get("metrics") or {}
|
|
assert metrics.get("total_pairs", 0) >= 1
|
|
last = metrics.get("last_summary")
|
|
assert last is not None
|
|
sources = last.get("color_sources") or []
|
|
assert any(entry.get("color") == "G" for entry in sources)
|
|
assert any(
|
|
provider.get("role") == "partner"
|
|
for entry in sources
|
|
for provider in entry.get("providers", [])
|
|
)
|