atlas-iac/testing/tests/test_hermes_hux_modes_backend.py

152 lines
8.1 KiB
Python
Raw Normal View History

"""Focused HUX-06 backend tests."""
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
FOUNDATION = ROOT / "dockerfiles" / "hermes-hux-foundation"
if str(FOUNDATION) not in sys.path:
sys.path.insert(0, str(FOUNDATION))
from hux import contracts, identity, modes, store
from hux.errors import Invalid
from hux.server import build_router
HEADERS = {"X-Hermes-Tenant-Identity": "slot-3", "X-Hux-Subject": "usr_0123456789abcdef", "X-Hux-Surface": "chat", "X-Hux-Relay-Key": "rk"}
OTHER = {**HEADERS, "X-Hux-Subject": "usr_fedcba9876543210"}
ALL_ON = ",".join(card["flag"] for card in contracts.load_flags()["cards"])
def call(router, method, path, body=None, headers=None):
raw = b"" if body is None else json.dumps(body).encode()
response = router.dispatch(method, path, {**HEADERS, **(headers or {})}, raw)
return response.status, response.body, response.headers
@pytest.fixture
def setup(tmp_path, monkeypatch):
monkeypatch.setenv("HUX_SWITCHYARD_ROUTE_CATALOG", "atlas/manual/codex/gpt-5,atlas/manual/claude/opus,atlas/manual/local/qwen-14b")
router = build_router(tmp_path, {"HUX_FLAGS": ALL_ON, "HUX_ROUTER_KEY": "rk"})
_, project, _ = call(router, "POST", "/hux/v1/projects", {"name": "P"})
_, conversation, _ = call(router, "POST", "/hux/v1/conversations", {"title": "C", "project_id": project["id"]})
base = f"/hux/v1/projects/{project['id']}/conversations/{conversation['id']}/mode"
return router, project, conversation, base
def test_catalog_is_provider_neutral_and_private_is_local(setup):
router, _, _, _ = setup
status, body, _ = call(router, "GET", "/hux/v1/modes")
assert status == 200 and [row["mode"] for row in body["items"]] == list(modes.MODE_NAMES)
for row in body["items"]:
assert contracts.validate("mode.schema.json", row) == []
if row["mode"] != "private":
assert row["switchyard"]["route_id"].startswith("atlas/auto/")
assert "/codex/" not in row["switchyard"]["route_id"] and "/claude/" not in row["switchyard"]["route_id"]
private = body["items"][-1]
assert private["constraints"]["providers"] == ["local"] and private["constraints"]["local_only"] is True
def test_select_get_replay_and_conversation_privacy_mode(setup):
router, project, conversation, base = setup
body = {"project_id": project["id"], "mode": "private"}
status, selected, headers = call(router, "PUT", base, body, {"If-Match": "0", "Idempotency-Key": "mode-key-0001"})
assert (status, selected["revision"], headers["ETag"]) == (200, 1, "1")
assert selected["mode"]["mode"] == "private" and selected["mode"]["switchyard"]["route_id"].startswith("atlas/manual/local/")
assert call(router, "GET", base)[1] == selected
stored_conversation = call(router, "GET", f"/hux/v1/conversations/{conversation['id']}")[1]
assert stored_conversation["mode"] == "private"
status, replay, replay_headers = call(router, "PUT", base, body, {"If-Match": "0", "Idempotency-Key": "mode-key-0001"})
assert status == 200 and replay == selected and replay_headers["HUX-Replayed"] == "true"
status, error, _ = call(router, "PUT", base, {**body, "mode": "fast"}, {"If-Match": "1", "Idempotency-Key": "mode-key-0001"})
assert (status, error["code"]) == (409, "conflict")
def test_advanced_pin_is_explicit_catalogued_and_constrained(setup):
router, project, _, base = setup
common = {"project_id": project["id"], "mode": "thoughtful"}
pin = "atlas/manual/claude/opus"
status, selected, _ = call(router, "PUT", base, {**common, "advanced": True, "override_route_id": pin}, {"If-Match": "0", "Idempotency-Key": "mode-key-0002"})
assert status == 200 and selected["mode"]["switchyard"]["override_route_id"] == pin
next_headers = {"If-Match": "1", "Idempotency-Key": "mode-key-0003"}
bad = [
{**common, "override_route_id": pin},
{**common, "advanced": True},
{**common, "advanced": True, "override_route_id": "atlas/manual/claude/not-catalogued"},
{**common, "advanced": True, "override_route_id": "atlas/auto/deep"},
{"project_id": project["id"], "mode": "private", "advanced": True, "override_route_id": "atlas/manual/claude/opus"},
]
for index, body in enumerate(bad):
status, error, _ = call(router, "PUT", base, body, {**next_headers, "Idempotency-Key": f"bad-mode-{index:03}"})
assert status == 400 and error["code"] == "invalid"
status, local, _ = call(router, "PUT", base, {"project_id": project["id"], "mode": "private", "advanced": True, "override_route_id": "atlas/manual/local/qwen-14b"}, next_headers)
assert status == 200 and local["revision"] == 2
@pytest.mark.parametrize("body,headers", [
({"project_id": None, "mode": "fast"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0100"}),
({"project_id": "prj_wrong0000", "mode": "fast"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0101"}),
({"mode": "fast"}, {"If-Match": "0"}),
({"mode": "fast"}, {"Idempotency-Key": "mode-key-0102"}),
({"mode": "unknown"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0103"}),
])
def test_selection_fails_closed(setup, body, headers):
router, project, _, base = setup
if "project_id" not in body:
body["project_id"] = project["id"]
status, _, _ = call(router, "PUT", base, body, headers)
assert status in {400, 404}
def test_revision_scope_and_catalog_bounds(setup, monkeypatch):
router, project, _, base = setup
body = {"project_id": project["id"], "mode": "fast"}
assert call(router, "PUT", base, body, {"If-Match": "1", "Idempotency-Key": "mode-key-0200"})[0] == 409
assert call(router, "GET", base)[0] == 404
assert call(router, "GET", base, headers=OTHER)[0] == 404
wrong = base.replace(project["id"], "prj_missing0000")
assert call(router, "GET", wrong)[0] == 404
monkeypatch.setenv("HUX_SWITCHYARD_ROUTE_CATALOG", ",".join(f"atlas/manual/codex/r{i}" for i in range(257)))
advanced = {**body, "advanced": True, "override_route_id": "atlas/manual/codex/r1"}
assert call(router, "PUT", base, advanced, {"If-Match": "0", "Idempotency-Key": "mode-key-0201"})[0] == 400
monkeypatch.setenv("HUX_SWITCHYARD_ROUTE_CATALOG", "garbage,atlas/manual/codex/gpt-5")
assert modes._catalog() == {"atlas/manual/codex/gpt-5"}
def test_body_and_header_validation(setup):
router, project, _, base = setup
assert router.dispatch("PUT", base, HEADERS, b"[]").status == 400
body = {"project_id": project["id"], "mode": "fast"}
assert call(router, "PUT", base, body, {"If-Match": "x", "Idempotency-Key": "mode-key-0300"})[0] == 400
assert call(router, "PUT", base, body, {"If-Match": "0", "Idempotency-Key": "short"})[0] == 400
assert call(router, "PUT", base, {**body, "provider": "claude"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0301"})[0] == 400
def test_missing_project_and_defensive_contract_failures(setup, monkeypatch):
router, project, _, base = setup
scoped = store.TenantStore(router.data_root, identity.resolve(HEADERS, {"HUX_ROUTER_KEY": "rk"}))
scoped.delete("projects", project["id"])
assert call(router, "GET", base)[0] == 404
original = modes.rules.mode_contract
monkeypatch.setattr(modes.rules, "mode_contract", lambda *_: (_ for _ in ()).throw(ValueError("bad mapping")))
with pytest.raises(Invalid, match="bad mapping"):
modes._contract("fast", False, None)
monkeypatch.setattr(modes.rules, "mode_contract", lambda *_: {"schema": "broken"})
with pytest.raises(Invalid, match="contract validation"):
modes._contract("fast", False, None)
monkeypatch.setattr(modes.rules, "mode_contract", original)
record = original("fast")
record["switchyard"]["route_id"] = "atlas/manual/codex/gpt-5"
monkeypatch.setattr(modes.rules, "mode_contract", lambda *_: record)
with pytest.raises(Invalid, match="may not pin"):
modes._contract("fast", False, None)
def test_source_and_test_files_stay_bounded():
assert len((FOUNDATION / "hux" / "modes.py").read_text().splitlines()) <= 500
assert len(Path(__file__).read_text().splitlines()) <= 500