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
399 lines
14 KiB
Python
399 lines
14 KiB
Python
"""
|
|
Enhanced search engine tests using scottvr's patterns.
|
|
|
|
This demonstrates how to use the new mock utilities and fixtures.
|
|
"""
|
|
|
|
import os
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from tests.test_utils import (
|
|
add_src_to_path,
|
|
assert_search_result_format,
|
|
mock_api_response,
|
|
)
|
|
|
|
# Add src to path
|
|
add_src_to_path()
|
|
|
|
import local_deep_research.metrics.search_tracker as search_tracker_module # noqa: E402
|
|
|
|
# Mock the search tracker for all tests in this module
|
|
mock_tracker = MagicMock()
|
|
mock_tracker.record_search = MagicMock()
|
|
search_tracker_module.get_search_tracker = MagicMock(return_value=mock_tracker)
|
|
|
|
|
|
class TestWikipediaSearchEnhanced:
|
|
"""Enhanced Wikipedia search tests using new patterns."""
|
|
|
|
def test_wikipedia_search_success(
|
|
self, monkeypatch, mock_wikipedia_response
|
|
):
|
|
"""Test successful Wikipedia search."""
|
|
# Mock the wikipedia library functions directly instead of requests.get
|
|
mock_search_results = ["Artificial intelligence", "Machine learning"]
|
|
monkeypatch.setattr(
|
|
"wikipedia.search", lambda query, results=10: mock_search_results
|
|
)
|
|
|
|
def mock_summary(title, sentences=3, auto_suggest=True):
|
|
if title == "Artificial intelligence":
|
|
return "Artificial intelligence (AI) is intelligence demonstrated by machines, in contrast to natural intelligence."
|
|
if title == "Machine learning":
|
|
return "Machine learning (ML) is a subset of artificial intelligence that focuses on algorithms."
|
|
return "Generic summary"
|
|
|
|
monkeypatch.setattr("wikipedia.summary", mock_summary)
|
|
|
|
# Import and test
|
|
from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
|
|
WikipediaSearchEngine,
|
|
)
|
|
|
|
search = WikipediaSearchEngine(max_results=5)
|
|
results = search.run("artificial intelligence")
|
|
|
|
# Verify results
|
|
assert len(results) == 2
|
|
for result in results:
|
|
assert_search_result_format(result)
|
|
|
|
# Check specific content
|
|
assert results[0]["title"] == "Artificial intelligence"
|
|
assert "intelligence demonstrated by machines" in results[0]["snippet"]
|
|
assert results[0]["source"] == "Wikipedia"
|
|
|
|
def test_wikipedia_search_error_handling(self, monkeypatch):
|
|
"""Test Wikipedia search error handling."""
|
|
|
|
# Mock wikipedia.search to raise an exception
|
|
def mock_search_error(*args, **kwargs):
|
|
raise Exception("Search failed")
|
|
|
|
monkeypatch.setattr("wikipedia.search", mock_search_error)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
|
|
WikipediaSearchEngine,
|
|
)
|
|
|
|
search = WikipediaSearchEngine()
|
|
results = search.run("test query")
|
|
|
|
# Should return empty list on error
|
|
assert isinstance(results, list)
|
|
assert len(results) == 0
|
|
|
|
def test_wikipedia_search_network_error(self, monkeypatch):
|
|
"""Test Wikipedia search with network errors."""
|
|
|
|
# Mock a network exception on wikipedia.search
|
|
def mock_network_error(*args, **kwargs):
|
|
raise ConnectionError("Network error")
|
|
|
|
monkeypatch.setattr("wikipedia.search", mock_network_error)
|
|
monkeypatch.setattr("wikipedia.set_lang", lambda x: None)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
|
|
WikipediaSearchEngine,
|
|
)
|
|
|
|
search = WikipediaSearchEngine()
|
|
results = search.run("test query")
|
|
|
|
# Should handle exception gracefully
|
|
assert isinstance(results, list)
|
|
assert len(results) == 0
|
|
|
|
|
|
class TestArxivSearchEnhanced:
|
|
"""Enhanced arXiv search tests."""
|
|
|
|
def test_arxiv_search_success(self, monkeypatch, mock_arxiv_response):
|
|
"""Test successful arXiv search."""
|
|
|
|
# Mock search_config to ensure searxng is available - patch multiple locations
|
|
def mock_search_config():
|
|
return {
|
|
"searxng": {
|
|
"module_path": ".engines.search_engine_searxng",
|
|
"class_name": "SearXNGSearchEngine",
|
|
"default_params": {"host_url": "http://localhost:8080"},
|
|
}
|
|
}
|
|
|
|
# Patch multiple potential import locations
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.search_engines_config.search_config",
|
|
mock_search_config,
|
|
)
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.search_engines_config.search_config",
|
|
mock_search_config,
|
|
)
|
|
|
|
# Also mock the search engine factory create function to avoid the KeyError entirely
|
|
def mock_create_search_engine(engine_name, **kwargs):
|
|
from unittest.mock import Mock
|
|
|
|
mock_engine = Mock()
|
|
mock_engine.is_available = True
|
|
mock_engine.run.return_value = []
|
|
return mock_engine
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.search_engine_factory.create_search_engine",
|
|
mock_create_search_engine,
|
|
)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
|
|
ArXivSearchEngine,
|
|
)
|
|
|
|
# Mock the _get_search_results method to return empty list to avoid actual arXiv API calls
|
|
def mock_get_search_results(self, query):
|
|
from unittest.mock import Mock
|
|
|
|
# Create a mock paper object
|
|
mock_paper = Mock()
|
|
mock_paper.entry_id = "2301.12345"
|
|
mock_paper.title = "Test Machine Learning Paper"
|
|
mock_paper.summary = (
|
|
"This is a test abstract about machine learning."
|
|
)
|
|
mock_paper.authors = [
|
|
Mock(name="John Doe"),
|
|
Mock(name="Jane Smith"),
|
|
]
|
|
mock_paper.published = None
|
|
mock_paper.journal_ref = None
|
|
return [mock_paper]
|
|
|
|
monkeypatch.setattr(
|
|
ArXivSearchEngine, "_get_search_results", mock_get_search_results
|
|
)
|
|
|
|
# Mock JournalReputationFilter.create_default to return None
|
|
# This avoids the need for LLM initialization
|
|
monkeypatch.setattr(
|
|
"local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
|
|
lambda *args, **kwargs: None,
|
|
)
|
|
|
|
search = ArXivSearchEngine(max_results=5)
|
|
results = search.run("machine learning")
|
|
|
|
# Verify results
|
|
assert len(results) >= 1
|
|
if results: # ArxivSearch might return empty if XML parsing fails
|
|
for result in results:
|
|
assert_search_result_format(result)
|
|
assert results[0]["source"] == "arXiv"
|
|
|
|
|
|
class TestSearchEngineFactory:
|
|
"""Test search engine factory with mocked configs."""
|
|
|
|
@pytest.mark.skipif(
|
|
os.getenv("CI") == "true", reason="Skipping in CI due to timeout issues"
|
|
)
|
|
def test_factory_with_mocked_llm(self, monkeypatch):
|
|
"""Test search engine factory with mocked LLM config."""
|
|
# Import the mock utilities
|
|
from tests.mock_modules import (
|
|
create_mock_db_utils,
|
|
create_mock_llm_config,
|
|
)
|
|
|
|
# Create mock LLM config
|
|
create_mock_llm_config(monkeypatch)
|
|
|
|
# Mock database utilities with search engine configurations
|
|
search_engine_config = {
|
|
"search.engine.web": {
|
|
"wikipedia": {
|
|
"module_path": "local_deep_research.web_search_engines.engines.search_engine_wikipedia",
|
|
"class_name": "WikipediaSearchEngine",
|
|
"requires_api_key": False,
|
|
"requires_llm": False,
|
|
"default_params": {"max_results": 10},
|
|
}
|
|
},
|
|
"search.engine.DEFAULT_SEARCH_ENGINE": "wikipedia",
|
|
"search.max_results": 10,
|
|
"search.engine.local": {},
|
|
}
|
|
create_mock_db_utils(monkeypatch, search_engine_config)
|
|
|
|
# Mock db_utils to avoid database access
|
|
from tests.mock_modules import create_mock_db_utils
|
|
|
|
create_mock_db_utils(monkeypatch)
|
|
|
|
# Mock search_engines_config to avoid circular imports
|
|
def mock_search_config():
|
|
return {
|
|
"wikipedia": {
|
|
"module_path": ".engines.search_engine_wikipedia",
|
|
"class_name": "WikipediaSearchEngine",
|
|
"default_params": {"max_results": 10},
|
|
"requires_api_key": False,
|
|
"requires_llm": False,
|
|
}
|
|
}
|
|
|
|
def mock_default_search_engine():
|
|
return "wikipedia"
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.search_engines_config.search_config",
|
|
mock_search_config,
|
|
)
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.search_engines_config.default_search_engine",
|
|
mock_default_search_engine,
|
|
)
|
|
|
|
# Mock wikipedia library
|
|
monkeypatch.setattr("wikipedia.set_lang", lambda *args, **kwargs: None)
|
|
monkeypatch.setattr(
|
|
"wikipedia.search", lambda query, results: ["Test Result"]
|
|
)
|
|
monkeypatch.setattr(
|
|
"wikipedia.summary",
|
|
lambda title, sentences=5, auto_suggest=False: "Test summary",
|
|
)
|
|
|
|
# Test factory
|
|
from local_deep_research.web_search_engines.search_engine_factory import (
|
|
create_search_engine,
|
|
)
|
|
|
|
# Create a minimal settings snapshot for the factory
|
|
settings_snapshot = {
|
|
"search.engine.web.wikipedia.module_path": {
|
|
"value": "local_deep_research.web_search_engines.engines"
|
|
".search_engine_wikipedia",
|
|
"ui_element": "text",
|
|
},
|
|
"search.engine.web.wikipedia.class_name": {
|
|
"value": "WikipediaSearchEngine",
|
|
"ui_element": "text",
|
|
},
|
|
"search.engine.web.wikipedia.requires_api_key": {
|
|
"value": False,
|
|
"ui_element": "checkbox",
|
|
},
|
|
"search.engine.web.wikipedia.requires_llm": {
|
|
"value": False,
|
|
"ui_element": "checkbox",
|
|
},
|
|
"search.engine.web.wikipedia.default_params.max_results": {
|
|
"value": 10,
|
|
"ui_element": "number",
|
|
},
|
|
}
|
|
|
|
# Should work even with mocked modules
|
|
engine = create_search_engine(
|
|
"wikipedia", settings_snapshot=settings_snapshot
|
|
)
|
|
assert engine is not None
|
|
|
|
# Test search
|
|
results = engine.run("test")
|
|
assert isinstance(results, list)
|
|
|
|
|
|
class TestMultipleSearchEngines:
|
|
"""Test multiple search engines with shared fixtures."""
|
|
|
|
@pytest.mark.parametrize(
|
|
"engine_name,response_fixture",
|
|
[
|
|
("wikipedia", "mock_wikipedia_response"),
|
|
("google_pse", "mock_google_pse_response"),
|
|
("semantic_scholar", "mock_semantic_scholar_response"),
|
|
],
|
|
)
|
|
def test_search_engines(
|
|
self, engine_name, response_fixture, request, monkeypatch
|
|
):
|
|
"""Test multiple search engines with parametrized fixtures."""
|
|
# Get the fixture value dynamically
|
|
mock_response_data = request.getfixturevalue(response_fixture)
|
|
|
|
# Mock the API response based on engine type
|
|
if engine_name == "wikipedia":
|
|
# Mock wikipedia library functions directly
|
|
mock_search_results = [
|
|
"Artificial intelligence",
|
|
"Machine learning",
|
|
]
|
|
monkeypatch.setattr(
|
|
"wikipedia.search",
|
|
lambda query, results=10: mock_search_results,
|
|
)
|
|
|
|
def mock_summary(title, sentences=3, auto_suggest=True):
|
|
if title == "Artificial intelligence":
|
|
return "Artificial intelligence (AI) is intelligence demonstrated by machines."
|
|
if title == "Machine learning":
|
|
return "Machine learning (ML) is a subset of artificial intelligence."
|
|
return "Generic summary"
|
|
|
|
monkeypatch.setattr("wikipedia.summary", mock_summary)
|
|
else:
|
|
# For other engines, use requests.get mocking
|
|
if engine_name == "google_pse" or engine_name == "semantic_scholar":
|
|
mock_response = mock_api_response(
|
|
200, json_data=mock_response_data
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
"requests.get", lambda *args, **kwargs: mock_response
|
|
)
|
|
|
|
# Import the appropriate search engine
|
|
if engine_name == "wikipedia":
|
|
from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
|
|
WikipediaSearchEngine as SearchEngine,
|
|
)
|
|
elif engine_name == "google_pse":
|
|
# Mock settings snapshot for Google PSE
|
|
def mock_get_setting_from_snapshot(
|
|
key, default=None, settings_snapshot=None
|
|
):
|
|
if "api_key" in key:
|
|
return "test_api_key"
|
|
if "engine_id" in key:
|
|
return "test_engine_id"
|
|
return default
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.config.thread_settings.get_setting_from_snapshot",
|
|
mock_get_setting_from_snapshot,
|
|
)
|
|
# Also set environment variables as fallback
|
|
monkeypatch.setenv("GOOGLE_PSE_API_KEY", "test_api_key")
|
|
monkeypatch.setenv("GOOGLE_PSE_ENGINE_ID", "test_engine_id")
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine as SearchEngine,
|
|
)
|
|
elif engine_name == "semantic_scholar":
|
|
from local_deep_research.web_search_engines.engines.search_engine_semantic_scholar import (
|
|
SemanticScholarSearchEngine as SearchEngine,
|
|
)
|
|
|
|
# Test the search
|
|
search = SearchEngine()
|
|
results = search.run("test query")
|
|
|
|
# Basic validation
|
|
assert isinstance(results, list)
|
|
if results: # Some engines might return empty on mock data
|
|
for result in results:
|
|
assert_search_result_format(result)
|