|
3 | 3 | """ |
4 | 4 | from contextlib import contextmanager |
5 | 5 | from datetime import datetime, timedelta |
6 | | -from unittest.mock import patch |
| 6 | +from unittest.mock import patch, call |
7 | 7 |
|
8 | 8 | import ddt |
9 | 9 | from Cryptodome.PublicKey import RSA |
|
12 | 12 | from django.utils import timezone |
13 | 13 | from edx_django_utils.cache import RequestCache |
14 | 14 | from jwkest.jwk import RSAKey |
| 15 | +from ccx_keys.locator import CCXBlockUsageLocator |
15 | 16 | from opaque_keys.edx.locator import CourseLocator |
16 | 17 |
|
17 | 18 | from lti_consumer.lti_xblock import LtiConsumerXBlock |
@@ -415,6 +416,80 @@ def test_get_redirect_uris_for_db_model_returns_expected( |
415 | 416 |
|
416 | 417 | assert self.lti_1p3_config_db.get_lti_1p3_redirect_uris() == expected |
417 | 418 |
|
| 419 | + @patch.object(LtiConfiguration, 'sync_configurations') |
| 420 | + def test_save(self, sync_configurations_mock): |
| 421 | + """Test save method.""" |
| 422 | + self.assertEqual(self.lti_1p3_config.save(), None) |
| 423 | + sync_configurations_mock.assert_called_once_with() |
| 424 | + |
| 425 | + @patch('lti_consumer.models.isinstance', return_value=True) |
| 426 | + @patch.object(LtiConfiguration.objects, 'filter') |
| 427 | + @patch('lti_consumer.models.model_to_dict') |
| 428 | + @patch('lti_consumer.models.setattr') |
| 429 | + def test_sync_configurations_with_ccx_location( |
| 430 | + self, |
| 431 | + setattr_mock, |
| 432 | + model_to_dict_mock, |
| 433 | + filter_mock, |
| 434 | + isinstance_mock, |
| 435 | + ): |
| 436 | + """ |
| 437 | + Test sync_configurations method with CCX location. |
| 438 | + """ |
| 439 | + model_to_dict_mock.return_value = {'test': 'test'} |
| 440 | + self.lti_1p3_config.location = 'ccx-block-v1:course+test+2020+ccx@1+type@problem+block@test' |
| 441 | + |
| 442 | + self.assertEqual(self.lti_1p3_config.sync_configurations(), None) |
| 443 | + isinstance_mock.assert_called_once_with(self.lti_1p3_config.location, CCXBlockUsageLocator) |
| 444 | + filter_mock.assert_has_calls([ |
| 445 | + call(location=self.lti_1p3_config.location.to_block_locator()), |
| 446 | + call().first(), |
| 447 | + ]) |
| 448 | + model_to_dict_mock.assert_called_once_with(filter_mock.return_value.first(), ['id', 'config_id', 'location']) |
| 449 | + setattr_mock.assert_called_once_with(self.lti_1p3_config, 'test', 'test') |
| 450 | + |
| 451 | + @patch('lti_consumer.models.isinstance', return_value=False) |
| 452 | + @patch.object(LtiConfiguration.objects, 'filter') |
| 453 | + @patch('lti_consumer.models.model_to_dict') |
| 454 | + def test_sync_configurations_with_location( |
| 455 | + self, |
| 456 | + model_to_dict_mock, |
| 457 | + filter_mock, |
| 458 | + isinstance_mock, |
| 459 | + ): |
| 460 | + """ |
| 461 | + Test sync_configurations method with location. |
| 462 | + """ |
| 463 | + self.assertEqual(self.lti_1p3_config.sync_configurations(), None) |
| 464 | + isinstance_mock.assert_called_once_with(self.lti_1p3_config.location, CCXBlockUsageLocator) |
| 465 | + filter_mock.assert_has_calls([ |
| 466 | + call(location__endswith=str(self.lti_1p3_config.location).split('@')[-1]), |
| 467 | + call().filter(location__startswith=CCXBlockUsageLocator.CANONICAL_NAMESPACE), |
| 468 | + call().filter().exclude(id=self.lti_1p3_config.pk), |
| 469 | + call().filter().exclude().update(**model_to_dict_mock), |
| 470 | + ]) |
| 471 | + model_to_dict_mock.assert_called_once_with(self.lti_1p3_config, ['id', 'config_id', 'location']) |
| 472 | + |
| 473 | + @patch('lti_consumer.models.isinstance', return_value=False) |
| 474 | + @patch.object(LtiConfiguration.objects, 'filter', side_effect=IndexError()) |
| 475 | + @patch('lti_consumer.models.log.exception') |
| 476 | + def test_sync_configurations_with_invalid_location( |
| 477 | + self, |
| 478 | + log_exception_mock, |
| 479 | + filter_mock, |
| 480 | + isinstance_mock, |
| 481 | + ): |
| 482 | + """ |
| 483 | + Test sync_configurations method with invalid location. |
| 484 | + """ |
| 485 | + self.assertEqual(self.lti_1p3_config.sync_configurations(), None) |
| 486 | + isinstance_mock.assert_called_once_with(self.lti_1p3_config.location, CCXBlockUsageLocator) |
| 487 | + filter_mock.assert_called_once_with(location__endswith=str(self.lti_1p3_config.location).split('@')[-1]) |
| 488 | + log_exception_mock.assert_called_once_with( |
| 489 | + f'Failed to query children CCX LTI configurations: ' |
| 490 | + f'Failed to parse main LTI configuration location: {self.lti_1p3_config.location}' |
| 491 | + ) |
| 492 | + |
418 | 493 |
|
419 | 494 | class TestLtiAgsLineItemModel(TestCase): |
420 | 495 | """ |
|
0 commit comments