agnes-the-ai-analyst/tests/test_openapi_snapshot.py
ZdenekSrotyr 6c53082295 feat: multi-instance deployment — all 14 must-have items from spec
CalVer CI (release.yml) with stable/dev channels, health endpoint
with version/channel/schema_version, JWT secret auto-generation with
file persistence, smoke test script + Docker-in-CI, pre-migration
snapshot, /api/admin/configure for headless setup, /api/admin/
discover-and-register, /setup wizard, OpenAPI snapshot test, custom
connector mount support, CHANGELOG, migration safety tests, startup
banner.

663 tests pass (6 new migration safety + 3 OpenAPI snapshot + 1
updated JWT test).
2026-04-10 11:57:42 +02:00

73 lines
2.3 KiB
Python

"""OpenAPI snapshot test — detect breaking API changes.
Compares the current app's OpenAPI schema against a committed snapshot.
Fails if any path or HTTP method has been removed (breaking change).
To update the snapshot after an intentional change:
make update-openapi-snapshot
"""
import json
import os
from pathlib import Path
import pytest
SNAPSHOT_PATH = Path(__file__).parent / "snapshots" / "openapi.json"
@pytest.fixture(scope="module")
def current_schema():
os.environ.setdefault("TESTING", "1")
from app.main import create_app
app = create_app()
return app.openapi()
def test_snapshot_exists():
"""Committed OpenAPI snapshot must exist."""
assert SNAPSHOT_PATH.exists(), (
"No OpenAPI snapshot found. Generate one with: make update-openapi-snapshot"
)
def test_no_removed_paths(current_schema):
"""No API paths should be removed compared to the snapshot."""
if not SNAPSHOT_PATH.exists():
pytest.skip("No snapshot to compare against")
snapshot = json.loads(SNAPSHOT_PATH.read_text())
current_paths = set(current_schema.get("paths", {}))
snapshot_paths = set(snapshot.get("paths", {}))
removed = snapshot_paths - current_paths
assert not removed, (
f"BREAKING: {len(removed)} API path(s) removed: {sorted(removed)}\n"
"If intentional, run: make update-openapi-snapshot"
)
def test_no_removed_methods(current_schema):
"""No HTTP methods should be removed from existing paths."""
if not SNAPSHOT_PATH.exists():
pytest.skip("No snapshot to compare against")
snapshot = json.loads(SNAPSHOT_PATH.read_text())
current_paths = current_schema.get("paths", {})
snapshot_paths = snapshot.get("paths", {})
breaking = []
for path in set(snapshot_paths) & set(current_paths):
removed_methods = set(snapshot_paths[path]) - set(current_paths[path])
# Ignore non-HTTP keys like 'parameters'
http_methods = {"get", "post", "put", "delete", "patch", "head", "options"}
removed_http = removed_methods & http_methods
if removed_http:
breaking.append(f" {path}: {sorted(removed_http)}")
assert not breaking, (
f"BREAKING: HTTP methods removed from {len(breaking)} path(s):\n"
+ "\n".join(breaking)
+ "\nIf intentional, run: make update-openapi-snapshot"
)