v1.0
This commit is contained in:
1 parent
0246cbb6ba
commit
0ca4b4bf7a
89 files changed
+7042
-2480
No files matched your search
@@ -0,0 +1,61 @@
|
||||
"""Tests for duckduckgo-mcp (run with duckduckgo-mcp/.venv: needs mcp 1.x FastMCP).
|
||||
|
||||
duckduckgo-mcp\\.venv\\Scripts\\python.exe -m pytest tests/test_duckduckgo_mcp.py -q
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
|
||||
pytest.importorskip("mcp.server.fastmcp")
|
||||
pytest.importorskip("duckduckgo_mcp")
|
||||
|
||||
from mcp.server.fastmcp.exceptions import ToolError # noqa: E402
|
||||
|
||||
from duckduckgo_mcp import server as srv # noqa: E402
|
||||
|
||||
|
||||
class FakeDDGS:
|
||||
def __init__(self, fail: Exception | None = None):
|
||||
self.fail = fail
|
||||
self.threads: list[str] = []
|
||||
|
||||
def text(self, query, **kwargs):
|
||||
self.threads.append(threading.current_thread().name)
|
||||
if self.fail:
|
||||
raise self.fail
|
||||
return [{"title": "T", "href": "https://example.org", "body": "B"}]
|
||||
|
||||
def news(self, query, **kwargs):
|
||||
return self.text(query, **kwargs)
|
||||
|
||||
|
||||
def test_search_runs_off_the_event_loop(monkeypatch):
|
||||
fake = FakeDDGS()
|
||||
monkeypatch.setattr(srv, "_get_ddgs", lambda: fake)
|
||||
out = asyncio.run(srv.mcp.call_tool("ddg_search", {"query": "python"}))
|
||||
assert "example.org" in str(out)
|
||||
assert fake.threads and fake.threads[0] != threading.main_thread().name
|
||||
|
||||
|
||||
def test_failures_are_tool_errors(monkeypatch):
|
||||
monkeypatch.setattr(srv, "_get_ddgs", lambda: FakeDDGS(RuntimeError("Ratelimit")))
|
||||
with pytest.raises(ToolError, match="Ratelimit"):
|
||||
asyncio.run(srv.mcp.call_tool("ddg_search", {"query": "python"}))
|
||||
with pytest.raises(ToolError, match="Ratelimit"):
|
||||
asyncio.run(srv.mcp.call_tool("ddg_answers", {"query": "python"}))
|
||||
|
||||
|
||||
def test_input_validation(monkeypatch):
|
||||
monkeypatch.setattr(srv, "_get_ddgs", lambda: FakeDDGS())
|
||||
with pytest.raises(ToolError, match="empty"):
|
||||
asyncio.run(srv.mcp.call_tool("ddg_news", {"query": " "}))
|
||||
with pytest.raises(ToolError, match="safesearch"):
|
||||
asyncio.run(srv.mcp.call_tool("ddg_search", {"query": "x", "safesearch": "strict"}))
|
||||
|
||||
|
||||
def test_tool_annotations():
|
||||
for t in asyncio.run(srv.mcp.list_tools()):
|
||||
assert t.annotations.readOnlyHint is True and t.annotations.openWorldHint is True, t.name
|
||||
Reference in new issue
Block a user