Files
ATOCore/tests/test_v1_aliases.py
Anto01 5fbd7e6094 feat(api): /v1 alias router for stable external contract (Issue A)
Mounts an explicit allowlist of public handlers under /v1 alongside the
existing unversioned paths. External clients (AKC, OpenClaw, future
tools) should target /v1; internal callers (hooks, wiki, admin UI) keep
working unchanged. Breaking schema changes will bump the prefix to /v2.

- src/atocore/main.py: _V1_PUBLIC_PATHS allowlist + second router
- tests/test_v1_aliases.py: parity + OpenAPI presence (5 tests)
- README.md: API versioning section
- DEV-LEDGER.md: session log, test_count 459 -> 463

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:04:46 -04:00

62 lines
1.9 KiB
Python

"""Tests for /v1 API aliases — stable contract for external clients."""
from fastapi.testclient import TestClient
from atocore.main import app
def test_v1_health_alias_matches_unversioned():
client = TestClient(app)
unversioned = client.get("/health")
versioned = client.get("/v1/health")
assert unversioned.status_code == 200
assert versioned.status_code == 200
assert versioned.json()["build_sha"] == unversioned.json()["build_sha"]
def test_v1_projects_alias_returns_same_shape():
client = TestClient(app)
unversioned = client.get("/projects")
versioned = client.get("/v1/projects")
assert unversioned.status_code == 200
assert versioned.status_code == 200
assert versioned.json() == unversioned.json()
def test_v1_entities_get_alias_reachable(tmp_data_dir):
from atocore.engineering.service import init_engineering_schema
init_engineering_schema()
client = TestClient(app)
response = client.get("/v1/entities")
assert response.status_code == 200
body = response.json()
assert "entities" in body
def test_v1_paths_appear_in_openapi():
client = TestClient(app)
spec = client.get("/openapi.json").json()
paths = spec["paths"]
expected = [
"/v1/entities",
"/v1/relationships",
"/v1/ingest",
"/v1/context/build",
"/v1/projects",
"/v1/memory",
"/v1/projects/{project_name}/mirror",
"/v1/health",
]
for path in expected:
assert path in paths, f"{path} missing from OpenAPI spec"
def test_unversioned_paths_still_present_in_openapi():
"""Regression: /v1 aliases must not displace the original paths."""
client = TestClient(app)
spec = client.get("/openapi.json").json()
paths = spec["paths"]
for path in ("/entities", "/projects", "/health", "/context/build"):
assert path in paths, f"unversioned {path} missing — aliases must coexist"