Files
wehub-resource-sync 7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

309 lines
10 KiB
Python

import sys
from pathlib import Path
from unittest.mock import Mock
import pytest
# Handle import paths for testing
sys.path.append(str(Path(__file__).parent.parent))
@pytest.fixture
def mock_search():
"""Create a mock search engine for testing."""
mock = Mock()
mock.run.return_value = [
{
"title": "Mocked Search Result",
"link": "https://example.com/mocked",
"snippet": "This is a mocked search result snippet.",
}
]
return mock
@pytest.fixture
def mock_strategy():
"""Create a mock search strategy for testing."""
mock = Mock()
mock.analyze_topic.return_value = {
"findings": [{"content": "Test finding"}],
"current_knowledge": "Test knowledge summary",
"iterations": 1,
"questions_by_iteration": {1: ["Question 1?", "Question 2?"]},
}
return mock
@pytest.mark.requires_llm
def test_progress_callback_forwarding(monkeypatch, mock_search, mock_llm):
"""Test that progress callbacks are properly forwarded to the strategy."""
# Create a mock strategy class and instance
mock_strategy_class = Mock()
mock_strategy_instance = Mock()
mock_strategy_class.return_value = mock_strategy_instance
# Mock SourceBasedSearchStrategy which is the default
monkeypatch.setattr(
"local_deep_research.search_system.SourceBasedSearchStrategy",
mock_strategy_class,
)
# Mock get_llm and get_search from their actual modules
monkeypatch.setattr(
"local_deep_research.config.llm_config.get_llm",
lambda **kwargs: mock_llm,
)
monkeypatch.setattr(
"local_deep_research.config.search_config.get_search",
lambda llm_instance=None, **kwargs: mock_search,
)
# Import after mocking
from local_deep_research.search_system import AdvancedSearchSystem
# Create the search system (will use default source-based strategy)
system = AdvancedSearchSystem(llm=mock_llm, search=mock_search)
# Create a mock progress callback
mock_callback = Mock()
# Set the callback
system.set_progress_callback(mock_callback)
# Internal _progress_callback should call the user-provided callback
system._progress_callback("Test message", 50, {"test": "metadata"})
# Verify callback was called with correct parameters
mock_callback.assert_called_once_with(
"Test message", 50, {"test": "metadata"}
)
def test_init_source_based_strategy(monkeypatch):
"""Test initialization with source-based strategy (the current default)."""
# Set up mock LLM and search
mock_llm_instance = Mock()
mock_search_instance = Mock()
# Mock get_llm and get_search from their actual modules
monkeypatch.setattr(
"local_deep_research.config.llm_config.get_llm",
lambda **kwargs: mock_llm_instance,
)
monkeypatch.setattr(
"local_deep_research.config.search_config.get_search",
lambda llm_instance=None, **kwargs: mock_search_instance,
)
# Import after mocking
from local_deep_research.search_system import AdvancedSearchSystem
# Create settings snapshot for the test
settings_snapshot = {
"search.cross_engine_max_results": {"value": 100, "type": "int"},
"search.cross_engine_use_reddit": {"value": False, "type": "bool"},
"search.cross_engine_min_date": {"value": None, "type": "str"},
"search.iterations": {"value": 2, "type": "int"},
"search.questions_per_iteration": {"value": 3, "type": "int"},
}
# Create with default strategy (source-based)
system = AdvancedSearchSystem(
llm=mock_llm_instance,
search=mock_search_instance,
settings_snapshot=settings_snapshot,
)
# Check if the correct strategy type was created
assert "SourceBasedSearchStrategy" in system.strategy.__class__.__name__
# Also test explicit source-based strategy
system_explicit = AdvancedSearchSystem(
llm=mock_llm_instance,
search=mock_search_instance,
strategy_name="source-based",
settings_snapshot=settings_snapshot,
)
assert (
"SourceBasedSearchStrategy"
in system_explicit.strategy.__class__.__name__
)
def test_init_invalid_strategy(monkeypatch):
"""Test initialization with invalid strategy (should default to source-based)."""
# Set up mock LLM and search
# audit: PUNCHLIST reviewed 2026-05 — issue resolved by prior PR (recommendation: delete).
mock_llm_instance = Mock()
mock_search_instance = Mock()
# Mock get_llm and get_search from their actual modules
monkeypatch.setattr(
"local_deep_research.config.llm_config.get_llm",
lambda **kwargs: mock_llm_instance,
)
monkeypatch.setattr(
"local_deep_research.config.search_config.get_search",
lambda llm_instance=None, **kwargs: mock_search_instance,
)
# Import after mocking
# Create with invalid strategy name (will fall through to default)
# Since StandardStrategy is imported lazily, it won't be available and
# the system will use whatever is the actual default implementation
# Skip this test for now as it requires complex mocking of the lazy import
pytest.skip(
"Skipping test for invalid strategy as StandardStrategy is deprecated"
)
def test_set_progress_callback(monkeypatch):
"""Test setting progress callback."""
# Set up mock LLM and search
mock_llm_instance = Mock()
mock_search_instance = Mock()
# Mock get_llm and get_search from their actual modules
monkeypatch.setattr(
"local_deep_research.config.llm_config.get_llm",
lambda **kwargs: mock_llm_instance,
)
monkeypatch.setattr(
"local_deep_research.config.search_config.get_search",
lambda llm_instance=None, **kwargs: mock_search_instance,
)
# Import after mocking
from local_deep_research.search_system import AdvancedSearchSystem
# Create settings snapshot for the test
settings_snapshot = {
"search.cross_engine_max_results": {"value": 100, "type": "int"},
"search.cross_engine_use_reddit": {"value": False, "type": "bool"},
"search.cross_engine_min_date": {"value": None, "type": "str"},
"search.iterations": {"value": 2, "type": "int"},
"search.questions_per_iteration": {"value": 3, "type": "int"},
}
system = AdvancedSearchSystem(
llm=mock_llm_instance,
search=mock_search_instance,
settings_snapshot=settings_snapshot,
)
# Create a mock callback
mock_callback = Mock()
# Set the callback
system.set_progress_callback(mock_callback)
# Verify callback was set on the search system
assert system.progress_callback == mock_callback
# Verify callback was passed to the strategy
assert system.strategy.progress_callback == mock_callback
@pytest.mark.requires_llm
def test_analyze_topic(monkeypatch):
"""Test analyzing a topic."""
# Set up mock LLM and search
mock_llm_instance = Mock()
mock_search_instance = Mock()
# Create a mock strategy class and instance
mock_strategy_class = Mock()
mock_strategy_instance = Mock()
mock_strategy_instance.analyze_topic.return_value = {
"findings": [{"content": "Test finding"}],
"current_knowledge": "Test knowledge",
"iterations": 2,
"questions_by_iteration": {
1: ["Question 1?", "Question 2?"],
2: ["Follow-up 1?", "Follow-up 2?"],
},
"all_links_of_system": [
"https://example.com/1",
"https://example.com/2",
],
}
# Set the questions_by_iteration attribute on the mock strategy
mock_strategy_instance.questions_by_iteration = {
1: ["Question 1?", "Question 2?"],
2: ["Follow-up 1?", "Follow-up 2?"],
}
# Set all_links_of_system attribute on the mock strategy
mock_strategy_instance.all_links_of_system = [
"https://example.com/1",
"https://example.com/2",
]
mock_strategy_class.return_value = mock_strategy_instance
# Mock get_llm and get_search from their actual modules
monkeypatch.setattr(
"local_deep_research.config.llm_config.get_llm",
lambda **kwargs: mock_llm_instance,
)
monkeypatch.setattr(
"local_deep_research.config.search_config.get_search",
lambda llm_instance=None, **kwargs: mock_search_instance,
)
# Mock SourceBasedSearchStrategy which is now the default
monkeypatch.setattr(
"local_deep_research.search_system.SourceBasedSearchStrategy",
mock_strategy_class,
)
# Import after mocking
from local_deep_research.search_system import AdvancedSearchSystem
# Create settings snapshot for the test
settings_snapshot = {
"search.cross_engine_max_results": {"value": 100, "type": "int"},
"search.cross_engine_use_reddit": {"value": False, "type": "bool"},
"search.cross_engine_min_date": {"value": None, "type": "str"},
"llm.provider": {"value": "test_provider", "type": "str"},
"llm.model": {"value": "test_model", "type": "str"},
"search.tool": {"value": "test_search", "type": "str"},
}
# Create the search system (uses source-based strategy by default)
system = AdvancedSearchSystem(
llm=mock_llm_instance,
search=mock_search_instance,
settings_snapshot=settings_snapshot,
)
# Set mock all_links_of_system attribute on the strategy
system.strategy.all_links_of_system = [
"https://example.com/1",
"https://example.com/2",
]
# Analyze a topic
result = system.analyze_topic("test query")
# Verify strategy's analyze_topic was called
mock_strategy_instance.analyze_topic.assert_called_once_with("test query")
# Verify result contents
assert "findings" in result
assert "current_knowledge" in result
assert "iterations" in result
assert "questions_by_iteration" in result
assert "search_system" in result
# Verify search_system reference is correct
assert result["search_system"] == system
# Verify questions and links were stored on the system
assert system.questions_by_iteration == {
1: ["Question 1?", "Question 2?"],
2: ["Follow-up 1?", "Follow-up 2?"],
}
assert system.all_links_of_system == [
"https://example.com/1",
"https://example.com/2",
]