80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
import json
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from ai_platform.infrastructure.openai_compatible_scoring import OpenAICompatibleScoringGateway
|
|
from ai_platform.lead_scoring.application.scoring_execution_repository import AIProviderFailure
|
|
|
|
|
|
def _completion(content: str) -> httpx.Response:
|
|
return httpx.Response(200, json={"choices": [{"message": {"content": content}}]})
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_compatible_adapter_accepts_json_fence_without_request_vkey():
|
|
requests: list[httpx.Request] = []
|
|
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
|
requests.append(request)
|
|
assert "authorization" not in request.headers
|
|
assert json.loads(request.content)["model"] == "gemini-3.5-flash-lite"
|
|
return _completion('```json\n{"items":[]}\n```')
|
|
|
|
http = httpx.AsyncClient(transport=httpx.MockTransport(handler))
|
|
provider = OpenAICompatibleScoringGateway("http://127.0.0.1:8317", None, http)
|
|
try:
|
|
evidence = await provider.extract_evidence(
|
|
model="gemini-3.5-flash-lite", snapshot={}, vkey="", timeout=7
|
|
)
|
|
finally:
|
|
await http.aclose()
|
|
assert evidence == []
|
|
assert len(requests) == 1
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("response", "error_code"),
|
|
[
|
|
(
|
|
_completion('{"score":80,"score":1,"confidence":0.8,"reasoning":"a"}'),
|
|
"openai_invalid_response",
|
|
),
|
|
(_completion('{"score":"80","confidence":0.8,"reasoning":"a"}'), "openai_invalid_score"),
|
|
(httpx.Response(429, text="sensitive upstream error"), "openai_http_error"),
|
|
],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_compatible_adapter_rejects_unsafe_outputs(response: httpx.Response, error_code: str):
|
|
http = httpx.AsyncClient(transport=httpx.MockTransport(lambda _: response))
|
|
provider = OpenAICompatibleScoringGateway("https://proxy.example", "test-key", http)
|
|
try:
|
|
with pytest.raises(AIProviderFailure) as error:
|
|
await provider.score(
|
|
model="ignored", system_prompt="system", user_prompt="user", vkey="", timeout=7
|
|
)
|
|
finally:
|
|
await http.aclose()
|
|
assert error.value.error_code == error_code
|
|
assert "sensitive upstream error" not in str(error.value)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_compatible_adapter_does_not_return_echoed_key():
|
|
secret = "test/secret"
|
|
http = httpx.AsyncClient(
|
|
transport=httpx.MockTransport(
|
|
lambda _: _completion(json.dumps({"score": 80, "confidence": 0.8, "reasoning": secret}))
|
|
)
|
|
)
|
|
provider = OpenAICompatibleScoringGateway("https://proxy.example", secret, http)
|
|
try:
|
|
with pytest.raises(AIProviderFailure) as error:
|
|
await provider.score(
|
|
model="ignored", system_prompt="system", user_prompt="user", vkey="", timeout=7
|
|
)
|
|
finally:
|
|
await http.aclose()
|
|
assert error.value.error_code == "openai_invalid_response"
|
|
assert secret not in str(error.value)
|