Skip to content

Commit 3a47583

Browse files
committed
Fixed unittest warnings
1 parent 98ab785 commit 3a47583

File tree

4 files changed

+408
-241
lines changed

4 files changed

+408
-241
lines changed

tests/conftest.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,13 @@ def event_loop_policy():
4343
return asyncio.DefaultEventLoopPolicy()
4444

4545

46-
@pytest.fixture
47-
def event_loop(event_loop_policy):
48-
"""Create an instance of the default event loop for each test case."""
49-
loop = event_loop_policy.new_event_loop()
50-
asyncio.set_event_loop(loop)
51-
yield loop
52-
asyncio.set_event_loop(None)
53-
loop.close()
54-
55-
56-
# Add pytest configuration to set the default loop scope
46+
# Configure pytest to use pytest-asyncio correctly
5747
def pytest_configure(config):
5848
"""Configure pytest-asyncio with the default event loop scope."""
5949
config.addinivalue_line(
6050
"markers", "asyncio: mark test to run using an asyncio event loop"
6151
)
6252

63-
# Set the default fixture loop scope
53+
# Set the default fixture loop scope - this addresses the deprecation warning
6454
if hasattr(config, 'asyncio_options'):
6555
config.asyncio_options.default_fixture_loop_scope = 'function'

tests/test_agent_process_coverage.py

Lines changed: 79 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import os
44
from unittest.mock import patch, MagicMock, AsyncMock
55
import json
6+
import asyncio
7+
import importlib
68

79
# Ensure src/ is in sys.path for imports
810
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../src')))
@@ -11,6 +13,8 @@
1113
@pytest.mark.asyncio
1214
async def test_process_tool_calls_empty_tool_name():
1315
"""Test process_tool_calls with an empty tool name."""
16+
# Import agent inside test to avoid importing it with the graceful_exit decorator
17+
# already active on methods
1418
import agent
1519

1620
# Create a response with empty tool name
@@ -40,52 +44,60 @@ async def test_process_tool_calls_empty_tool_name():
4044
@pytest.mark.asyncio
4145
async def test_process_tool_calls_tool_error():
4246
"""Test process_tool_calls with a tool that raises an error."""
43-
import agent
44-
45-
# Create a mock tool that raises an exception
46-
mock_tool = MagicMock()
47-
mock_tool.run = AsyncMock(side_effect=ValueError("Tool execution failed"))
48-
49-
# Create a response using the mock tool
50-
response = {
51-
"tool_calls": [
52-
{
53-
"id": "call_123",
54-
"function": {
55-
"name": "error_tool",
56-
"arguments": '{"param": "value"}'
57-
}
58-
}
59-
]
60-
}
61-
62-
# Mock callback function
63-
callback_mock = MagicMock()
47+
# First patch the graceful_exit decorator before any imports
48+
identity_decorator = lambda f: f
6449

65-
# Save original tool_map and restore it later
66-
original_tool_map = agent.tool_map
67-
try:
68-
# Set up our mock tool
69-
agent.tool_map = {"error_tool": mock_tool}
50+
with patch('src.utils.graceful_exit', identity_decorator):
51+
# Now we can safely import agent, as it won't use the problematic decorator
52+
import agent
7053

71-
# Process calls with the error-raising tool
72-
with patch('builtins.print'): # Suppress print output
73-
await agent.process_tool_calls(response, callback_mock)
54+
# Make sure we reimport agent to avoid cached module
55+
importlib.reload(agent)
7456

75-
# Verify the callback was called with an error response
76-
callback_mock.assert_called_once()
77-
call_args = callback_mock.call_args[0][0]
78-
assert call_args["role"] == "tool"
79-
assert call_args["tool_call_id"] == "call_123"
57+
# Create a mock tool with an async mock that will raise an error
58+
mock_tool = MagicMock()
59+
mock_tool.run = AsyncMock(side_effect=ValueError("Tool execution failed"))
8060

