myrmidon / python /tests /integration /services /test_phase47_devbot_skills.py
tek Atrust
chore(deploy): build monolithic server for Hugging Face
d5ef46f
Raw
History Blame Contribute Delete
3.66 kB
import json
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from src.server.services.agent_service import AgentService
@pytest.fixture
def mock_mcp_client():
client = AsyncMock()
# Mock tool response
client.search_code_examples.return_value = "Found example: from foo.bar import Baz"
return client
@pytest.mark.asyncio
async def test_analyze_error_with_skills_flow(mock_mcp_client):
"""
[Phase 4.7] Test the 'Look-Before-Leap' flow where DevBot uses a tool before fixing.
"""
# 1. Setup Service with MCP
service = AgentService(mcp_client=mock_mcp_client)
mock_tool_call = MagicMock()
mock_tool_call.function.name = "search_code_examples"
mock_tool_call.function.arguments = '{"query": "ImportError"}'
mock_tool_call.id = "call_123"
# Response 1: Wants to use tool
r1_message = MagicMock()
r1_message.tool_calls = [mock_tool_call]
r1_message.content = None
r1_choice = MagicMock()
r1_choice.message = r1_message
# Response 2: Final verdict (after seeing tool output)
final_fix = {"file_path": "script.py", "fixed_content": "import foo", "reasoning": "Fixed based on search"}
r2_message = MagicMock()
r2_message.tool_calls = None
r2_message.content = json.dumps(final_fix)
r2_choice = MagicMock()
r2_choice.message = r2_message
# Mock the LLM client
mock_llm_client = AsyncMock()
mock_llm_client.chat.completions.create.side_effect = [
MagicMock(choices=[r1_choice]), # Round 1
MagicMock(choices=[r2_choice]), # Round 2
]
mock_ctx = AsyncMock()
mock_ctx.__aenter__.return_value = mock_llm_client
mock_provider_config = {"chat_model": "test-model-v1"}
with (
patch("src.server.services.dev_ops_agent_service.get_llm_client", return_value=mock_ctx),
patch(
"src.server.services.dev_ops_agent_service.credential_service.get_active_provider", return_value=mock_provider_config
),
):
result = await service.dev_ops._analyze_error_with_structured_output(
command="python script.py", stderr="ImportError: No module named foo", agent_id="bcb00484-30bd-46fb-9e39-84b2ec4ced31"
)
mock_mcp_client.search_code_examples.assert_called_once_with(query="ImportError")
assert mock_llm_client.chat.completions.create.call_count == 2
assert result == final_fix
@pytest.mark.asyncio
async def test_analyze_error_graceful_degradation():
"""
[Phase 4.7] Test that DevBot works even if MCP client is missing (legacy mode).
"""
service = AgentService(mcp_client=None)
final_fix = {"file_path": "a.py", "fixed_content": "print('ok')", "reasoning": "guess"}
r1_message = MagicMock()
r1_message.tool_calls = None
r1_message.content = json.dumps(final_fix)
mock_llm_client = AsyncMock()
mock_llm_client.chat.completions.create.return_value = MagicMock(choices=[MagicMock(message=r1_message)])
mock_ctx = AsyncMock()
mock_ctx.__aenter__.return_value = mock_llm_client
with (
patch("src.server.services.dev_ops_agent_service.get_llm_client", return_value=mock_ctx),
patch(
"src.server.services.dev_ops_agent_service.credential_service.get_active_provider",
return_value={"chat_model": "test-model-v1"},
),
):
result = await service.dev_ops._analyze_error_with_structured_output("cmd", "err", agent_id="bcb00484-30bd-46fb-9e39-84b2ec4ced31")
assert result == final_fix
call_args = mock_llm_client.chat.completions.create.call_args
assert call_args.kwargs["tools"] is None