11import unittest
22from unittest .mock import patch , MagicMock , mock_open
33from tools .llm_api import create_llm_client , query_llm , load_environment
4+ from tools .token_tracker import TokenUsage , APIResponse
45import os
56import google .generativeai as genai
67import io
78import sys
89
9- def is_llm_configured ():
10- """Check if LLM is configured by trying to connect to the server"""
11- try :
12- client = create_llm_client ()
13- response = query_llm ("test" , client )
14- return response is not None
15- except :
16- return False
17-
18- # Skip all LLM tests if LLM is not configured
19- skip_llm_tests = not is_llm_configured ()
20- skip_message = "Skipping LLM tests as LLM is not configured. This is normal if you haven't set up a local LLM server."
21-
2210class TestEnvironmentLoading (unittest .TestCase ):
2311 def setUp (self ):
2412 # Save original environment
@@ -87,23 +75,43 @@ def setUp(self):
8775 # Create mock clients for different providers
8876 self .mock_openai_client = MagicMock ()
8977 self .mock_anthropic_client = MagicMock ()
78+ self .mock_azure_client = MagicMock ()
9079 self .mock_gemini_client = MagicMock ()
9180
92- # Set up OpenAI-style response
81+ # Set up mock responses
9382 self .mock_openai_response = MagicMock ()
94- self .mock_openai_choice = MagicMock ()
95- self .mock_openai_message = MagicMock ()
96- self .mock_openai_message .content = "Test OpenAI response"
97- self .mock_openai_choice .message = self .mock_openai_message
98- self .mock_openai_response .choices = [self .mock_openai_choice ]
99- self .mock_openai_client .chat .completions .create .return_value = self .mock_openai_response
100-
101- # Set up Anthropic-style response
83+ self .mock_openai_response .choices = [MagicMock ()]
84+ self .mock_openai_response .choices [0 ].message = MagicMock ()
85+ self .mock_openai_response .choices [0 ].message .content = "Test OpenAI response"
86+ self .mock_openai_response .usage = TokenUsage (
87+ prompt_tokens = 10 ,
88+ completion_tokens = 5 ,
89+ total_tokens = 15 ,
90+ reasoning_tokens = None
91+ )
92+
10293 self .mock_anthropic_response = MagicMock ()
103- self .mock_anthropic_content = MagicMock ()
104- self .mock_anthropic_content .text = "Test Anthropic response"
105- self .mock_anthropic_response .content = [self .mock_anthropic_content ]
94+ self .mock_anthropic_response .content = [MagicMock ()]
95+ self .mock_anthropic_response .content [0 ].text = "Test Anthropic response"
96+ self .mock_anthropic_response .usage = MagicMock ()
97+ self .mock_anthropic_response .usage .input_tokens = 10
98+ self .mock_anthropic_response .usage .output_tokens = 5
99+
100+ self .mock_azure_response = MagicMock ()
101+ self .mock_azure_response .choices = [MagicMock ()]
102+ self .mock_azure_response .choices [0 ].message = MagicMock ()
103+ self .mock_azure_response .choices [0 ].message .content = "Test Azure OpenAI response"
104+ self .mock_azure_response .usage = TokenUsage (
105+ prompt_tokens = 10 ,
106+ completion_tokens = 5 ,
107+ total_tokens = 15 ,
108+ reasoning_tokens = None
109+ )
110+
111+ # Set up return values for mock clients
112+ self .mock_openai_client .chat .completions .create .return_value = self .mock_openai_response
106113 self .mock_anthropic_client .messages .create .return_value = self .mock_anthropic_response
114+ self .mock_azure_client .chat .completions .create .return_value = self .mock_azure_response
107115
108116 # Set up Gemini-style response
109117 self .mock_gemini_model = MagicMock ()
@@ -122,29 +130,17 @@ def setUp(self):
122130 'AZURE_OPENAI_MODEL_DEPLOYMENT' : 'test-model-deployment'
123131 })
124132 self .env_patcher .start ()
125-
126- # Set up Azure OpenAI mock
127- self .mock_azure_response = MagicMock ()
128- self .mock_azure_choice = MagicMock ()
129- self .mock_azure_message = MagicMock ()
130- self .mock_azure_message .content = "Test Azure OpenAI response"
131- self .mock_azure_choice .message = self .mock_azure_message
132- self .mock_azure_response .choices = [self .mock_azure_choice ]
133- self .mock_azure_client = MagicMock ()
134- self .mock_azure_client .chat .completions .create .return_value = self .mock_azure_response
135133
136134 def tearDown (self ):
137135 self .env_patcher .stop ()
138136
139- @unittest .skipIf (skip_llm_tests , skip_message )
140137 @patch ('tools.llm_api.OpenAI' )
141138 def test_create_openai_client (self , mock_openai ):
142139 mock_openai .return_value = self .mock_openai_client
143140 client = create_llm_client ("openai" )
144141 mock_openai .assert_called_once_with (api_key = 'test-openai-key' )
145142 self .assertEqual (client , self .mock_openai_client )
146143
147- @unittest .skipIf (skip_llm_tests , skip_message )
148144 @patch ('tools.llm_api.AzureOpenAI' )
149145 def test_create_azure_client (self , mock_azure ):
150146 mock_azure .return_value = self .mock_azure_client
@@ -156,7 +152,6 @@ def test_create_azure_client(self, mock_azure):
156152 )
157153 self .assertEqual (client , self .mock_azure_client )
158154
159- @unittest .skipIf (skip_llm_tests , skip_message )
160155 @patch ('tools.llm_api.OpenAI' )
161156 def test_create_deepseek_client (self , mock_openai ):
162157 mock_openai .return_value = self .mock_openai_client
@@ -167,86 +162,67 @@ def test_create_deepseek_client(self, mock_openai):
167162 )
168163 self .assertEqual (client , self .mock_openai_client )
169164
170- @unittest .skipIf (skip_llm_tests , skip_message )
171165 @patch ('tools.llm_api.Anthropic' )
172166 def test_create_anthropic_client (self , mock_anthropic ):
173167 mock_anthropic .return_value = self .mock_anthropic_client
174168 client = create_llm_client ("anthropic" )
175169 mock_anthropic .assert_called_once_with (api_key = 'test-anthropic-key' )
176170 self .assertEqual (client , self .mock_anthropic_client )
177171
178- @unittest .skipIf (skip_llm_tests , skip_message )
179172 @patch ('tools.llm_api.genai' )
180173 def test_create_gemini_client (self , mock_genai ):
181174 client = create_llm_client ("gemini" )
182175 mock_genai .configure .assert_called_once_with (api_key = 'test-google-key' )
183176 self .assertEqual (client , mock_genai )
184177
185- @unittest .skipIf (skip_llm_tests , skip_message )
186- @patch ('tools.llm_api.OpenAI' )
187- def test_create_local_client (self , mock_openai ):
188- mock_openai .return_value = self .mock_openai_client
189- client = create_llm_client ("local" )
190- mock_openai .assert_called_once_with (
191- base_url = "http://192.168.180.137:8006/v1" ,
192- api_key = "not-needed"
193- )
194- self .assertEqual (client , self .mock_openai_client )
195-
196- @unittest .skipIf (skip_llm_tests , skip_message )
197178 def test_create_invalid_provider (self ):
198179 with self .assertRaises (ValueError ):
199180 create_llm_client ("invalid_provider" )
200181
201- @unittest .skipIf (skip_llm_tests , skip_message )
202- @patch ('tools.llm_api.create_llm_client' )
182+ @patch ('tools.llm_api.OpenAI' )
203183 def test_query_openai (self , mock_create_client ):
204184 mock_create_client .return_value = self .mock_openai_client
205- response = query_llm ("Test prompt" , provider = "openai" )
185+ response = query_llm ("Test prompt" , provider = "openai" , model = "gpt-4o" )
206186 self .assertEqual (response , "Test OpenAI response" )
207187 self .mock_openai_client .chat .completions .create .assert_called_once_with (
208188 model = "gpt-4o" ,
209189 messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}],
210190 temperature = 0.7
211191 )
212192
213- @unittest .skipIf (skip_llm_tests , skip_message )
214193 @patch ('tools.llm_api.create_llm_client' )
215194 def test_query_azure (self , mock_create_client ):
216195 mock_create_client .return_value = self .mock_azure_client
217- response = query_llm ("Test prompt" , provider = "azure" )
196+ response = query_llm ("Test prompt" , provider = "azure" , model = "gpt-4o" )
218197 self .assertEqual (response , "Test Azure OpenAI response" )
219198 self .mock_azure_client .chat .completions .create .assert_called_once_with (
220- model = os . getenv ( 'AZURE_OPENAI_MODEL_DEPLOYMENT' , ' gpt-4o-ms' ) ,
199+ model = " gpt-4o" ,
221200 messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}],
222201 temperature = 0.7
223202 )
224203
225- @unittest .skipIf (skip_llm_tests , skip_message )
226204 @patch ('tools.llm_api.create_llm_client' )
227205 def test_query_deepseek (self , mock_create_client ):
228206 mock_create_client .return_value = self .mock_openai_client
229- response = query_llm ("Test prompt" , provider = "deepseek" )
207+ response = query_llm ("Test prompt" , provider = "deepseek" , model = "gpt-4o" )
230208 self .assertEqual (response , "Test OpenAI response" )
231209 self .mock_openai_client .chat .completions .create .assert_called_once_with (
232- model = "deepseek-chat " ,
210+ model = "gpt-4o " ,
233211 messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}],
234212 temperature = 0.7
235213 )
236214
237- @unittest .skipIf (skip_llm_tests , skip_message )
238215 @patch ('tools.llm_api.create_llm_client' )
239216 def test_query_anthropic (self , mock_create_client ):
240217 mock_create_client .return_value = self .mock_anthropic_client
241- response = query_llm ("Test prompt" , provider = "anthropic" )
218+ response = query_llm ("Test prompt" , provider = "anthropic" , model = "claude-3-5-sonnet-20241022" )
242219 self .assertEqual (response , "Test Anthropic response" )
243220 self .mock_anthropic_client .messages .create .assert_called_once_with (
244- model = "claude-3-sonnet-20240229 " ,
221+ model = "claude-3-5- sonnet-20241022 " ,
245222 max_tokens = 1000 ,
246223 messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}]
247224 )
248225
249- @unittest .skipIf (skip_llm_tests , skip_message )
250226 @patch ('tools.llm_api.create_llm_client' )
251227 def test_query_gemini (self , mock_create_client ):
252228 mock_create_client .return_value = self .mock_gemini_client
@@ -255,35 +231,21 @@ def test_query_gemini(self, mock_create_client):
255231 self .mock_gemini_client .GenerativeModel .assert_called_once_with ("gemini-pro" )
256232 self .mock_gemini_model .generate_content .assert_called_once_with ("Test prompt" )
257233
258- @unittest .skipIf (skip_llm_tests , skip_message )
259- @patch ('tools.llm_api.create_llm_client' )
260- def test_query_local (self , mock_create_client ):
261- mock_create_client .return_value = self .mock_openai_client
262- response = query_llm ("Test prompt" , provider = "local" )
263- self .assertEqual (response , "Test OpenAI response" )
264- self .mock_openai_client .chat .completions .create .assert_called_once_with (
265- model = "Qwen/Qwen2.5-32B-Instruct-AWQ" ,
266- messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}],
267- temperature = 0.7
268- )
269-
270- @unittest .skipIf (skip_llm_tests , skip_message )
271234 @patch ('tools.llm_api.create_llm_client' )
272235 def test_query_with_custom_model (self , mock_create_client ):
273236 mock_create_client .return_value = self .mock_openai_client
274- response = query_llm ("Test prompt" , model = "custom-model " )
237+ response = query_llm ("Test prompt" , provider = "openai" , model = "gpt-4o " )
275238 self .assertEqual (response , "Test OpenAI response" )
276239 self .mock_openai_client .chat .completions .create .assert_called_once_with (
277- model = "custom-model " ,
240+ model = "gpt-4o " ,
278241 messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}],
279242 temperature = 0.7
280243 )
281244
282- @unittest .skipIf (skip_llm_tests , skip_message )
283245 @patch ('tools.llm_api.create_llm_client' )
284246 def test_query_o1_model (self , mock_create_client ):
285247 mock_create_client .return_value = self .mock_openai_client
286- response = query_llm ("Test prompt" , model = "o1" )
248+ response = query_llm ("Test prompt" , provider = "openai" , model = "o1" )
287249 self .assertEqual (response , "Test OpenAI response" )
288250 self .mock_openai_client .chat .completions .create .assert_called_once_with (
289251 model = "o1" ,
@@ -292,14 +254,16 @@ def test_query_o1_model(self, mock_create_client):
292254 reasoning_effort = "low"
293255 )
294256
295- @unittest .skipIf (skip_llm_tests , skip_message )
296257 @patch ('tools.llm_api.create_llm_client' )
297258 def test_query_with_existing_client (self , mock_create_client ):
298- response = query_llm ("Test prompt" , client = self .mock_openai_client )
259+ response = query_llm ("Test prompt" , client = self .mock_openai_client , model = "gpt-4o" )
299260 self .assertEqual (response , "Test OpenAI response" )
300- mock_create_client .assert_not_called ()
261+ self .mock_openai_client .chat .completions .create .assert_called_once_with (
262+ model = "gpt-4o" ,
263+ messages = [{"role" : "user" , "content" : [{"type" : "text" , "text" : "Test prompt" }]}],
264+ temperature = 0.7
265+ )
301266
302- @unittest .skipIf (skip_llm_tests , skip_message )
303267 @patch ('tools.llm_api.create_llm_client' )
304268 def test_query_error (self , mock_create_client ):
305269 self .mock_openai_client .chat .completions .create .side_effect = Exception ("Test error" )
0 commit comments