Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

204 lines
5.2 KiB
Python

"""Tests for the LLM registry module."""
import pytest
from langchain_core.language_models import BaseChatModel
from langchain_core.messages import AIMessage
from langchain_core.outputs import ChatGeneration, ChatResult
from local_deep_research.llm import (
clear_llm_registry,
get_llm_from_registry,
is_llm_registered,
list_registered_llms,
register_llm,
unregister_llm,
)
class MockLLM(BaseChatModel):
"""Mock LLM for testing."""
name: str = "mock"
def _generate(self, messages, **kwargs):
"""Generate mock response."""
message = AIMessage(content=f"Mock response from {self.name}")
generation = ChatGeneration(message=message)
return ChatResult(generations=[generation])
@property
def _llm_type(self):
return "mock"
@pytest.fixture(autouse=True)
def clear_registry():
"""Clear the registry before and after each test."""
clear_llm_registry()
yield
clear_llm_registry()
def test_register_llm_instance():
"""Test registering an LLM instance."""
llm = MockLLM(name="test-llm")
# Register the LLM
register_llm("test_model", llm)
# Check it's registered
assert is_llm_registered("test_model")
assert "test_model" in list_registered_llms()
# Retrieve it
retrieved = get_llm_from_registry("test_model")
assert retrieved is llm
def test_register_llm_factory():
"""Test registering an LLM factory function."""
def create_llm(**kwargs):
return MockLLM(name="factory-llm", **kwargs)
# Register the factory
register_llm("factory_model", create_llm)
# Check it's registered
assert is_llm_registered("factory_model")
# Retrieve the factory
factory = get_llm_from_registry("factory_model")
assert callable(factory)
# Create an LLM from the factory
llm = factory()
assert isinstance(llm, MockLLM)
assert llm.name == "factory-llm"
def test_unregister_llm():
"""Test unregistering an LLM."""
llm = MockLLM()
register_llm("temp_model", llm)
# Verify it's registered
assert is_llm_registered("temp_model")
# Unregister it
unregister_llm("temp_model")
# Verify it's gone
assert not is_llm_registered("temp_model")
assert "temp_model" not in list_registered_llms()
assert get_llm_from_registry("temp_model") is None
def test_multiple_llms():
"""Test registering multiple LLMs."""
llm1 = MockLLM(name="llm1")
llm2 = MockLLM(name="llm2")
register_llm("model1", llm1)
register_llm("model2", llm2)
# Check both are registered
registered = list_registered_llms()
assert len(registered) == 2
assert "model1" in registered
assert "model2" in registered
# Retrieve them
assert get_llm_from_registry("model1") is llm1
assert get_llm_from_registry("model2") is llm2
def test_overwrite_existing():
"""Test overwriting an existing LLM."""
llm1 = MockLLM(name="original")
llm2 = MockLLM(name="replacement")
# Register first LLM
register_llm("model", llm1)
assert get_llm_from_registry("model") is llm1
# Overwrite with second LLM
register_llm("model", llm2)
assert get_llm_from_registry("model") is llm2
def test_clear_registry():
"""Test clearing all registered LLMs."""
# Register multiple LLMs
register_llm("model1", MockLLM())
register_llm("model2", MockLLM())
register_llm("model3", MockLLM())
assert len(list_registered_llms()) == 3
# Clear the registry
clear_llm_registry()
# Verify all are gone
assert len(list_registered_llms()) == 0
assert not is_llm_registered("model1")
assert not is_llm_registered("model2")
assert not is_llm_registered("model3")
def test_thread_safety():
"""Test that registry operations are thread-safe."""
import threading
import time
results = []
errors = []
def register_many():
"""Register many LLMs in a thread."""
try:
for i in range(100):
register_llm(f"thread_model_{i}", MockLLM(name=f"thread-{i}"))
results.append("register_complete")
except Exception as e:
errors.append(e)
def read_many():
"""Read from registry in a thread."""
try:
for _ in range(100):
_ = list_registered_llms()
time.sleep(0.001) # Small delay to increase contention
results.append("read_complete")
except Exception as e:
errors.append(e)
# Start multiple threads
threads = []
for _ in range(3):
threads.append(threading.Thread(target=register_many))
threads.append(threading.Thread(target=read_many))
for t in threads:
t.start()
for t in threads:
t.join()
# Check no errors occurred
assert len(errors) == 0
assert len(results) == 6 # 3 register + 3 read threads
def test_get_nonexistent():
"""Test getting a non-existent LLM."""
assert get_llm_from_registry("does_not_exist") is None
assert not is_llm_registered("does_not_exist")
def test_empty_registry():
"""Test operations on empty registry."""
assert list_registered_llms() == []
assert not is_llm_registered("any_model")
assert get_llm_from_registry("any_model") is None