Skip to content

Commit 2a62dfb

Browse files
committed
tests
1 parent 9922bf9 commit 2a62dfb

File tree

4 files changed

+830
-0
lines changed

4 files changed

+830
-0
lines changed

tests/unit/codegen/agents/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Unit tests for codegen.agents package
+308
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
import pytest
2+
from unittest.mock import MagicMock, patch
3+
from typing import Dict, Any
4+
import os # Add missing import for os module
5+
6+
from codegen.agents.agent import Agent, AgentTask
7+
from codegen.agents.client.openapi_client.api_client import ApiClient
8+
from codegen.agents.client.openapi_client.models.agent_run_response import AgentRunResponse
9+
from codegen.agents.client.openapi_client.api.agents_api import AgentsApi
10+
from codegen.agents.client.openapi_client.configuration import Configuration
11+
from codegen.agents.constants import CODEGEN_BASE_API_URL
12+
13+
14+
class TestAgentTask:
15+
16+
@pytest.fixture
17+
def agent_run_response(self):
18+
"""Create a mock AgentRunResponse"""
19+
mock_response = MagicMock(spec=AgentRunResponse)
20+
mock_response.id = "123" # Keep as string as this is likely the format from API
21+
mock_response.status = "running"
22+
mock_response.result = None
23+
mock_response.web_url = "https://example.com/run/123"
24+
return mock_response
25+
26+
@pytest.fixture
27+
def api_client(self):
28+
"""Create a mock ApiClient"""
29+
mock_client = MagicMock() # Remove spec to allow dynamic attributes
30+
mock_client.configuration = MagicMock() # Create configuration attribute
31+
mock_client.configuration.access_token = "test-token"
32+
return mock_client
33+
34+
@pytest.fixture
35+
def mock_agents_api(self):
36+
"""Create a proper mock for the AgentsApi"""
37+
# Create a proper mock with a get method
38+
mock_api = MagicMock(spec=AgentsApi)
39+
return mock_api
40+
41+
@pytest.fixture
42+
def agent_task(self, agent_run_response, api_client, mock_agents_api):
43+
"""Create an AgentTask instance with mock dependencies"""
44+
# Patch the AgentsApi constructor to return our mock
45+
with patch('codegen.agents.agent.AgentsApi', return_value=mock_agents_api):
46+
task = AgentTask(agent_run_response, api_client, org_id=42)
47+
return task
48+
49+
def test_init(self, agent_task, agent_run_response, api_client, mock_agents_api):
50+
"""Test initialization of AgentTask"""
51+
assert agent_task.id == "123"
52+
assert agent_task.org_id == 42
53+
assert agent_task.status == "running"
54+
assert agent_task.result is None
55+
assert agent_task.web_url == "https://example.com/run/123"
56+
assert agent_task._api_client == api_client
57+
assert agent_task._agents_api == mock_agents_api
58+
59+
def test_refresh_without_id(self, agent_task, mock_agents_api):
60+
"""Test refresh method when job ID is None"""
61+
agent_task.id = None
62+
# Should return early without making API call
63+
agent_task.refresh()
64+
mock_agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get.assert_not_called()
65+
66+
def test_refresh_with_id(self, agent_task, mock_agents_api):
67+
"""Test refresh method updates job status"""
68+
# Setup mock API response
69+
mock_updated_response = {
70+
"status": "completed",
71+
"result": {"output": "Success!"}
72+
}
73+
mock_agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get.return_value = mock_updated_response
74+
75+
# Call refresh
76+
agent_task.refresh()
77+
78+
# Verify API was called with correct params
79+
mock_agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get.assert_called_once_with(
80+
agent_run_id="123", # Use string ID as stored in agent_task.id
81+
org_id=42,
82+
authorization="Bearer test-token"
83+
)
84+
85+
# Verify status was updated
86+
assert agent_task.status == "completed"
87+
assert agent_task.result == {"output": "Success!"}
88+
89+
def test_refresh_with_dict_response(self, agent_task, mock_agents_api):
90+
"""Test refresh method when API returns dict instead of object"""
91+
# Setup mock API response as dict
92+
mock_updated_response = {
93+
"status": "failed",
94+
"result": {"error": "Something went wrong"}
95+
}
96+
mock_agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get.return_value = mock_updated_response
97+
98+
# Call refresh
99+
agent_task.refresh()
100+
101+
# Verify status was updated
102+
assert agent_task.status == "failed"
103+
assert agent_task.result == {"error": "Something went wrong"}
104+
105+
106+
class TestAgent:
107+
108+
@pytest.fixture
109+
def mock_api_client(self):
110+
"""Create a mock ApiClient"""
111+
with patch("codegen.agents.agent.ApiClient") as mock_client_class:
112+
mock_client = MagicMock() # Remove spec to allow dynamic attributes
113+
mock_client.configuration = MagicMock() # Create configuration attribute
114+
mock_client.configuration.access_token = "test-token"
115+
mock_client_class.return_value = mock_client
116+
yield mock_client
117+
118+
@pytest.fixture
119+
def mock_agents_api(self):
120+
"""Create a mock AgentsApi"""
121+
with patch("codegen.agents.agent.AgentsApi") as mock_api_class:
122+
mock_api = MagicMock(spec=AgentsApi)
123+
mock_api_class.return_value = mock_api
124+
yield mock_api
125+
126+
@pytest.fixture
127+
def agent(self, mock_api_client, mock_agents_api):
128+
"""Create an Agent instance with mock dependencies"""
129+
with patch.object(Configuration, "__init__", return_value=None) as mock_config:
130+
agent = Agent(token="test-token", org_id=42)
131+
# Verify config initialization
132+
mock_config.assert_called_once_with(host=CODEGEN_BASE_API_URL, access_token="test-token")
133+
return agent
134+
135+
def test_init_with_explicit_org_id(self, mock_api_client, mock_agents_api):
136+
"""Test initialization with explicitly provided org_id"""
137+
with patch.object(Configuration, "__init__", return_value=None):
138+
agent = Agent(token="test-token", org_id=42)
139+
assert agent.token == "test-token"
140+
assert agent.org_id == 42
141+
assert agent.api_client == mock_api_client
142+
assert agent.agents_api == mock_agents_api
143+
assert agent.current_job is None
144+
145+
def test_init_with_default_org_id(self, mock_api_client, mock_agents_api):
146+
"""Test initialization with default org_id"""
147+
with patch.object(Configuration, "__init__", return_value=None):
148+
with patch.dict("os.environ", {"CODEGEN_ORG_ID": "99"}):
149+
agent = Agent(token="test-token")
150+
assert agent.org_id == 99
151+
152+
def test_init_with_custom_base_url(self, mock_api_client):
153+
"""Test initialization with custom base URL"""
154+
with patch.object(Configuration, "__init__", return_value=None) as mock_config:
155+
custom_url = "https://custom-api.example.com"
156+
agent = Agent(token="test-token", org_id=42, base_url=custom_url)
157+
mock_config.assert_called_once_with(host=custom_url, access_token="test-token")
158+
159+
def test_run(self, agent, mock_agents_api):
160+
"""Test run method creates and returns job"""
161+
# Setup mock API response
162+
mock_run_response = MagicMock(spec=AgentRunResponse)
163+
mock_run_response.id = "123"
164+
mock_run_response.status = "running"
165+
mock_run_response.result = None
166+
mock_run_response.web_url = "https://example.com/run/123"
167+
mock_agents_api.create_agent_run_v1_organizations_org_id_agent_run_post.return_value = mock_run_response
168+
169+
# Call run
170+
job = agent.run("Test prompt")
171+
172+
# Verify API call
173+
mock_agents_api.create_agent_run_v1_organizations_org_id_agent_run_post.assert_called_once()
174+
call_args = mock_agents_api.create_agent_run_v1_organizations_org_id_agent_run_post.call_args
175+
assert call_args[1]["org_id"] == 42
176+
assert call_args[1]["authorization"] == "Bearer test-token"
177+
assert call_args[1]["_headers"] == {"Content-Type": "application/json"}
178+
assert call_args[1]["create_agent_run_input"].prompt == "Test prompt"
179+
180+
# Verify job
181+
assert isinstance(job, AgentTask)
182+
assert job.id == "123"
183+
assert job.status == "running"
184+
assert agent.current_job == job
185+
186+
def test_get_status_with_no_job(self, agent):
187+
"""Test get_status when no job has been run"""
188+
assert agent.get_status() is None
189+
190+
def test_get_status_with_job(self, agent):
191+
"""Test get_status returns current job status"""
192+
# Setup mock job
193+
mock_job = MagicMock(spec=AgentTask)
194+
mock_job.id = "123"
195+
mock_job.status = "completed"
196+
mock_job.result = {"output": "Success!"}
197+
mock_job.web_url = "https://example.com/run/123"
198+
199+
agent.current_job = mock_job
200+
201+
# Call get_status
202+
status = agent.get_status()
203+
204+
# Verify job was refreshed
205+
mock_job.refresh.assert_called_once()
206+
207+
# Verify status
208+
assert status == {
209+
"id": "123",
210+
"status": "completed",
211+
"result": {"output": "Success!"},
212+
"web_url": "https://example.com/run/123"
213+
}
214+
215+
216+
# Integration-like tests
217+
class TestAgentIntegration:
218+
219+
@pytest.fixture
220+
def mock_response(self):
221+
"""Create a mock response for API calls"""
222+
mock_response = MagicMock() # Remove spec=AgentRunResponse
223+
mock_response.id = "987"
224+
mock_response.status = "running"
225+
mock_response.result = None
226+
mock_response.web_url = "https://example.com/run/987"
227+
return mock_response
228+
229+
@pytest.fixture
230+
def mock_updated_response(self):
231+
"""Create a mock updated response for API calls"""
232+
mock_updated = {
233+
"id": "987",
234+
"status": "completed",
235+
"result": {"output": "Task completed successfully"},
236+
"web_url": "https://example.com/run/987"
237+
}
238+
239+
return mock_updated
240+
241+
def test_full_workflow(self, mock_response, mock_updated_response):
242+
"""Test a complete agent workflow from initialization to status check"""
243+
with patch("codegen.agents.agent.ApiClient") as mock_api_client_class, \
244+
patch("codegen.agents.agent.AgentsApi") as mock_agents_api_class, \
245+
patch.object(Configuration, "__init__", return_value=None):
246+
247+
# Setup mocks
248+
mock_api_client = MagicMock() # Remove spec to allow dynamic attributes
249+
mock_api_client.configuration = MagicMock() # Create configuration attribute
250+
mock_api_client.configuration.access_token = "test-token"
251+
mock_api_client_class.return_value = mock_api_client
252+
253+
# Setup agents API mock
254+
mock_agents_api = MagicMock(spec=AgentsApi)
255+
mock_agents_api.create_agent_run_v1_organizations_org_id_agent_run_post.return_value = mock_response
256+
mock_agents_api_class.return_value = mock_agents_api
257+
258+
# We're patching the same class for both the Agent and AgentTask
259+
mock_inner_agents_api = mock_agents_api
260+
mock_inner_agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get.return_value = mock_updated_response
261+
262+
# Initialize agent
263+
agent = Agent(token="test-token", org_id=123)
264+
265+
# Run agent
266+
job = agent.run("Execute this instruction")
267+
268+
# Verify job properties
269+
assert job.id == "987"
270+
assert job.status == "running"
271+
assert job.result is None
272+
273+
# Check status
274+
status = agent.get_status()
275+
276+
# Verify API calls
277+
mock_agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get.assert_called_once_with(
278+
agent_run_id="987", # Use string ID
279+
org_id=123,
280+
authorization="Bearer test-token"
281+
)
282+
283+
# Verify status
284+
assert isinstance(status, dict)
285+
assert status["id"] == "987"
286+
assert status["status"] == "completed"
287+
assert status["result"] == {"output": "Task completed successfully"}
288+
assert status["web_url"] == "https://example.com/run/987"
289+
290+
def test_exception_handling(self):
291+
"""Test handling of API exceptions during agent run"""
292+
with patch("codegen.agents.agent.ApiClient"), \
293+
patch("codegen.agents.agent.AgentsApi") as mock_agents_api_class, \
294+
patch.object(Configuration, "__init__", return_value=None):
295+
296+
# Setup API to raise exception
297+
mock_agents_api = MagicMock(spec=AgentsApi)
298+
mock_agents_api.create_agent_run_v1_organizations_org_id_agent_run_post.side_effect = Exception("API Error")
299+
mock_agents_api_class.return_value = mock_agents_api
300+
301+
# Initialize agent
302+
agent = Agent(token="test-token", org_id=123)
303+
304+
# Run agent and expect exception
305+
with pytest.raises(Exception) as excinfo:
306+
agent.run("Execute this instruction")
307+
308+
assert "API Error" in str(excinfo.value)

0 commit comments

Comments
 (0)