141 lines
5.0 KiB
Python
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
|