"""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