Files
X-Financial/server/tests/runtime_chat_testkit.py

80 lines
2.2 KiB
Python
Raw Normal View History

from __future__ import annotations
from app.services.runtime_chat import RuntimeChatOperationContext, RuntimeChatService
from app.services.runtime_chat_attempts import RuntimeChatAttemptPermit
class RecordingAttemptObserver:
def __init__(self, timeline: list[str] | None = None) -> None:
self.permits = []
self.completed = []
self.failures = []
self.timeline = timeline
def on_permit(self, event):
self.permits.append(event)
if self.timeline is not None:
self.timeline.append(f"permit:{event.identity.attempt}")
return None
def on_completed(self, event) -> None:
self.completed.append(event)
if self.timeline is not None:
self.timeline.append(
f"completed:{event.identity.attempt}:{event.outcome}"
)
def on_observer_failure(self, failure) -> None:
self.failures.append(failure)
class FailingCompletionObserver(RecordingAttemptObserver):
def on_completed(self, event) -> None:
super().on_completed(event)
raise RuntimeError("completion observer unavailable")
class FailingPermitObserver(RecordingAttemptObserver):
def on_permit(self, event):
super().on_permit(event)
raise RuntimeError("permit observer unavailable")
class DenyingAttemptObserver(RecordingAttemptObserver):
def on_permit(self, event):
super().on_permit(event)
return RuntimeChatAttemptPermit(
allowed=False,
reason="tenant quota exhausted",
)
def build_operation_context() -> RuntimeChatOperationContext:
return RuntimeChatOperationContext(
tenant_id="tenant-runtime-chat",
operation_id="operation-runtime-chat-001",
run_id="run-runtime-chat-001",
invocation_seq=7,
attempt_scope="unit-test-completion",
)
def patch_single_slot(
monkeypatch,
service: RuntimeChatService,
*,
provider: str,
model: str,
) -> None:
monkeypatch.setattr(
service,
"_load_chat_slot",
lambda slot: {
"slot": slot,
"provider": provider,
"endpoint": "https://example.com/v1",
"model": model,
"apiKey": "secret",
},
)