Files
sibilla/tests/test_ai.py
T
Sibilla f3fe13c60e Initial commit: Sibilla — self-hosted Perplexity-like AI search engine
- Flask web app with Perplexity-style search + synthesis pipeline
- Degoog → SearXNG → DuckDuckGo cascading search backends
- Gemini LLM for query expansion + answer synthesis with citations
- MCP server exposing search tools via stdio
- 57 unit tests covering all modules
2026-07-17 07:40:14 +00:00

136 lines
4.7 KiB
Python

"""Tests for sibilla.ai — GeminiClient with mocked API."""
import pytest
from unittest import mock
from sibilla.ai import GeminiClient, SynthesisResult
class TestSynthesisResult:
def test_defaults(self):
sr = SynthesisResult(answer="")
assert sr.answer == ""
assert sr.model == ""
assert sr.tokens_used == 0
assert sr.error is None
class TestGeminiClient:
def test_no_api_key_returns_error(self):
client = GeminiClient(api_key="")
result = client.synthesize("system", "user")
assert result.answer == ""
assert "GOOGLE_API_KEY" in result.error
def test_lazy_client_raises_without_key(self):
client = GeminiClient(api_key="")
with pytest.raises(ValueError, match="GOOGLE_API_KEY"):
_ = client.client
def test_synthesize_success(self):
client = GeminiClient(api_key="fake-key")
mock_genai = mock.MagicMock()
client._client = mock_genai
mock_part = mock.MagicMock()
mock_part.text = "This is the answer."
mock_content = mock.MagicMock()
mock_content.parts = [mock_part]
mock_candidate = mock.MagicMock()
mock_candidate.content = mock_content
mock_usage = mock.MagicMock()
mock_usage.total_token_count = 42
mock_response = mock.MagicMock()
mock_response.candidates = [mock_candidate]
mock_response.usage_metadata = mock_usage
mock_genai.models.generate_content.return_value = mock_response
result = client.synthesize("system prompt", "user query")
assert result.answer == "This is the answer."
assert result.tokens_used == 42
assert result.model == "gemini-2.5-flash"
assert result.error is None
def test_synthesize_no_candidates(self):
client = GeminiClient(api_key="fake-key")
mock_genai = mock.MagicMock()
client._client = mock_genai
mock_response = mock.MagicMock()
mock_response.candidates = []
mock_response.usage_metadata = None
mock_genai.models.generate_content.return_value = mock_response
result = client.synthesize("s", "u")
assert result.answer == ""
assert result.error is None
def test_synthesize_api_exception(self):
client = GeminiClient(api_key="fake-key")
mock_genai = mock.MagicMock()
client._client = mock_genai
mock_genai.models.generate_content.side_effect = RuntimeError("API down")
result = client.synthesize("s", "u")
assert result.error == "API down"
assert result.answer == ""
def test_rewrite_query_no_api_key(self):
client = GeminiClient(api_key="")
variants = client.rewrite_query("test query", num_variants=3)
assert variants == ["test query"]
def test_rewrite_query_success(self):
client = GeminiClient(api_key="fake-key")
mock_genai = mock.MagicMock()
client._client = mock_genai
mock_part = mock.MagicMock()
mock_part.text = "rewritten query 1\nrewritten query 2\nrewritten query 3"
mock_content = mock.MagicMock()
mock_content.parts = [mock_part]
mock_candidate = mock.MagicMock()
mock_candidate.content = mock_content
mock_response = mock.MagicMock()
mock_response.candidates = [mock_candidate]
mock_genai.models.generate_content.return_value = mock_response
variants = client.rewrite_query("original", num_variants=3)
assert len(variants) == 4
assert variants[0] == "original"
assert "rewritten query 1" in variants
def test_rewrite_query_strips_bullets(self):
client = GeminiClient(api_key="fake-key")
mock_genai = mock.MagicMock()
client._client = mock_genai
mock_part = mock.MagicMock()
mock_part.text = "- bullet query\n• dot query"
mock_content = mock.MagicMock()
mock_content.parts = [mock_part]
mock_candidate = mock.MagicMock()
mock_candidate.content = mock_content
mock_response = mock.MagicMock()
mock_response.candidates = [mock_candidate]
mock_genai.models.generate_content.return_value = mock_response
variants = client.rewrite_query("original", num_variants=2)
assert "bullet query" in variants
assert "dot query" in variants
assert not any(v.startswith("-") for v in variants)
def test_rewrite_query_exception_fallback(self):
client = GeminiClient(api_key="fake-key")
mock_genai = mock.MagicMock()
client._client = mock_genai
mock_genai.models.generate_content.side_effect = RuntimeError("boom")
variants = client.rewrite_query("original", num_variants=2)
assert variants == ["original"]