|
|
"""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 |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
result = initialize_agent_system() |
|
|
|
|
|
|
|
|
assert result == (mock_planner_agent, mock_executor_agent) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
mock_embedder = MagicMock() |
|
|
mock_embedder_cls.return_value = mock_embedder |
|
|
|
|
|
mock_kg = MagicMock() |
|
|
mock_kg.load_tools_from_json.return_value = False |
|
|
mock_kg_cls.return_value = mock_kg |
|
|
|
|
|
|
|
|
result = initialize_agent_system() |
|
|
|
|
|
|
|
|
assert result == (None, None) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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 |
|
|
mock_kg_cls.return_value = mock_kg |
|
|
|
|
|
|
|
|
result = initialize_agent_system() |
|
|
|
|
|
|
|
|
assert result == (None, None) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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 |
|
|
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 |
|
|
|
|
|
|
|
|
result = initialize_agent_system() |
|
|
|
|
|
|
|
|
assert result == (mock_planner_agent, mock_executor_agent) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
mock_embedder_cls.side_effect = Exception("Test error") |
|
|
|
|
|
|
|
|
result = initialize_agent_system() |
|
|
|
|
|
|
|
|
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() |
|
|
|
|
|
|
|
|
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", []) |
|
|
|
|
|
|
|
|
assert result[0] == "" |
|
|
assert len(result[1]) == 2 |
|
|
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 |
|
|
|
|
|
|
|
|
mock_agent.generate_plan.return_value = [] |
|
|
|
|
|
result = process_user_query("test query", [], use_enhanced_planner=True) |
|
|
|
|
|
|
|
|
assert result[0] == "" |
|
|
assert len(result[1]) == 2 |
|
|
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 |
|
|
|
|
|
|
|
|
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 |
|
|
) |
|
|
|
|
|
with patch.object( |
|
|
type(mock_step), |
|
|
"summary", |
|
|
new_callable=lambda: property(lambda self: "Test summary"), |
|
|
): |
|
|
|
|
|
mock_agent.generate_plan.return_value = [mock_step] |
|
|
|
|
|
result = process_user_query("test query", [], use_enhanced_planner=True) |
|
|
|
|
|
|
|
|
assert result[0] == "" |
|
|
assert len(result[1]) == 2 |
|
|
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 |
|
|
|
|
|
|
|
|
mock_tool = MCPTool( |
|
|
tool_id="test_tool", |
|
|
name="Test Tool", |
|
|
description="A test tool", |
|
|
tags=["test"], |
|
|
invocation_command_stub="test_command", |
|
|
) |
|
|
|
|
|
|
|
|
mock_agent.suggest_tools.return_value = [mock_tool] |
|
|
|
|
|
result = process_user_query("test query", [], use_enhanced_planner=False) |
|
|
|
|
|
|
|
|
assert result[0] == "" |
|
|
assert len(result[1]) == 2 |
|
|
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 |
|
|
|
|
|
|
|
|
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 |
|
|
) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|