Fix research pipeline provider failures
This commit is contained in:
107
tests/test_backend_pipeline_repairs.py
Normal file
107
tests/test_backend_pipeline_repairs.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""Regression tests for the deployed backend research pipeline fixes."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from uuid import uuid4
|
||||
|
||||
import httpx
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from nsct.config import AppSettings, AudioConfig, DatabaseConfig, LLMConfig, VisionConfig
|
||||
from nsct.orchestration.orchestrator import ResearchOrchestrator
|
||||
from nsct.orchestration.state import ResearchRunState
|
||||
from nsct.providers.llm import _LLMProviderImpl
|
||||
from nsct.providers.metrics import ProviderMetrics
|
||||
from nsct.providers.searxng import SearXNGProvider
|
||||
|
||||
|
||||
def _config(*, searxng_base_url: str | None = "http://searxng:8080") -> AppSettings:
|
||||
return AppSettings(
|
||||
llm=LLMConfig(base_url="http://llm.example/v1", model="test-model"),
|
||||
vision=VisionConfig(base_url="http://vision.example/v1", model="vision"),
|
||||
audio=AudioConfig(base_url="http://audio.example/v1"),
|
||||
postgres=DatabaseConfig(url="sqlite+aiosqlite://"),
|
||||
searxng_base_url=searxng_base_url,
|
||||
)
|
||||
|
||||
|
||||
def test_llm_base_url_does_not_duplicate_existing_v1() -> None:
|
||||
provider = _LLMProviderImpl(_config(), ProviderMetrics())
|
||||
provider._api_key = "test-key"
|
||||
client = provider._create_client()
|
||||
try:
|
||||
assert str(client.base_url) == "http://llm.example/v1/"
|
||||
finally:
|
||||
asyncio.run(client.close())
|
||||
|
||||
|
||||
def test_searxng_provider_normalizes_json_results() -> None:
|
||||
async def run() -> None:
|
||||
provider = SearXNGProvider("http://searxng:8080")
|
||||
provider._client = httpx.AsyncClient(
|
||||
transport=httpx.MockTransport(
|
||||
lambda request: httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"results": [
|
||||
{"url": "https://example.org/a", "title": "A", "content": "Snippet"},
|
||||
{"url": "mailto:invalid@example.org", "title": "Invalid"},
|
||||
]
|
||||
},
|
||||
)
|
||||
)
|
||||
)
|
||||
try:
|
||||
results = await provider.search("test")
|
||||
assert len(results) == 1
|
||||
assert results[0].provider == "searxng"
|
||||
assert results[0].url == "https://example.org/a"
|
||||
assert results[0].snippet == "Snippet"
|
||||
assert provider._client is not None
|
||||
finally:
|
||||
await provider._client.aclose()
|
||||
|
||||
asyncio.run(run())
|
||||
|
||||
|
||||
def test_orchestrator_registers_searxng_provider() -> None:
|
||||
orchestrator = ResearchOrchestrator(_config(), uuid4(), "test")
|
||||
provider = orchestrator._get_multi_search().get_provider("searxng")
|
||||
assert isinstance(provider, SearXNGProvider)
|
||||
|
||||
|
||||
def test_pipeline_executes_extracting_between_fetching_and_analyzing() -> None:
|
||||
async def run() -> None:
|
||||
orchestrator = ResearchOrchestrator(_config(), uuid4(), "test")
|
||||
orchestrator._comparison_data = {}
|
||||
for step in ("planning", "searching", "fetching", "extracting", "analyzing", "comparing", "synthesizing"):
|
||||
async def handler(target: str = step) -> dict[str, object]:
|
||||
orchestrator._transition_to(target)
|
||||
return {"success": True, "data": {}}
|
||||
|
||||
setattr(orchestrator, f"_step_{step}", AsyncMock(side_effect=handler))
|
||||
|
||||
result = await orchestrator.run()
|
||||
|
||||
assert result["success"] is True
|
||||
assert orchestrator._step_extracting.await_count == 1
|
||||
assert orchestrator.state is ResearchRunState.COMPLETED
|
||||
|
||||
asyncio.run(run())
|
||||
|
||||
|
||||
def test_no_search_provider_marks_run_failed_with_reason() -> None:
|
||||
async def run() -> None:
|
||||
orchestrator = ResearchOrchestrator(_config(searxng_base_url=None), uuid4(), "test")
|
||||
await orchestrator.start()
|
||||
orchestrator._step_planning = AsyncMock(return_value={"success": True, "data": {}})
|
||||
|
||||
result = await orchestrator.run()
|
||||
|
||||
assert result["success"] is False
|
||||
assert result["failed_step"] == "searching"
|
||||
assert "No search provider" in result["error"]
|
||||
assert orchestrator.state is ResearchRunState.FAILED
|
||||
|
||||
asyncio.run(run())
|
||||
Reference in New Issue
Block a user