|
3 | 3 | """ |
4 | 4 |
|
5 | 5 | import json |
| 6 | +import logging |
6 | 7 | import urllib.parse |
7 | 8 | from datetime import timedelta |
8 | 9 | from unittest.mock import Mock, NonCallableMock, PropertyMock, patch |
9 | 10 |
|
10 | 11 | import ddt |
11 | 12 | from Cryptodome.PublicKey import RSA |
| 13 | +from django.conf import settings as dj_settings |
12 | 14 | from django.test.testcases import TestCase |
13 | 15 | from django.utils import timezone |
14 | 16 | from jwkest.jwk import RSAKey |
|
19 | 21 | from lti_consumer.lti_xblock import LtiConsumerXBlock, parse_handler_suffix |
20 | 22 | from lti_consumer.tests.unit import test_utils |
21 | 23 | from lti_consumer.tests.unit.test_utils import FAKE_USER_ID, make_request, make_xblock |
| 24 | +from lti_consumer.utils import resolve_custom_parameter_template |
22 | 25 |
|
23 | 26 | HTML_PROBLEM_PROGRESS = '<div class="problem-progress">' |
24 | 27 | HTML_ERROR_MESSAGE = '<h3 class="error_message">' |
@@ -301,6 +304,30 @@ def test_prefixed_custom_parameters(self): |
301 | 304 |
|
302 | 305 | self.assertEqual(params, expected_params) |
303 | 306 |
|
| 307 | + @patch('lti_consumer.lti_xblock.resolve_custom_parameter_template') |
| 308 | + def test_templated_custom_parameters(self, mock_resolve_custom_parameter_template): |
| 309 | + """ |
| 310 | + Test `prefixed_custom_parameters` when a custom parameter with templated value has been provided. |
| 311 | + """ |
| 312 | + now = timezone.now() |
| 313 | + one_day = timedelta(days=1) |
| 314 | + self.xblock.due = now |
| 315 | + self.xblock.graceperiod = one_day |
| 316 | + self.xblock.custom_parameters = ['dynamic_param_1=${template_value}', 'param_2=false'] |
| 317 | + mock_resolve_custom_parameter_template.return_value = 'resolved_template_value' |
| 318 | + expected_params = { |
| 319 | + 'custom_component_display_name': self.xblock.display_name, |
| 320 | + 'custom_component_due_date': now.strftime('%Y-%m-%d %H:%M:%S'), |
| 321 | + 'custom_component_graceperiod': str(one_day.total_seconds()), |
| 322 | + 'custom_dynamic_param_1': 'resolved_template_value', |
| 323 | + 'custom_param_2': 'false', |
| 324 | + } |
| 325 | + |
| 326 | + params = self.xblock.prefixed_custom_parameters |
| 327 | + |
| 328 | + self.assertEqual(params, expected_params) |
| 329 | + mock_resolve_custom_parameter_template.assert_called_once_with(self.xblock, '${template_value}') |
| 330 | + |
304 | 331 | def test_invalid_custom_parameter(self): |
305 | 332 | """ |
306 | 333 | Test `prefixed_custom_parameters` when a custom parameter has been configured with the wrong format |
@@ -1532,3 +1559,77 @@ def test_access_token(self): |
1532 | 1559 |
|
1533 | 1560 | response = self.xblock.lti_1p3_access_token(request) |
1534 | 1561 | self.assertEqual(response.status_code, 200) |
| 1562 | + |
| 1563 | + |
| 1564 | +@patch('lti_consumer.utils.log') |
| 1565 | +@patch('lti_consumer.utils.import_module') |
| 1566 | +class TestDynamicCustomParametersResolver(TestLtiConsumerXBlock): |
| 1567 | + """ |
| 1568 | + Unit tests for lti_xblock utils resolve_custom_parameter_template method. |
| 1569 | + """ |
| 1570 | + |
| 1571 | + def setUp(self): |
| 1572 | + super().setUp() |
| 1573 | + |
| 1574 | + self.logger = logging.getLogger() |
| 1575 | + dj_settings.LTI_CUSTOM_PARAM_TEMPLATES = { |
| 1576 | + 'templated_param_value': 'customer_package.module:func', |
| 1577 | + } |
| 1578 | + self.mock_processor_module = Mock(func=Mock()) |
| 1579 | + |
| 1580 | + def test_successful_resolve_custom_parameter_template(self, mock_import_module, *_): |
| 1581 | + """ |
| 1582 | + Test a successful module import and execution. The template value to be resolved |
| 1583 | + should be replaced by the processor. |
| 1584 | + """ |
| 1585 | + |
| 1586 | + custom_parameter_template_value = '${templated_param_value}' |
| 1587 | + expected_resolved_value = 'resolved_value' |
| 1588 | + mock_import_module.return_value = self.mock_processor_module |
| 1589 | + self.mock_processor_module.func.return_value = expected_resolved_value |
| 1590 | + |
| 1591 | + resolved_value = resolve_custom_parameter_template(self.xblock, custom_parameter_template_value) |
| 1592 | + |
| 1593 | + mock_import_module.assert_called_once() |
| 1594 | + self.assertEqual(resolved_value, expected_resolved_value) |
| 1595 | + |
| 1596 | + def test_resolve_custom_parameter_template_with_invalid_data_type_returned(self, mock_import_module, mock_log): |
| 1597 | + """ |
| 1598 | + Test a successful module import and execution. The value returned by the processor should be a string object. |
| 1599 | + Otherwise, it should log an error. |
| 1600 | + """ |
| 1601 | + |
| 1602 | + custom_parameter_template_value = '${templated_param_value}' |
| 1603 | + mock_import_module.return_value = self.mock_processor_module |
| 1604 | + self.mock_processor_module.func.return_value = 1 |
| 1605 | + |
| 1606 | + resolved_value = resolve_custom_parameter_template(self.xblock, custom_parameter_template_value) |
| 1607 | + |
| 1608 | + self.assertEqual(resolved_value, custom_parameter_template_value) |
| 1609 | + assert mock_log.error.called |
| 1610 | + |
| 1611 | + def test_resolve_custom_parameter_template_with_invalid_module(self, mock_import_module, mock_log): |
| 1612 | + """ |
| 1613 | + Test a failed import with an undefined module. This should log an error. |
| 1614 | + """ |
| 1615 | + mock_import_module.side_effect = ModuleNotFoundError |
| 1616 | + custom_parameter_template_value = '${not_defined_parameter_template}' |
| 1617 | + |
| 1618 | + resolved_value = resolve_custom_parameter_template(self.xblock, custom_parameter_template_value) |
| 1619 | + |
| 1620 | + self.assertEqual(resolved_value, custom_parameter_template_value) |
| 1621 | + assert mock_log.error.called |
| 1622 | + |
| 1623 | + def test_lti_custom_param_templates_not_configured(self, mock_import_module, mock_log): |
| 1624 | + """ |
| 1625 | + Test the feature with LTI_CUSTOM_PARAM_TEMPLATES setting attribute not configured. |
| 1626 | + """ |
| 1627 | + custom_parameter_template_value = '${templated_param_value}' |
| 1628 | + |
| 1629 | + dj_settings.__delattr__('LTI_CUSTOM_PARAM_TEMPLATES') |
| 1630 | + |
| 1631 | + resolved_value = resolve_custom_parameter_template(self.xblock, custom_parameter_template_value) |
| 1632 | + |
| 1633 | + self.assertEqual(resolved_value, custom_parameter_template_value) |
| 1634 | + assert mock_log.error.called |
| 1635 | + mock_import_module.asser_not_called() |
0 commit comments