dotb_ai-platform/tests/test_profile_provider_execution.py

104 lines
3.2 KiB
Python

import json
from datetime import UTC, datetime
from pathlib import Path
import pytest
from ai_platform.lead_scoring.application.repository import AIProfileRecord
from ai_platform.lead_scoring.application.scoring_execution import ScoringExecutionUseCases
from ai_platform.lead_scoring.application.scoring_execution_repository import (
Evidence,
Scoring,
ScoringExecutionRun,
ScoringResult,
)
FIXTURE = Path(__file__).parent / "fixtures" / "mock_omni_run.json"
class RunRepository:
def __init__(self, run: ScoringExecutionRun, profile: AIProfileRecord):
self.run = run
self.profile = profile
self.result: ScoringResult | None = None
async def find_run(self, run_id: str):
return self.run
async def find_profile(self, version: str):
assert version == self.run.profile_version
return self.profile
async def mark_running(self, run_id: str):
pass
async def complete(self, run_id: str, result: ScoringResult, completed_at: datetime):
self.result = result
async def fail(self, run_id: str, completed_at: datetime, error_code: str):
pytest.fail(f"execution failed: {error_code}")
async def mark_interrupted(self, completed_at: datetime):
pytest.fail("unexpected recovery")
class StubProvider:
def __init__(self):
self.models: list[str] = []
self.keys: list[str] = []
async def extract_evidence(self, *, model, snapshot, vkey, timeout):
self.models.append(model)
self.keys.append(vkey)
return [Evidence("interest", "Asked about enrollment", "mock-message-001")]
async def score(self, *, model, system_prompt, user_prompt, vkey, timeout):
self.models.append(model)
self.keys.append(vkey)
return Scoring(80, 0.8, "Evidence supports intent")
@pytest.mark.asyncio
async def test_execution_uses_frozen_profile_provider_and_never_forwards_vkey_to_openai():
payload = json.loads(FIXTURE.read_text())
payload["ai_profile"] = "medium"
payload["scoring_config"].update(rule_weight=0.5, ai_weight=0.5)
run = ScoringExecutionRun("run-1", "pending", payload, "old-profile")
profile = AIProfileRecord(
"old-profile",
"gemini-3.5-flash-lite",
"prompt",
30,
{},
False,
"openai_compatible",
"http://127.0.0.1:8318",
)
repository = RunRepository(run, profile)
old_provider = StubProvider()
active_aihub_provider = StubProvider()
async def no_op():
pass
selected_urls: list[str] = []
def provider_for_url(url: str) -> StubProvider:
selected_urls.append(url)
return old_provider
cases = ScoringExecutionUseCases(
repository,
{"aihub": active_aihub_provider},
no_op,
no_op,
lambda: datetime(2026, 9, 28, tzinfo=UTC),
provider_for_url,
)
await cases.execute(run.id, "caller-vkey-should-not-reach-openai")
assert repository.result is not None and repository.result.result_mode == "hybrid"
assert selected_urls == ["http://127.0.0.1:8318"]
assert old_provider.models == ["gemini-3.5-flash-lite"] * 2
assert old_provider.keys == ["", ""]
assert active_aihub_provider.models == []