dotb_ai-platform/tests/test_contract.py
hungtran24 6577bb74be refactor: simplify scoring service, AI profile revisions and test suite
Phase 2 and 3 of the platform rework.

- Neutral request/response contract: external_id, metadata, X-AI-Key,
  run_id in the response; client-specific fields removed.
- AI profile is a revision table: saving creates an inactive revision,
  activation is separate, try-run does not store a run. One
  chat-completions gateway serves AIHub and OpenAI-compatible profiles.
- Add between and in rule operators.
- Contracts moved to contracts/lead-scoring/ with a score-response fixture.
- Admin Web updated for revisions, runs and the neutral fixture.
- Consolidate tests; remove rewrite_architect.md and the stale handoff doc;
  rewrite spec, CONTEXT and ARCHITECTURE for the current design.

Not verified: live AIHub/OpenAI behavior, Omni/EMS integration.
2026-10-09 08:23:21 +07:00

44 lines
1.7 KiB
Python

import json
import subprocess
import sys
from pathlib import Path
from ai_platform.bootstrap.app import create_app
from ai_platform.infrastructure.config.settings import Settings
from ai_platform.presentation.http.run_responses import ScoreResponse
from ai_platform.presentation.http.schemas import RunRequest
ROOT = Path(__file__).resolve().parents[1]
CONTRACT = ROOT / "contracts/lead-scoring"
def test_committed_openapi_and_fixtures_match_the_code():
assert json.loads((CONTRACT / "openapi.json").read_text()) == create_app(Settings()).openapi()
ScoreResponse.model_validate_json((CONTRACT / "fixtures/score-response.json").read_text())
RunRequest.model_validate_json((CONTRACT / "fixtures/run-request.json").read_text())
subprocess.run(
[sys.executable, "scripts/export_contract_fixtures.py", "--check"], cwd=ROOT, check=True
)
def test_score_operation_is_documented_with_neutral_headers():
openapi = create_app(Settings()).openapi()
operation = openapi["paths"]["/v1/lead-scoring/score"]["post"]
headers = {p["name"] for p in operation["parameters"]}
assert operation["security"] == [{"HTTPBearer": []}]
assert {"Idempotency-Key", "X-AI-Key"} <= headers
assert {"200", "401", "413", "422", "503"} <= set(operation["responses"])
assert operation["responses"]["200"]["content"]["application/json"]["schema"] == {
"$ref": "#/components/schemas/ScoreResponse"
}
paths = set(openapi["paths"])
assert {
"/v1/admin/ai-profiles",
"/v1/admin/ai-profiles/try",
"/v1/admin/ai-profiles/{revision}/activate",
"/v1/admin/runs",
"/v1/admin/runs/{run_id}",
"/v1/admin/apps",
} <= paths
assert "/v1/lead-scoring/runs/{run_id}" not in paths