kgraph-mcp-agent-platform / tests /test_app_gradio.py
BasalGanglia's picture
๐Ÿ› ๏ธ Fix HuggingFace Space configuration - Remove quotes from frontmatter
64ced8b verified
"""Tests for Gradio UI functions and initialization in app.py."""
from unittest.mock import MagicMock, patch
from kg_services.ontology import MCPPrompt, MCPTool, PlannedStep
class TestInitializeAgentSystem:
"""Test agent system initialization."""
@patch("app.McpExecutorAgent")
@patch("app.SimplePlannerAgent")
@patch("app.InMemoryKG")
@patch("app.EmbeddingService")
def test_initialize_agent_system_success(
self,
mock_embedder_cls,
mock_kg_cls,
mock_planner_agent_cls,
mock_executor_agent_cls,
):
"""Test successful agent system initialization."""
from app import initialize_agent_system
# Setup mocks
mock_embedder = MagicMock()
mock_embedder_cls.return_value = mock_embedder
mock_kg = MagicMock()
mock_kg.load_tools_from_json.return_value = True
mock_kg.load_prompts_from_json.return_value = True
mock_kg.build_vector_index.return_value = True
mock_kg_cls.return_value = mock_kg
mock_planner_agent = MagicMock()
mock_planner_agent_cls.return_value = mock_planner_agent
mock_executor_agent = MagicMock()
mock_executor_agent_cls.return_value = mock_executor_agent
# Call function
result = initialize_agent_system()
# Verify result is a tuple with both agents
assert result == (mock_planner_agent, mock_executor_agent)
# Verify initialization sequence
mock_embedder_cls.assert_called_once()
mock_kg_cls.assert_called_once()
mock_kg.load_tools_from_json.assert_called_once_with("data/initial_tools.json")
mock_kg.load_prompts_from_json.assert_called_once_with(
"data/initial_prompts.json"
)
mock_kg.build_vector_index.assert_called_once_with(mock_embedder)
mock_planner_agent_cls.assert_called_once_with(
kg=mock_kg, embedder=mock_embedder
)
mock_executor_agent_cls.assert_called_once()
@patch("app.SimplePlannerAgent")
@patch("app.InMemoryKG")
@patch("app.EmbeddingService")
def test_initialize_agent_system_tools_load_failure(
self, mock_embedder_cls, mock_kg_cls, mock_agent_cls
):
"""Test agent initialization when tools fail to load."""
from app import initialize_agent_system
# Setup mocks
mock_embedder = MagicMock()
mock_embedder_cls.return_value = mock_embedder
mock_kg = MagicMock()
mock_kg.load_tools_from_json.return_value = False # Fail to load tools
mock_kg_cls.return_value = mock_kg
# Call function
result = initialize_agent_system()
# Verify result
assert result == (None, None)
# Verify tools loading was attempted but prompts loading was not
mock_kg.load_tools_from_json.assert_called_once_with("data/initial_tools.json")
mock_kg.load_prompts_from_json.assert_not_called()
mock_agent_cls.assert_not_called()
@patch("app.SimplePlannerAgent")
@patch("app.InMemoryKG")
@patch("app.EmbeddingService")
def test_initialize_agent_system_prompts_load_failure(
self, mock_embedder_cls, mock_kg_cls, mock_agent_cls
):
"""Test agent initialization when prompts fail to load."""
from app import initialize_agent_system
# Setup mocks
mock_embedder = MagicMock()
mock_embedder_cls.return_value = mock_embedder
mock_kg = MagicMock()
mock_kg.load_tools_from_json.return_value = True
mock_kg.load_prompts_from_json.return_value = False # Fail to load prompts
mock_kg_cls.return_value = mock_kg
# Call function
result = initialize_agent_system()
# Verify result
assert result == (None, None)
# Verify loading sequence
mock_kg.load_tools_from_json.assert_called_once_with("data/initial_tools.json")
mock_kg.load_prompts_from_json.assert_called_once_with(
"data/initial_prompts.json"
)
mock_kg.build_vector_index.assert_not_called()
mock_agent_cls.assert_not_called()
@patch("app.McpExecutorAgent")
@patch("app.SimplePlannerAgent")
@patch("app.InMemoryKG")
@patch("app.EmbeddingService")
def test_initialize_agent_system_vector_index_failure_with_fallback(
self,
mock_embedder_cls,
mock_kg_cls,
mock_planner_agent_cls,
mock_executor_agent_cls,
):
"""Test agent initialization when vector index fails but fallback succeeds."""
from app import initialize_agent_system
# Setup mocks
mock_embedder = MagicMock()
mock_embedder_cls.return_value = mock_embedder
mock_kg = MagicMock()
mock_kg.load_tools_from_json.return_value = True
mock_kg.load_prompts_from_json.return_value = True
mock_kg.build_vector_index.return_value = False # Fail to build index
mock_kg_cls.return_value = mock_kg
mock_planner_agent = MagicMock()
mock_planner_agent_cls.return_value = mock_planner_agent
mock_executor_agent = MagicMock()
mock_executor_agent_cls.return_value = mock_executor_agent
# Call function
result = initialize_agent_system()
# Verify result
assert result == (mock_planner_agent, mock_executor_agent)
# Verify fallback was called
mock_kg.build_vector_index.assert_called_once_with(mock_embedder)
mock_kg._create_mock_embeddings.assert_called_once()
mock_planner_agent_cls.assert_called_once_with(
kg=mock_kg, embedder=mock_embedder
)
mock_executor_agent_cls.assert_called_once()
@patch("app.SimplePlannerAgent")
@patch("app.InMemoryKG")
@patch("app.EmbeddingService")
def test_initialize_agent_system_exception_handling(
self, mock_embedder_cls, mock_kg_cls, mock_agent_cls
):
"""Test agent initialization exception handling."""
from app import initialize_agent_system
# Setup mocks to raise exception
mock_embedder_cls.side_effect = Exception("Test error")
# Call function
result = initialize_agent_system()
# Verify result
assert result == (None, None)
class TestGradioUtilityFunctions:
"""Test Gradio utility functions."""
def test_get_task_status(self):
"""Test get_task_status function."""
from app import get_task_status
result = get_task_status()
# Should return a string status
assert isinstance(result, str)
assert len(result) > 0
def test_create_new_task_with_title(self):
"""Test create_new_task with valid title."""
from app import create_new_task
result = create_new_task("Test Task", "Test Description")
assert isinstance(result, str)
assert "Test Task" in result
assert "Test Description" in result
assert "โœ… Created task" in result
def test_create_new_task_empty_title(self):
"""Test create_new_task with empty title."""
from app import create_new_task
result = create_new_task("", "Test Description")
assert isinstance(result, str)
assert "โŒ Error" in result
assert "required" in result
def test_create_new_task_whitespace_title(self):
"""Test create_new_task with whitespace-only title."""
from app import create_new_task
result = create_new_task(" ", "Test Description")
assert isinstance(result, str)
assert "โŒ Error" in result
assert "required" in result
class TestProcessUserQuery:
"""Test process_user_query function."""
@patch("app.planner_agent")
def test_process_user_query_empty_query(self, mock_agent):
"""Test process_user_query with empty query."""
from app import process_user_query
result = process_user_query("", [])
assert result[0] == "Please enter a valid query."
assert result[1] == []
def test_process_user_query_no_agent(self):
"""Test process_user_query when agent is not initialized."""
from app import process_user_query
with patch("app.planner_agent", None):
result = process_user_query("test query", [])
# Function returns empty string as first element, message is in history
assert result[0] == ""
assert len(result[1]) == 2 # User query + assistant response
assert "not initialized" in result[1][1]["content"]
@patch("app.planner_agent")
def test_process_user_query_enhanced_planner_no_results(self, mock_agent):
"""Test process_user_query with enhanced planner returning no results."""
from app import process_user_query
# Setup mock
mock_agent.generate_plan.return_value = []
result = process_user_query("test query", [], use_enhanced_planner=True)
# Function returns empty string as first element, message is in history
assert result[0] == ""
assert len(result[1]) == 2 # User query + assistant response
assert "couldn't find any relevant" in result[1][1]["content"]
@patch("app.planner_agent")
def test_process_user_query_enhanced_planner_with_results(self, mock_agent):
"""Test process_user_query with enhanced planner returning results."""
from app import process_user_query
# Create mock planned step
mock_tool = MCPTool(
tool_id="test_tool",
name="Test Tool",
description="A test tool",
tags=["test"],
invocation_command_stub="test_command",
)
mock_prompt = MCPPrompt(
prompt_id="test_prompt",
name="Test Prompt",
description="A test prompt",
target_tool_id="test_tool",
template_string="Test template",
tags=["test"],
input_variables=[],
difficulty_level="beginner",
)
mock_step = PlannedStep(
tool=mock_tool, prompt=mock_prompt, relevance_score=0.85
)
# Mock the summary property since it's computed
with patch.object(
type(mock_step),
"summary",
new_callable=lambda: property(lambda self: "Test summary"),
):
# Setup mock
mock_agent.generate_plan.return_value = [mock_step]
result = process_user_query("test query", [], use_enhanced_planner=True)
# Function returns empty string as first element, message is in history
assert result[0] == ""
assert len(result[1]) == 2 # User query + assistant response
assert "Enhanced Planning Results" in result[1][1]["content"]
assert "Test Tool" in result[1][1]["content"]
assert "Test Prompt" in result[1][1]["content"]
@patch("app.planner_agent")
def test_process_user_query_regular_planner(self, mock_agent):
"""Test process_user_query with regular planner."""
from app import process_user_query
# Create mock tool
mock_tool = MCPTool(
tool_id="test_tool",
name="Test Tool",
description="A test tool",
tags=["test"],
invocation_command_stub="test_command",
)
# Setup mock
mock_agent.suggest_tools.return_value = [mock_tool]
result = process_user_query("test query", [], use_enhanced_planner=False)
# Function returns empty string as first element, message is in history
assert result[0] == ""
assert len(result[1]) == 2 # User query + assistant response
assert "Test Tool" in result[1][1]["content"]
class TestHandleGeneratePlan:
"""Test handle_generate_plan function."""
@patch("app.planner_agent")
def test_handle_generate_plan_success(self, mock_agent):
"""Test successful plan generation."""
from app import handle_generate_plan_core
# Create mock planned step
mock_tool = MCPTool(
tool_id="test_tool",
name="Test Tool",
description="A test tool",
tags=["test"],
invocation_command_stub="test_command",
)
mock_prompt = MCPPrompt(
prompt_id="test_prompt",
name="Test Prompt",
description="A test prompt",
target_tool_id="test_tool",
template_string="Test {{input}}",
tags=["test"],
input_variables=["input"],
difficulty_level="beginner",
)
mock_step = PlannedStep(
tool=mock_tool, prompt=mock_prompt, relevance_score=0.85
)
# Setup mock
mock_agent.generate_plan.return_value = [mock_step]
result = handle_generate_plan_core("test query")
assert result["status"] == "success"
assert result["query"] == "test query"
assert result["total_steps"] == 1
assert len(result["planned_steps"]) == 1
@patch("app.planner_agent", None)
def test_handle_generate_plan_no_agent(self):
"""Test plan generation when agent is not initialized."""
from app import handle_generate_plan_core
result = handle_generate_plan_core("test query")
assert result["status"] == "error"
assert "not initialized" in result["message"]
@patch("app.planner_agent")
def test_handle_generate_plan_empty_query(self, mock_agent):
"""Test plan generation with empty query."""
from app import handle_generate_plan_core
result = handle_generate_plan_core("")
assert result["status"] == "error"
assert "query" in result["message"]
@patch("app.planner_agent")
def test_handle_generate_plan_exception(self, mock_agent):
"""Test plan generation exception handling."""
from app import handle_generate_plan_core
# Setup mock to raise exception
mock_agent.generate_plan.side_effect = Exception("Test error")
result = handle_generate_plan_core("test query")
assert result["status"] == "error"
assert "error" in result["message"]
# Note: Main function testing is complex due to Gradio/Uvicorn integration
# Coverage for main() function is achieved through integration testing