Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

399 lines
14 KiB
Python

"""
Integration tests for MCP server.
Tests for complete research workflows with realistic mocked data.
"""
from unittest.mock import patch
import pytest
# Skip all tests if MCP is not available
try:
import mcp # noqa: F401
MCP_AVAILABLE = True
except ImportError:
MCP_AVAILABLE = False
pytestmark = pytest.mark.skipif(
not MCP_AVAILABLE, reason="MCP package not installed"
)
class TestSettingsFlow:
"""Tests for settings snapshot creation and override flow."""
def test_settings_snapshot_created_for_quick_research(self):
"""Verify settings snapshot is created when calling quick_research."""
from local_deep_research.mcp.server import quick_research
with patch(
"local_deep_research.mcp.server.create_settings_snapshot"
) as mock_snapshot:
mock_snapshot.return_value = {"llm.provider": "openai"}
with patch(
"local_deep_research.mcp.server.ldr_quick_summary",
return_value={
"summary": "Test",
"findings": [],
"sources": [],
"iterations": 1,
},
):
result = quick_research(query="test")
mock_snapshot.assert_called_once()
assert result["status"] == "success"
def test_settings_overrides_applied_to_snapshot(self):
"""Verify overrides are passed to create_settings_snapshot."""
from local_deep_research.mcp.server import quick_research
with patch(
"local_deep_research.mcp.server.create_settings_snapshot"
) as mock_snapshot:
mock_snapshot.return_value = {}
with (
patch(
"local_deep_research.mcp.server.ldr_quick_summary",
return_value={
"summary": "Test",
"findings": [],
"sources": [],
"iterations": 1,
},
),
patch(
"local_deep_research.mcp.server._validate_search_engine",
side_effect=lambda e: e,
),
patch(
"local_deep_research.mcp.server._validate_strategy",
side_effect=lambda s: s,
),
):
quick_research(
query="test",
search_engine="wikipedia",
strategy="source-based",
iterations=3,
)
# Check that overrides were passed (last call is from quick_research)
call_kwargs = mock_snapshot.call_args[1]
assert "overrides" in call_kwargs
overrides = call_kwargs["overrides"]
assert overrides["search.tool"] == "wikipedia"
assert overrides["search.search_strategy"] == "source-based"
assert overrides["search.iterations"] == 3
def test_settings_snapshot_passed_to_api(self):
"""Verify settings snapshot is passed to the API function."""
from local_deep_research.mcp.server import quick_research
mock_settings = {"llm.provider": "openai", "search.tool": "wikipedia"}
with patch(
"local_deep_research.mcp.server.create_settings_snapshot",
return_value=mock_settings,
):
with patch(
"local_deep_research.mcp.server.ldr_quick_summary"
) as mock_api:
mock_api.return_value = {
"summary": "Test",
"findings": [],
"sources": [],
"iterations": 1,
}
quick_research(query="test query")
# Verify settings_snapshot was passed to API
call_kwargs = mock_api.call_args[1]
assert "settings_snapshot" in call_kwargs
assert call_kwargs["settings_snapshot"] == mock_settings
def test_no_overrides_when_no_params(self):
"""Verify no overrides dict when no optional params provided."""
from local_deep_research.mcp.server import quick_research
with patch(
"local_deep_research.mcp.server.create_settings_snapshot"
) as mock_snapshot:
mock_snapshot.return_value = {}
with patch(
"local_deep_research.mcp.server.ldr_quick_summary",
return_value={
"summary": "Test",
"findings": [],
"sources": [],
"iterations": 1,
},
):
quick_research(query="test") # No optional params
# Should still be called (with empty overrides or no overrides kwarg)
mock_snapshot.assert_called_once()
class TestResearchFlowIntegration:
"""Tests for complete research workflows."""
def test_quick_research_complete_flow(self):
"""Test complete quick_research flow from input to output."""
from local_deep_research.mcp.server import quick_research
mock_result = {
"summary": "Quantum computing uses qubits for computation.",
"findings": [
{"phase": "Iteration 1", "content": "Found info about qubits"},
{
"phase": "Iteration 2",
"content": "Found info about superposition",
},
],
"sources": [
{"title": "Wikipedia", "link": "https://wikipedia.org/quantum"},
],
"iterations": 2,
"formatted_findings": "## Findings\n\nContent here",
}
with patch(
"local_deep_research.mcp.server.ldr_quick_summary",
return_value=mock_result,
):
result = quick_research(
query="What is quantum computing?",
search_engine="wikipedia",
iterations=2,
)
assert result["status"] == "success"
assert result["summary"] == mock_result["summary"]
assert len(result["findings"]) == 2
assert len(result["sources"]) == 1
assert result["iterations"] == 2
def test_detailed_research_complete_flow(self):
"""Test complete detailed_research flow."""
from local_deep_research.mcp.server import detailed_research
mock_result = {
"query": "machine learning applications",
"research_id": "research-abc-123",
"summary": "Machine learning has many applications...",
"findings": [{"content": "Finding 1"}, {"content": "Finding 2"}],
"sources": [{"title": "Source 1", "link": "https://example.com"}],
"iterations": 3,
"formatted_findings": "Formatted content",
"metadata": {
"timestamp": "2024-01-15T10:00:00Z",
"search_tool": "arxiv",
"strategy": "source-based",
},
}
with patch(
"local_deep_research.mcp.server.ldr_detailed_research",
return_value=mock_result,
):
result = detailed_research(
query="machine learning applications",
search_engine="arxiv",
strategy="source-based",
)
assert result["status"] == "success"
assert result["query"] == "machine learning applications"
assert result["research_id"] == "research-abc-123"
assert "metadata" in result
assert result["metadata"]["search_tool"] == "arxiv"
def test_generate_report_complete_flow(self):
"""Test complete generate_report flow."""
from local_deep_research.mcp.server import generate_report
mock_result = {
"content": "# Research Report\n\n## Introduction\n\nThis report...\n\n## Findings\n\n...",
"metadata": {
"generated_at": "2024-01-15T10:00:00Z",
"query": "climate change",
},
}
with patch(
"local_deep_research.mcp.server.ldr_generate_report",
return_value=mock_result,
):
result = generate_report(
query="climate change impacts",
searches_per_section=3,
)
assert result["status"] == "success"
assert result["content"].startswith("# Research Report")
assert "metadata" in result
class TestDiscoveryToolsIntegration:
"""Integration tests for discovery tools."""
def test_list_strategies_returns_all_expected_strategies(self):
"""Verify list_strategies returns the complete list."""
from local_deep_research.mcp.server import list_strategies
result = list_strategies()
assert result["status"] == "success"
strategy_names = [s["name"] for s in result["strategies"]]
# Check for key strategies
assert "source-based" in strategy_names
assert "focused-iteration" in strategy_names
assert "topic-organization" in strategy_names
assert "langgraph-agent" in strategy_names
def test_get_configuration_structure(self):
"""Verify get_configuration returns expected structure."""
from local_deep_research.mcp.server import get_configuration
result = get_configuration()
assert result["status"] == "success"
assert "config" in result
config = result["config"]
assert "llm" in config
assert "search" in config
# Check LLM config structure
assert "provider" in config["llm"]
assert "model" in config["llm"]
assert "temperature" in config["llm"]
# Check search config structure
assert "default_engine" in config["search"]
assert "default_strategy" in config["search"]
assert "iterations" in config["search"]
class TestErrorFlowIntegration:
"""Integration tests for error handling flows."""
def test_quick_research_error_flow(self):
"""Test error handling flow in quick_research."""
from local_deep_research.mcp.server import quick_research
with patch(
"local_deep_research.mcp.server.ldr_quick_summary",
side_effect=Exception("LLM service unavailable: 503"),
):
result = quick_research(query="test")
assert result["status"] == "error"
assert result["error_type"] == "service_unavailable"
def test_detailed_research_error_flow(self):
"""Test error handling flow in detailed_research."""
from local_deep_research.mcp.server import detailed_research
with patch(
"local_deep_research.mcp.server.ldr_detailed_research",
side_effect=Exception("Invalid API key"),
):
result = detailed_research(query="test")
assert result["status"] == "error"
assert result["error_type"] == "auth_error"
def test_generate_report_error_flow(self):
"""Test error handling flow in generate_report."""
from local_deep_research.mcp.server import generate_report
with patch(
"local_deep_research.mcp.server.ldr_generate_report",
side_effect=Exception("Request timeout after 30s"),
):
result = generate_report(query="test")
assert result["status"] == "error"
assert "timeout" in result["error"].lower()
assert result["error_type"] == "timeout"
def test_analyze_documents_error_flow(self):
"""Test error handling flow in analyze_documents."""
from local_deep_research.mcp.server import analyze_documents
with patch(
"local_deep_research.mcp.server.ldr_analyze_documents",
side_effect=Exception("Collection 'nonexistent' not found"),
):
result = analyze_documents(
query="test", collection_name="nonexistent"
)
assert result["status"] == "error"
assert result["error_type"] == "model_not_found"
class TestMultipleCallsIsolation:
"""Tests to verify calls don't interfere with each other."""
def test_settings_isolation_between_calls(self):
"""Verify settings from one call don't leak to another."""
from local_deep_research.mcp.server import quick_research
calls = []
def capture_call(*args, **kwargs):
calls.append(kwargs.get("settings_snapshot", {}))
return {
"summary": "Test",
"findings": [],
"sources": [],
"iterations": 1,
}
with patch(
"local_deep_research.mcp.server.ldr_quick_summary",
side_effect=capture_call,
):
# First call with wikipedia
quick_research(query="test1", search_engine="wikipedia")
# Second call with arxiv
quick_research(query="test2", search_engine="arxiv")
# Each call should have its own settings
assert len(calls) == 2
# Settings should be different (or at least both captured)
def test_error_in_one_call_doesnt_affect_next(self):
"""Verify an error in one call doesn't affect subsequent calls."""
from local_deep_research.mcp.server import quick_research
call_count = [0]
def mock_api(*args, **kwargs):
call_count[0] += 1
if call_count[0] == 1:
raise Exception("First call fails")
return {
"summary": "Success",
"findings": [],
"sources": [],
"iterations": 1,
}
with patch(
"local_deep_research.mcp.server.ldr_quick_summary",
side_effect=mock_api,
):
result1 = quick_research(query="test1")
result2 = quick_research(query="test2")
assert result1["status"] == "error"
assert result2["status"] == "success"
assert result2["summary"] == "Success"