dotb_ai-platform/tests/test_aihub_two_pass.py
hungtran24 b1f6643796 refactor: score synchronously and drop webhook/background execution
POST /v1/lead-scoring/score now evaluates in the request, applies an overall
AI deadline, and stores the completed run only after scoring. Idempotency is
kept by (app_id, account_id, request_id) with a body fingerprint.

Removes the webhook outbox, scheduler/recovery loop, app lead_scoring
permission, credential audit events, seed_demo and generate_secret scripts,
and the tests that covered them. Trims tests to behavior of the new flow.
2026-10-09 02:44:24 +07:00

105 lines
3.7 KiB
Python

import json
import httpx
import pytest
from ai_platform.infrastructure.aihub import AiHubClient, AiHubError
from ai_platform.lead_scoring.application.ai_provider import Evidence
from ai_platform.lead_scoring.application.scoring_prompts import (
scoring_system_prompt,
scoring_user_prompt,
)
VKEY = "request-only-vkey-test-secret"
def completion(content: str) -> httpx.Response:
return httpx.Response(
200,
json={"choices": [{"message": {"content": content}}]},
)
@pytest.mark.asyncio
async def test_two_pass_adapter_uses_same_model_timeout_and_vkey_without_putting_key_in_prompts():
requests: list[httpx.Request] = []
def handler(request: httpx.Request) -> httpx.Response:
requests.append(request)
body = json.loads(request.content)
assert body["model"] == "openai/gpt-4o-mini"
assert body["stream"] is False
assert body["response_format"] == {"type": "json_object"}
assert request.headers["authorization"] == f"Bearer {VKEY}"
assert request.extensions["timeout"]["read"] == 7
return completion(
'{"items":[{"signal":"ý định","detail":"Hỏi điều kiện đăng ký","source":"message-1"}]}'
if len(requests) == 1
else '{"score":81,"confidence":0.91,"reasoning":"Quan tâm rõ ràng"}'
)
http_client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
client = AiHubClient("https://aihub.test", http_client)
snapshot = {
"lead_profile": {"name": "Example", "custom_fields": {"region": "north"}},
"conversations": [
{
"messages": [
{
"message_id": "message-1",
"sender_type": "contact",
"content": "Please send me requirements.",
}
]
}
],
}
try:
evidence = await client.extract_evidence(
model="openai/gpt-4o-mini", snapshot=snapshot, vkey=VKEY, timeout=7
)
score = await client.score(
model="openai/gpt-4o-mini",
system_prompt=scoring_system_prompt("Đánh giá theo hồ sơ AI đã cấu hình."),
user_prompt=scoring_user_prompt(
snapshot,
[Evidence(item.signal, item.detail, item.source) for item in evidence.items],
),
vkey=VKEY,
timeout=7,
)
finally:
await client.aclose()
assert score.score == 81
assert score.confidence == 0.91
assert len(requests) == 2
for request in requests:
body = json.loads(request.content)
prompt = " ".join(message["content"] for message in body["messages"])
assert VKEY not in prompt
assert '"points"' not in prompt
assert '"rule_weight"' not in prompt
assert '"ai_weight"' not in prompt
assert "message-1" in json.loads(requests[0].content)["messages"][1]["content"]
assert "EVIDENCE" in json.loads(requests[1].content)["messages"][1]["content"]
@pytest.mark.asyncio
async def test_aihub_errors_have_stable_codes_and_do_not_expose_response_or_request_secret():
def handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(429, text=f"private response mentions {VKEY}")
client = AiHubClient(
"https://aihub.test", httpx.AsyncClient(transport=httpx.MockTransport(handler))
)
try:
with pytest.raises(AiHubError) as error:
await client.extract_evidence(model="openai/gpt-4o-mini", snapshot={}, vkey=VKEY)
finally:
await client.aclose()
assert error.value.error_code == "aihub_http_error"
assert VKEY not in str(error.value)
assert "private response" not in str(error.value)