Files
Edu/services/ai/tests/conftest.py
2026-07-10 18:57:39 +08:00

85 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""共享测试 fixtures."""
from collections.abc import AsyncGenerator
from typing import Any
import pytest
from src.ai.errors import AILLMUnavailableError
from src.ai.providers import LLMProvider, LLMResponse, LLMStreamChunk
class MockProvider(LLMProvider):
"""可控的 LLM Provider mock用于测试 FailoverChain + Service."""
def __init__(
self,
name: str = "mock",
available: bool = True,
response_content: str = "mock response",
fail: bool = False,
stream_chunks: list[str] | None = None,
) -> None:
self._name = name
self._available = available
self._response_content = response_content
self._fail = fail
self._stream_chunks = stream_chunks or ["hello", " world"]
@property
def name(self) -> str:
return self._name
def is_available(self) -> bool:
return self._available
async def chat(
self,
messages: list[dict[str, str]],
model: str,
temperature: float = 0.7,
**kwargs: Any,
) -> LLMResponse:
if self._fail:
raise AILLMUnavailableError(f"{self._name} mock failure")
return LLMResponse(
content=self._response_content,
model=model,
usage={"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30},
provider=self._name,
)
async def stream_chat(
self,
messages: list[dict[str, str]],
model: str,
temperature: float = 0.7,
**kwargs: Any,
) -> AsyncGenerator[LLMStreamChunk, None]:
if self._fail:
raise AILLMUnavailableError(f"{self._name} mock stream failure")
for i, chunk in enumerate(self._stream_chunks):
finish = "stop" if i == len(self._stream_chunks) - 1 else None
yield LLMStreamChunk(
delta=chunk, model=model,
finish_reason=finish, provider=self._name,
)
@pytest.fixture
def mock_provider() -> MockProvider:
"""默认可用的 mock provider."""
return MockProvider()
@pytest.fixture
def failing_provider() -> MockProvider:
"""总是失败的 mock provider."""
return MockProvider(name="failing", fail=True)
@pytest.fixture
def unavailable_provider() -> MockProvider:
"""未配置的 mock provider."""
return MockProvider(name="unconfigured", available=False)