Files
research-bridge/tests/unit/test_searxng_client.py

141 lines
5.0 KiB
Python

"""Unit tests for SearXNG client."""
import json
from unittest.mock import AsyncMock, Mock, patch
import httpx
import pytest
from httpx import Response
from src.models.schemas import SearchRequest
from src.search.searxng import SearXNGClient, SearXNGError
class TestSearXNGClient:
"""Test cases for SearXNGClient."""
@pytest.fixture
def client(self):
return SearXNGClient(base_url="http://test:8080")
@pytest.mark.asyncio
async def test_search_success(self, client):
"""Test successful search request."""
mock_response = {
"results": [
{
"title": "Test Result",
"url": "https://example.com",
"content": "Test content",
"engine": "google",
"score": 0.95
}
],
"number_of_results": 1,
"engines": ["google"]
}
mock_client = AsyncMock()
mock_response_obj = Mock()
mock_response_obj.status_code = 200
mock_response_obj.json = Mock(return_value=mock_response)
mock_response_obj.text = json.dumps(mock_response)
mock_response_obj.raise_for_status = Mock(return_value=None)
mock_client.get.return_value = mock_response_obj
with patch.object(client, '_client', mock_client):
request = SearchRequest(q="test query", engines=["google"], page=1)
result = await client.search(request)
assert result.query == "test query"
assert len(result.results) == 1
assert result.results[0].title == "Test Result"
assert result.results[0].source == "google"
@pytest.mark.asyncio
async def test_search_http_error(self, client):
"""Test handling of HTTP errors."""
mock_client = AsyncMock()
# Create proper HTTPStatusError with async side effect
async def raise_http_error(*args, **kwargs):
from httpx import Request, Response
mock_request = Mock(spec=Request)
mock_response = Response(status_code=404, text="Not found")
raise httpx.HTTPStatusError(
"Not found",
request=mock_request,
response=mock_response
)
mock_client.get.side_effect = raise_http_error
with patch.object(client, '_client', mock_client):
request = SearchRequest(q="test", engines=["google"], page=1)
with pytest.raises(SearXNGError) as exc_info:
await client.search(request)
assert "HTTP error" in str(exc_info.value)
@pytest.mark.asyncio
async def test_search_connection_error(self, client):
"""Test handling of connection errors."""
mock_client = AsyncMock()
mock_client.get.side_effect = httpx.ConnectError("Connection refused")
with patch.object(client, '_client', mock_client):
request = SearchRequest(q="test", engines=["google"], page=1)
with pytest.raises(SearXNGError) as exc_info:
await client.search(request)
assert "Request failed" in str(exc_info.value)
@pytest.mark.asyncio
async def test_search_invalid_json(self, client):
"""Test handling of invalid JSON response."""
mock_client = AsyncMock()
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.side_effect = json.JSONDecodeError("test", "", 0)
mock_response.text = "invalid json"
mock_response.raise_for_status = Mock(return_value=None)
mock_client.get.return_value = mock_response
with patch.object(client, '_client', mock_client):
request = SearchRequest(q="test", engines=["google"], page=1)
with pytest.raises(SearXNGError) as exc_info:
await client.search(request)
assert "Invalid JSON" in str(exc_info.value)
@pytest.mark.asyncio
async def test_health_check_success(self, client):
"""Test successful health check."""
mock_client = AsyncMock()
mock_client.get.return_value = Response(status_code=200)
with patch.object(client, '_client', mock_client):
result = await client.health_check()
assert result is True
@pytest.mark.asyncio
async def test_health_check_failure(self, client):
"""Test failed health check."""
mock_client = AsyncMock()
mock_client.get.side_effect = httpx.ConnectError("Connection refused")
with patch.object(client, '_client', mock_client):
result = await client.health_check()
assert result is False
def test_build_url(self, client):
"""Test URL building with parameters."""
params = {"q": "test query", "format": "json", "engines": "google,bing"}
url = client._build_url(params)
assert url.startswith("http://test:8080/search")
assert "q=test+query" in url or "q=test%20query" in url
assert "format=json" in url
assert "engines=google%2Cbing" in url or "engines=google,bing" in url