Files
llm-connect/tests/test_factory.py
Bernd Worsch d71f4114d1 feat: WP-0001 foundation + WP-0002 core extensions
WP-0001 — Foundation & GAAF Baseline
- SCOPE.md, ARCHITECTURE-LAYERS.md, contracts/ tree
- .claude/rules/ stubs filled (architecture, stack, boundary)
- 57 tests (pytest), pyproject.toml with ruff+mypy, CI workflow

WP-0002 — Core Extensions (FR-4 + FR-3)
- FR-4: BudgetTracker (thread-safe) + LLMBudgetExceededError +
  optional RunConfig.budget_tracker + enforcement in all adapters
- FR-3: async_execute_prompt on LLMAdapter ABC (asyncio.to_thread
  fallback) + native asyncio.create_subprocess_exec in ClaudeCodeAdapter

81 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 22:24:14 +00:00

98 lines
4.1 KiB
Python

"""
Tests for create_adapter() and create_embedding_adapter() factories.
"""
import pytest
from llm_connect.factory import create_adapter
from llm_connect.embedding_factory import create_embedding_adapter
from llm_connect.exceptions import LLMConfigurationError
from llm_connect.adapter import LLMAdapter
from llm_connect.embedding_adapter import EmbeddingAdapter
from llm_connect.openrouter import OpenRouterAdapter
from llm_connect.claude_code import ClaudeCodeAdapter
from llm_connect.openai import OpenAIAdapter
from llm_connect.gemini import GeminiAdapter
from llm_connect.embedding_openai import OpenAICompatibleEmbeddingAdapter
class TestCreateAdapter:
def test_unknown_provider_raises(self):
with pytest.raises(LLMConfigurationError, match="Unknown LLM provider"):
create_adapter("nonexistent-provider")
def test_unknown_provider_error_lists_known(self):
with pytest.raises(LLMConfigurationError) as exc_info:
create_adapter("bad")
assert "openai" in str(exc_info.value)
assert "gemini" in str(exc_info.value)
def test_openrouter_returns_adapter(self):
adapter = create_adapter("openrouter", api_key="test-key")
assert isinstance(adapter, OpenRouterAdapter)
assert isinstance(adapter, LLMAdapter)
def test_openrouter_no_key_still_constructs(self):
# OpenRouterAdapter defers key validation to execute_prompt
adapter = create_adapter("openrouter")
assert isinstance(adapter, OpenRouterAdapter)
def test_openai_with_key_returns_adapter(self):
adapter = create_adapter("openai", api_key="sk-test-key")
assert isinstance(adapter, OpenAIAdapter)
assert isinstance(adapter, LLMAdapter)
def test_openai_without_key_raises(self, monkeypatch):
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
with pytest.raises(LLMConfigurationError):
create_adapter("openai")
def test_gemini_with_key_returns_adapter(self):
adapter = create_adapter("gemini", api_key="aistudio-test-key")
assert isinstance(adapter, GeminiAdapter)
assert isinstance(adapter, LLMAdapter)
def test_gemini_without_key_raises(self, monkeypatch):
monkeypatch.delenv("GEMINI_API_KEY", raising=False)
with pytest.raises(LLMConfigurationError):
create_adapter("gemini")
def test_claude_code_returns_adapter(self):
adapter = create_adapter("claude-code")
assert isinstance(adapter, ClaudeCodeAdapter)
assert isinstance(adapter, LLMAdapter)
def test_claude_code_with_model(self):
adapter = create_adapter("claude-code", model="claude-opus-4-6")
assert isinstance(adapter, ClaudeCodeAdapter)
def test_all_known_providers_are_reachable(self):
known = {"openrouter", "openai", "gemini", "claude-code"}
# Just verify each key is in the factory registry (no construction needed)
from llm_connect.factory import _PROVIDERS
assert known == set(_PROVIDERS.keys())
class TestCreateEmbeddingAdapter:
def test_unknown_provider_raises(self):
with pytest.raises(LLMConfigurationError, match="Unknown embedding provider"):
create_embedding_adapter("nonexistent")
def test_openai_returns_adapter(self):
adapter = create_embedding_adapter("openai", api_key="sk-test")
assert isinstance(adapter, OpenAICompatibleEmbeddingAdapter)
assert isinstance(adapter, EmbeddingAdapter)
def test_openrouter_returns_adapter(self):
adapter = create_embedding_adapter("openrouter", api_key="or-test")
assert isinstance(adapter, OpenAICompatibleEmbeddingAdapter)
assert isinstance(adapter, EmbeddingAdapter)
def test_validate_returns_true_when_key_set(self):
adapter = create_embedding_adapter("openai", api_key="sk-test")
assert adapter.validate() is True
def test_validate_returns_false_when_no_key(self, monkeypatch):
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
adapter = create_embedding_adapter("openai")
assert adapter.validate() is False