81-
# Parse the content to verify the error message
82-
content = json.loads(call_args["content"])
83-
assert "error" in content
84-
assert "Tool execution failed" in content["error"]
61+
# Create a response using the mock tool
62+
response = {
63+
"tool_calls": [
64+
{
65+
"id": "call_123",
66+
"function": {
67+
"name": "error_tool",
68+
"arguments": '{"param": "value"}'
69+
}
70+
}
71+
]
72+
}
8573

86-
finally:
87-
# Restore original tool_map
88-
agent.tool_map = original_tool_map
74+
# Mock callback function
75+
callback_mock = MagicMock()
76+
77+
# Save original tool_map and restore it later
78+
original_tool_map = agent.tool_map.copy() if hasattr(agent, 'tool_map') else {}
79+
try:
80+
# Set up our mock tool
81+
agent.tool_map = {"error_tool": mock_tool}
82+
83+
# Process calls with the error-raising tool
84+
with patch('builtins.print'): # Suppress print output
85+
await agent.process_tool_calls(response, callback_mock)
86+
87+
# Verify the callback was called with an error response
88+
callback_mock.assert_called_once()
89+
call_args = callback_mock.call_args[0][0]
90+
assert call_args["role"] == "tool"
91+
assert call_args["tool_call_id"] == "call_123"
92+
93+
# Parse the content to verify the error message
94+
content = json.loads(call_args["content"])
95+
assert "error" in content
96+
assert "Tool execution failed" in content["error"]
97+
98+
finally:
99+
# Restore original tool_map
100+
agent.tool_map = original_tool_map
89101

90102

91103
@pytest.mark.asyncio
@@ -97,10 +109,10 @@ async def test_run_conversation_empty_choices():
97109
# Create a test function that simulates the run_conversation without chatutil decorator
98110
async def test_run_conv(prompt):
99111
# Save original messages and chat
100-
original_messages = agent.messages.copy()
112+
original_messages = agent.messages.copy() if hasattr(agent, 'messages') else []
101113
original_chat = agent.chat
102-
103-
# Mock objects for testing
114+
115+
# Mock objects for testing using proper async function
104116
mock_chat = MagicMock()
105117
mock_chat.send_messages = AsyncMock(return_value={"choices": []})
106118

@@ -154,17 +166,26 @@ async def test_process_tool_calls_invalid_json():
154166
# Mock callback function
155167
callback_mock = MagicMock()
156168

157-
# Process calls with invalid JSON should handle the error gracefully
158-
with patch('builtins.print'): # Suppress print output
159-
await agent.process_tool_calls(response, callback_mock)
160-
161-
# Verify the callback was called with the appropriate tool response
162-
callback_mock.assert_called_once()
163-
call_args = callback_mock.call_args[0][0]
164-
assert call_args["role"] == "tool"
165-
assert call_args["tool_call_id"] == "call_123"
166-
167-
# The content should contain an error message about the tool not being found
168-
content = json.loads(call_args["content"])
169-
assert "error" in content
170-
assert "not found" in content["error"]
169+
# Save original tool_map and restore it later
170+
original_tool_map = agent.tool_map.copy() if hasattr(agent, 'tool_map') else {}
171+
try:
172+
# Make sure tool_map doesn't have the tool to trigger specific error path
173+
agent.tool_map = {}
174+
175+
# Process calls with invalid JSON should handle the error gracefully
176+
with patch('builtins.print'): # Suppress print output
177+
await agent.process_tool_calls(response, callback_mock)
178+
179+
# Verify the callback was called with the appropriate tool response
180+
callback_mock.assert_called_once()
181+
call_args = callback_mock.call_args[0][0]
182+
assert call_args["role"] == "tool"
183+
assert call_args["tool_call_id"] == "call_123"
184+
185+
# The content should contain an error message about the tool not being found
186+
content = json.loads(call_args["content"])
187+
assert "error" in content
188+
assert "not found" in content["error"]
189+
finally:
190+
# Restore original tool_map
191+
agent.tool_map = original_tool_map

0 commit comments

Comments
 (0)