mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-29 16:43:16 +00:00
- Add 104 comprehensive tests for agent system - Integrate agent tests into CI/CD pipeline - Standardize tests with @pytest.mark.unit markers - Fix cross-platform path compatibility - Clean up unused imports and dependencies
236 lines
8.2 KiB
Python
236 lines
8.2 KiB
Python
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
from application.agents.tools.base import Tool
|
|
from application.agents.tools.tool_manager import ToolManager
|
|
|
|
|
|
class MockTool(Tool):
|
|
def __init__(self, config):
|
|
self.config = config
|
|
|
|
def execute_action(self, action_name: str, **kwargs):
|
|
return f"Executed {action_name} with {kwargs}"
|
|
|
|
def get_actions_metadata(self):
|
|
return [{"name": "test_action", "description": "Test action"}]
|
|
|
|
def get_config_requirements(self):
|
|
return {"required": ["api_key"]}
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestToolManager:
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
def test_tool_manager_initialization(self, mock_iter):
|
|
mock_iter.return_value = []
|
|
|
|
config = {"tool1": {"key": "value"}}
|
|
manager = ToolManager(config)
|
|
|
|
assert manager.config == config
|
|
assert isinstance(manager.tools, dict)
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
@patch("application.agents.tools.tool_manager.importlib.import_module")
|
|
def test_load_tools_skips_base_and_private(self, mock_import, mock_iter):
|
|
mock_iter.return_value = [
|
|
(None, "base", False),
|
|
(None, "__init__", False),
|
|
(None, "__pycache__", False),
|
|
(None, "valid_tool", False),
|
|
]
|
|
|
|
mock_module = Mock()
|
|
mock_module.MockTool = MockTool
|
|
mock_import.return_value = mock_module
|
|
|
|
manager = ToolManager({})
|
|
|
|
assert "base" not in manager.tools
|
|
assert "__init__" not in manager.tools
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
def test_load_tools_creates_tool_instances(self, mock_iter):
|
|
mock_iter.return_value = []
|
|
|
|
manager = ToolManager({})
|
|
|
|
mock_tool = MockTool({"test": "config"})
|
|
manager.tools["mock_tool"] = mock_tool
|
|
|
|
assert "mock_tool" in manager.tools
|
|
assert isinstance(manager.tools["mock_tool"], MockTool)
|
|
assert manager.tools["mock_tool"].config == {"test": "config"}
|
|
|
|
def test_load_tool_with_user_id(self):
|
|
with patch(
|
|
"application.agents.tools.tool_manager.pkgutil.iter_modules",
|
|
return_value=[],
|
|
):
|
|
manager = ToolManager({})
|
|
tool = MockTool({"key": "value"})
|
|
assert tool.config == {"key": "value"}
|
|
|
|
manager.config["test_tool"] = {"key": "value"}
|
|
assert "test_tool" in manager.config
|
|
|
|
def test_load_tool_without_user_id(self):
|
|
tool = MockTool({"api_key": "test123"})
|
|
|
|
assert isinstance(tool, MockTool)
|
|
assert tool.config == {"api_key": "test123"}
|
|
|
|
assert hasattr(tool, "execute_action")
|
|
assert hasattr(tool, "get_actions_metadata")
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
def test_load_tool_updates_config(self, mock_iter):
|
|
mock_iter.return_value = []
|
|
|
|
manager = ToolManager({})
|
|
new_config = {"new_key": "new_value"}
|
|
|
|
manager.config["test_tool"] = new_config
|
|
|
|
assert manager.config["test_tool"] == new_config
|
|
assert "test_tool" in manager.config
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
@patch("application.agents.tools.tool_manager.importlib.import_module")
|
|
def test_execute_action_on_loaded_tool(self, mock_import, mock_iter):
|
|
mock_iter.return_value = [(None, "mock_tool", False)]
|
|
|
|
mock_tool_instance = MockTool({})
|
|
|
|
with patch("inspect.getmembers", return_value=[("MockTool", MockTool)]):
|
|
with patch("inspect.isclass", return_value=True):
|
|
with patch.object(MockTool, "__init__", return_value=None):
|
|
manager = ToolManager({})
|
|
manager.tools["mock_tool"] = mock_tool_instance
|
|
|
|
result = manager.execute_action(
|
|
"mock_tool", "test_action", param="value"
|
|
)
|
|
|
|
assert "Executed test_action" in result
|
|
|
|
def test_execute_action_tool_not_loaded(self):
|
|
with patch(
|
|
"application.agents.tools.tool_manager.pkgutil.iter_modules",
|
|
return_value=[],
|
|
):
|
|
manager = ToolManager({})
|
|
with pytest.raises(ValueError, match="Tool 'nonexistent' not loaded"):
|
|
manager.execute_action("nonexistent", "action")
|
|
|
|
@patch("application.agents.tools.tool_manager.importlib.import_module")
|
|
def test_execute_action_with_user_id_for_mcp_tool(self, mock_import):
|
|
mock_tool = MockTool({})
|
|
|
|
with patch("inspect.getmembers", return_value=[("MockTool", MockTool)]):
|
|
with patch("inspect.isclass", return_value=True):
|
|
manager = ToolManager({"mcp_tool": {}})
|
|
manager.tools["mcp_tool"] = mock_tool
|
|
|
|
with patch.object(
|
|
manager, "load_tool", return_value=mock_tool
|
|
) as mock_load:
|
|
manager.execute_action("mcp_tool", "action", user_id="user123")
|
|
|
|
mock_load.assert_called_once_with("mcp_tool", {}, "user123")
|
|
|
|
@patch("application.agents.tools.tool_manager.importlib.import_module")
|
|
def test_execute_action_with_user_id_for_memory_tool(self, mock_import):
|
|
mock_tool = MockTool({})
|
|
|
|
with patch("inspect.getmembers", return_value=[("MockTool", MockTool)]):
|
|
with patch("inspect.isclass", return_value=True):
|
|
manager = ToolManager({"memory": {}})
|
|
manager.tools["memory"] = mock_tool
|
|
|
|
with patch.object(
|
|
manager, "load_tool", return_value=mock_tool
|
|
) as mock_load:
|
|
manager.execute_action("memory", "view", user_id="user456")
|
|
|
|
mock_load.assert_called_once_with("memory", {}, "user456")
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
@patch("application.agents.tools.tool_manager.importlib.import_module")
|
|
def test_get_all_actions_metadata(self, mock_import, mock_iter):
|
|
mock_iter.return_value = [(None, "tool1", False), (None, "tool2", False)]
|
|
|
|
mock_tool1 = Mock()
|
|
mock_tool1.get_actions_metadata.return_value = [{"name": "action1"}]
|
|
|
|
mock_tool2 = Mock()
|
|
mock_tool2.get_actions_metadata.return_value = [{"name": "action2"}]
|
|
|
|
manager = ToolManager({})
|
|
manager.tools = {"tool1": mock_tool1, "tool2": mock_tool2}
|
|
|
|
metadata = manager.get_all_actions_metadata()
|
|
|
|
assert len(metadata) == 2
|
|
assert {"name": "action1"} in metadata
|
|
assert {"name": "action2"} in metadata
|
|
|
|
@patch("application.agents.tools.tool_manager.pkgutil.iter_modules")
|
|
def test_get_all_actions_metadata_empty(self, mock_iter):
|
|
mock_iter.return_value = []
|
|
|
|
manager = ToolManager({})
|
|
manager.tools = {}
|
|
|
|
metadata = manager.get_all_actions_metadata()
|
|
|
|
assert metadata == []
|
|
|
|
def test_load_tool_with_notes_tool(self):
|
|
tool = MockTool({"key": "value"})
|
|
|
|
assert isinstance(tool, MockTool)
|
|
assert tool.config == {"key": "value"}
|
|
|
|
result = tool.execute_action("test_action", param="value")
|
|
assert "test_action" in result
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestToolBase:
|
|
|
|
def test_tool_base_is_abstract(self):
|
|
with pytest.raises(TypeError):
|
|
Tool()
|
|
|
|
def test_mock_tool_implements_interface(self):
|
|
tool = MockTool({"test": "config"})
|
|
|
|
assert hasattr(tool, "execute_action")
|
|
assert hasattr(tool, "get_actions_metadata")
|
|
assert hasattr(tool, "get_config_requirements")
|
|
|
|
def test_mock_tool_execute_action(self):
|
|
tool = MockTool({})
|
|
result = tool.execute_action("test", param="value")
|
|
|
|
assert "Executed test" in result
|
|
assert "param" in result
|
|
|
|
def test_mock_tool_get_actions_metadata(self):
|
|
tool = MockTool({})
|
|
metadata = tool.get_actions_metadata()
|
|
|
|
assert isinstance(metadata, list)
|
|
assert len(metadata) > 0
|
|
assert "name" in metadata[0]
|
|
|
|
def test_mock_tool_get_config_requirements(self):
|
|
tool = MockTool({})
|
|
requirements = tool.get_config_requirements()
|
|
|
|
assert isinstance(requirements, dict)
|
|
assert "required" in requirements
|