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