fed8b2eed7
Backend release / release (push) Waiting to run
Bandit Security Scan / bandit_scan (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / manifest (push) Blocked by required conditions
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / manifest (push) Blocked by required conditions
Python linting / ruff (push) Waiting to run
Run python tests with pytest / Run tests and count coverage (3.12) (push) Waiting to run
React Widget Build / build (push) Waiting to run
146 lines
5.2 KiB
Python
146 lines
5.2 KiB
Python
"""Tests for application/agents/tools/duckduckgo.py"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from application.agents.tools.duckduckgo import DuckDuckGoSearchTool
|
|
|
|
|
|
@pytest.fixture
|
|
def tool():
|
|
return DuckDuckGoSearchTool(config={})
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestDuckDuckGoExecuteAction:
|
|
def test_unknown_action_raises(self, tool):
|
|
with pytest.raises(ValueError, match="Unknown action"):
|
|
tool.execute_action("invalid")
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_web_search_success(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.text.return_value = [
|
|
{"title": "Result 1", "href": "https://example.com", "body": "snippet"}
|
|
]
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_web_search", query="python")
|
|
|
|
assert result["status_code"] == 200
|
|
assert len(result["results"]) == 1
|
|
assert "successfully" in result["message"]
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_image_search_success(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.images.return_value = [{"image": "https://img.com/1.jpg"}]
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_image_search", query="cats")
|
|
|
|
assert result["status_code"] == 200
|
|
assert len(result["results"]) == 1
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_news_search_success(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.news.return_value = [{"title": "News"}]
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_news_search", query="tech")
|
|
|
|
assert result["status_code"] == 200
|
|
assert len(result["results"]) == 1
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_search_error_returns_500(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.text.side_effect = Exception("Network error")
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_web_search", query="test")
|
|
|
|
assert result["status_code"] == 500
|
|
assert "failed" in result["message"].lower()
|
|
assert result["results"] == []
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_max_results_capped_at_20(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.text.return_value = []
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
tool.execute_action("ddg_web_search", query="test", max_results=100)
|
|
|
|
call_kwargs = mock_client.text.call_args[1]
|
|
assert call_kwargs["max_results"] == 20
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_image_max_results_capped_at_50(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.images.return_value = []
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
tool.execute_action("ddg_image_search", query="test", max_results=200)
|
|
|
|
call_kwargs = mock_client.images.call_args[1]
|
|
assert call_kwargs["max_results"] == 50
|
|
|
|
@patch("application.agents.tools.duckduckgo.time.sleep")
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_rate_limit_retries(self, mock_client_factory, mock_sleep, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.text.side_effect = [
|
|
Exception("RateLimit exceeded"),
|
|
[{"title": "Result"}],
|
|
]
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_web_search", query="test")
|
|
|
|
assert result["status_code"] == 200
|
|
assert len(result["results"]) == 1
|
|
mock_sleep.assert_called_once()
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_empty_results(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.text.return_value = []
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_web_search", query="obscure query")
|
|
|
|
assert result["status_code"] == 200
|
|
assert result["results"] == []
|
|
|
|
@patch.object(DuckDuckGoSearchTool, "_get_ddgs_client")
|
|
def test_none_results(self, mock_client_factory, tool):
|
|
mock_client = MagicMock()
|
|
mock_client.text.return_value = None
|
|
mock_client_factory.return_value = mock_client
|
|
|
|
result = tool.execute_action("ddg_web_search", query="test")
|
|
|
|
assert result["status_code"] == 200
|
|
assert result["results"] == []
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestDuckDuckGoMetadata:
|
|
def test_actions_metadata(self, tool):
|
|
meta = tool.get_actions_metadata()
|
|
assert len(meta) == 3
|
|
names = {a["name"] for a in meta}
|
|
assert "ddg_web_search" in names
|
|
assert "ddg_image_search" in names
|
|
assert "ddg_news_search" in names
|
|
|
|
def test_config_requirements(self, tool):
|
|
assert tool.get_config_requirements() == {}
|
|
|
|
def test_custom_timeout(self):
|
|
tool = DuckDuckGoSearchTool(config={"timeout": 30})
|
|
assert tool.timeout == 30
|