feat: auto committed

This commit is contained in:
SpecialX
2026-07-10 18:57:39 +08:00
parent c09d6fb7d2
commit 9ea81f1bd7
96 changed files with 13000 additions and 392 deletions

View File

@@ -0,0 +1,84 @@
"""共享测试 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)