|
13 | 13 |
|
14 | 14 | from learning_assistant.constants import LMS_DATETIME_FORMAT |
15 | 15 | from learning_assistant.utils import ( |
| 16 | + extract_message_content, |
16 | 17 | get_audit_trial_length_days, |
17 | 18 | get_chat_response, |
18 | 19 | get_optimizely_variation, |
@@ -148,6 +149,31 @@ def test_post_request_structure_v2_endpoint(self, mock_requests, mock_v2_enabled |
148 | 149 | timeout=(connect_timeout, read_timeout) |
149 | 150 | ) |
150 | 151 |
|
| 152 | + @ddt.data( |
| 153 | + # (v2_enabled, response_data, description) |
| 154 | + (False, {'role': 'assistant', 'content': 'v1 response'}, 'v1 single dict'), |
| 155 | + (True, [{'role': 'assistant', 'content': 'v2 response'}], 'v2 array of dicts'), |
| 156 | + (True, {'role': 'assistant', 'content': 'v2 dict'}, 'v2 unexpected dict format'), |
| 157 | + ) |
| 158 | + @ddt.unpack |
| 159 | + @responses.activate |
| 160 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 161 | + def test_endpoint_response_formats(self, v2_enabled, response_data, description, mock_v2_enabled): |
| 162 | + """Test that both v1 and v2 endpoint response formats are handled correctly.""" |
| 163 | + mock_v2_enabled.return_value = v2_enabled |
| 164 | + |
| 165 | + endpoint = settings.CHAT_COMPLETION_API_V2 if v2_enabled else settings.CHAT_COMPLETION_API |
| 166 | + responses.add( |
| 167 | + responses.POST, |
| 168 | + endpoint, |
| 169 | + status=200, |
| 170 | + body=json.dumps(response_data), |
| 171 | + ) |
| 172 | + |
| 173 | + status_code, message = self.get_response() |
| 174 | + self.assertEqual(status_code, 200, f"Failed for {description}") |
| 175 | + self.assertEqual(message, response_data, f"Response mismatch for {description}") |
| 176 | + |
151 | 177 |
|
152 | 178 | class GetReducedMessageListTests(TestCase): |
153 | 179 | """ |
@@ -225,7 +251,9 @@ def test_get_audit_trial_length_days_no_setting(self): |
225 | 251 | ) |
226 | 252 | @ddt.unpack |
227 | 253 | @patch('learning_assistant.utils.get_optimizely_variation') |
228 | | - def test_get_audit_trial_length_days_experiment(self, variation_key, expected_value, mock_get_optimizely_variation): |
| 254 | + def test_get_audit_trial_length_days_experiment( |
| 255 | + self, variation_key, expected_value, mock_get_optimizely_variation |
| 256 | + ): |
229 | 257 | mock_get_optimizely_variation.return_value = {'enabled': True, 'variation_key': variation_key} |
230 | 258 | with patch.object(settings, 'OPTIMIZELY_LEARNING_ASSISTANT_TRIAL_VARIATION_KEY_28', 'variation'): |
231 | 259 | self.assertEqual(get_audit_trial_length_days(1, 'verified'), expected_value) |
@@ -273,3 +301,107 @@ def test_wrong_date(self): |
273 | 301 | response = parse_lms_datetime('when I get my homework done') |
274 | 302 |
|
275 | 303 | self.assertEqual(response, expected_value) |
| 304 | + |
| 305 | + |
| 306 | +@ddt.ddt |
| 307 | +class ExtractMessageContentTests(TestCase): |
| 308 | + """ |
| 309 | + Tests for the extract_message_content utility function |
| 310 | + """ |
| 311 | + |
| 312 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 313 | + def test_v2_endpoint_with_list_dict_message(self, mock_v2_enabled): |
| 314 | + """Test v2 endpoint with list containing dict messages""" |
| 315 | + mock_v2_enabled.return_value = True |
| 316 | + |
| 317 | + message = [ |
| 318 | + {'role': 'assistant', 'content': 'First message'}, |
| 319 | + {'role': 'assistant', 'content': 'Last message'} |
| 320 | + ] |
| 321 | + |
| 322 | + result = extract_message_content(message) |
| 323 | + self.assertEqual(result, 'Last message') |
| 324 | + |
| 325 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 326 | + def test_v2_endpoint_with_list_non_dict_message(self, mock_v2_enabled): |
| 327 | + """Test v2 endpoint with list containing non-dict messages""" |
| 328 | + mock_v2_enabled.return_value = True |
| 329 | + |
| 330 | + message = ['First message', 'Last message'] |
| 331 | + |
| 332 | + result = extract_message_content(message) |
| 333 | + self.assertEqual(result, 'Last message') |
| 334 | + |
| 335 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 336 | + def test_v2_endpoint_with_empty_list(self, mock_v2_enabled): |
| 337 | + """Test v2 endpoint with empty list""" |
| 338 | + mock_v2_enabled.return_value = True |
| 339 | + |
| 340 | + message = [] |
| 341 | + |
| 342 | + result = extract_message_content(message) |
| 343 | + self.assertEqual(result, '') |
| 344 | + |
| 345 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 346 | + def test_v2_endpoint_with_dict_missing_content(self, mock_v2_enabled): |
| 347 | + """Test v2 endpoint with dict message missing content key""" |
| 348 | + mock_v2_enabled.return_value = True |
| 349 | + |
| 350 | + message = [{'role': 'assistant'}] |
| 351 | + |
| 352 | + result = extract_message_content(message) |
| 353 | + self.assertEqual(result, '') |
| 354 | + |
| 355 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 356 | + def test_v1_endpoint_with_dict_message(self, mock_v2_enabled): |
| 357 | + """Test v1 endpoint with dict message containing content""" |
| 358 | + mock_v2_enabled.return_value = False |
| 359 | + |
| 360 | + message = {'role': 'assistant', 'content': 'v1 response'} |
| 361 | + |
| 362 | + result = extract_message_content(message) |
| 363 | + self.assertEqual(result, 'v1 response') |
| 364 | + |
| 365 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 366 | + def test_v1_endpoint_with_dict_missing_content(self, mock_v2_enabled): |
| 367 | + """Test v1 endpoint with dict message missing content key""" |
| 368 | + mock_v2_enabled.return_value = False |
| 369 | + |
| 370 | + message = {'role': 'assistant'} |
| 371 | + |
| 372 | + result = extract_message_content(message) |
| 373 | + self.assertEqual(result, "{'role': 'assistant'}") |
| 374 | + |
| 375 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 376 | + def test_fallback_with_string_message(self, mock_v2_enabled): |
| 377 | + """Test fallback case with string message""" |
| 378 | + mock_v2_enabled.return_value = False |
| 379 | + |
| 380 | + message = 'Error: Something went wrong' |
| 381 | + |
| 382 | + result = extract_message_content(message) |
| 383 | + self.assertEqual(result, 'Error: Something went wrong') |
| 384 | + |
| 385 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 386 | + def test_fallback_with_none_message(self, mock_v2_enabled): |
| 387 | + """Test fallback case with None message""" |
| 388 | + mock_v2_enabled.return_value = False |
| 389 | + |
| 390 | + message = None |
| 391 | + |
| 392 | + result = extract_message_content(message) |
| 393 | + self.assertEqual(result, 'None') |
| 394 | + |
| 395 | + @patch('learning_assistant.utils.v2_endpoint_enabled') |
| 396 | + def test_v2_endpoint_mixed_message_types(self, mock_v2_enabled): |
| 397 | + """Test v2 endpoint with mixed message types in list""" |
| 398 | + mock_v2_enabled.return_value = True |
| 399 | + |
| 400 | + message = [ |
| 401 | + 'First string message', |
| 402 | + {'role': 'assistant', 'content': 'Dict message'}, |
| 403 | + 'Last string message' |
| 404 | + ] |
| 405 | + |
| 406 | + result = extract_message_content(message) |
| 407 | + self.assertEqual(result, 'Last string message') |
0 commit comments