diff --git a/cms/djangoapps/contentstore/core/course_optimizer_provider.py b/cms/djangoapps/contentstore/core/course_optimizer_provider.py index 1f74025c9d4..2d9714be206 100644 --- a/cms/djangoapps/contentstore/core/course_optimizer_provider.py +++ b/cms/djangoapps/contentstore/core/course_optimizer_provider.py @@ -12,8 +12,14 @@ def generate_broken_links_descriptor(json_content, request_user): """ Returns a Data Transfer Object for frontend given a list of broken links. - json_content contains a list of [block_id, link, is_locked] - is_locked is true if the link is a studio link and returns 403 on request + ** Example json_content structure ** + Note: is_locked is true if the link is a studio link and returns 403 + [ + ['block_id_1', 'link_1', is_locked], + ['block_id_1', 'link_2', is_locked], + ['block_id_2', 'link_3', is_locked], + ... + ] ** Example DTO structure ** { @@ -100,9 +106,16 @@ def _update_node_tree_and_dictionary(block, link, is_locked, node_tree, dictiona ** Example dictionary structure ** { 'xblock_id: { - 'display_name': 'xblock name' - 'category': 'html' + 'display_name': 'xblock name', + 'category': 'chapter' }, + 'html_block_id': { + 'display_name': 'xblock name', + 'category': 'chapter', + 'url': 'url_1', + 'locked_links': [...], + 'broken_links': [...] + } ..., } """ diff --git a/cms/djangoapps/contentstore/core/tests/test_course_optimizer_provider.py b/cms/djangoapps/contentstore/core/tests/test_course_optimizer_provider.py index 1bd1c6ef2f3..aa78c2fe485 100644 --- a/cms/djangoapps/contentstore/core/tests/test_course_optimizer_provider.py +++ b/cms/djangoapps/contentstore/core/tests/test_course_optimizer_provider.py @@ -18,8 +18,15 @@ class TestLinkCheck(CourseTestCase): Tests for the link check functionality """ def setUp(self): + """Setup for tests""" global MOCK_TREE global MOCK_XBLOCK_DICTIONARY + global MOCK_COURSE + global MOCK_SECTION + global MOCK_SUBSECTION + global MOCK_UNIT + global MOCK_BLOCK + MOCK_TREE = { 'chapter_1': { 'sequential_1': { @@ -29,39 +36,110 @@ def setUp(self): } } } + MOCK_XBLOCK_DICTIONARY = { 'chapter_1': { - 'display_name': 'Chapter 1', + 'display_name': 'Section Name', 'category': 'chapter' }, 'sequential_1': { - 'display_name': 'Sequential 1', + 'display_name': 'Subsection Name', 'category': 'sequential' }, 'vertical_1': { - 'display_name': 'Vertical 1', + 'display_name': 'Unit Name', 'category': 'vertical' }, 'block_1': { - 'display_name': 'Block 1', + 'display_name': 'Block Name', 'url': '/block/1', 'broken_links': ['broken_link_1', 'broken_link_2'], 'locked_links': ['locked_link'] } } + MOCK_COURSE = Mock() + MOCK_SECTION = Mock( + location=Mock(block_id='chapter_1'), + display_name='Section Name', + category='chapter' + ) + MOCK_SUBSECTION = Mock( + location=Mock(block_id='sequential_1'), + display_name='Subsection Name', + category='sequential' + ) + MOCK_UNIT = Mock( + location=Mock(block_id='vertical_1'), + display_name='Unit Name', + category='vertical' + ) + MOCK_BLOCK = Mock( + location=Mock(block_id='block_1'), + display_name='Block Name', + course_id='course-v1:test+course', + category='html' + ) + # MOCK_BLOCK.location.__str__.return_value = 'block_location_str' + MOCK_COURSE.get_parent.return_value = None + MOCK_SECTION.get_parent.return_value = MOCK_COURSE + MOCK_SUBSECTION.get_parent.return_value = MOCK_SECTION + MOCK_UNIT.get_parent.return_value = MOCK_SUBSECTION + MOCK_BLOCK.get_parent.return_value = MOCK_UNIT + + + def test_update_node_tree_and_dictionary(self): + """Test _update_node_tree_and_dictionary""" + expected_tree = MOCK_TREE + expected_dictionary = { + 'chapter_1': { + 'display_name': 'Section Name', + 'category': 'chapter' + }, + 'sequential_1': { + 'display_name': 'Subsection Name', + 'category': 'sequential' + }, + 'vertical_1': { + 'display_name': 'Unit Name', + 'category': 'vertical' + }, + 'block_1': { + 'display_name': 'Block Name', + 'category': 'html', + 'url': f'/course/{MOCK_BLOCK.course_id}/editor/html/{MOCK_BLOCK.location}', + 'locked_links': ['example_link'] + } + } + + result_tree, result_dictionary = _update_node_tree_and_dictionary( + MOCK_BLOCK, 'example_link', True, {}, {} + ) + + self.assertEqual(expected_tree, result_tree) + self.assertEqual(expected_dictionary, result_dictionary) + + + def test_get_node_path(self): + """Tests _get_node_path""" + expected_result = [MOCK_SECTION, MOCK_SUBSECTION, MOCK_UNIT, MOCK_BLOCK] + result = _get_node_path(MOCK_BLOCK) + self.assertEqual(expected_result, result) + - def test_recursive_empty(self): + def test_create_dto_recursive_empty(self): + """Tests _create_dto_from_node_tree_recursive""" expected = _create_dto_from_node_tree_recursive({}, {}) self.assertEqual(None, expected) - def test_recursive_leaf_node(self): + def test_create_dto_recursive_leaf_node(self): + """Tests _create_dto_from_node_tree_recursive""" expected_result = { 'blocks': [ { 'id': 'block_1', - 'displayName': 'Block 1', + 'displayName': 'Block Name', 'url': '/block/1', 'brokenLinks': ['broken_link_1', 'broken_link_2'], 'lockedLinks': ['locked_link'] @@ -75,24 +153,25 @@ def test_recursive_leaf_node(self): self.assertEqual(expected_result, expected) - def test_recursive_full_tree(self): + def test_create_dto_recursive_full_tree(self): + """Tests _create_dto_from_node_tree_recursive""" expected_result = { 'sections': [ { 'id': 'chapter_1', - 'displayName': 'Chapter 1', + 'displayName': 'Section Name', 'subsections': [ { 'id': 'sequential_1', - 'displayName': 'Sequential 1', + 'displayName': 'Subsection Name', 'units': [ { 'id': 'vertical_1', - 'displayName': 'Vertical 1', + 'displayName': 'Unit Name', 'blocks': [ { 'id': 'block_1', - 'displayName': 'Block 1', + 'displayName': 'Block Name', 'url': '/block/1', 'brokenLinks': ['broken_link_1', 'broken_link_2'], 'lockedLinks': ['locked_link'] @@ -108,134 +187,4 @@ def test_recursive_full_tree(self): expected = _create_dto_from_node_tree_recursive(MOCK_TREE, MOCK_XBLOCK_DICTIONARY) self.assertEqual(expected_result, expected) - - - def test_get_node_path(self): - mock_course = Mock() - mock_section = Mock( - location=Mock(block_id='section_id'), - display_name='Section Name' - ) - mock_subsection = Mock( - location=Mock(block_id='subsection_id'), - display_name='Subsection Name' - ) - mock_unit = Mock( - location=Mock(block_id='unit_id'), - display_name='Unit Name' - ) - mock_block = Mock( - course_id='course-v1:test+course+2024', - location=Mock(block_id='block_id'), - display_name='Block Name', - category='html' - ) - mock_course.get_parent.return_value = None - mock_section.get_parent.return_value = mock_course - mock_subsection.get_parent.return_value = mock_section - mock_unit.get_parent.return_value = mock_subsection - mock_block.get_parent.return_value = mock_unit - - expected_result = [mock_course, mock_section, mock_subsection, mock_unit, mock_block] - - result = _get_node_path(mock_unit) - self.assertEqual(expected_result, result) - - - # @patch('cms.djangoapps.contentstore.core.course_optimizer_provider._create_dto_from_node_tree_recursive') - @patch('cms.djangoapps.contentstore.core.course_optimizer_provider._update_node_tree_and_dictionary') - @patch('cms.djangoapps.contentstore.core.course_optimizer_provider.get_xblock') - @patch('cms.djangoapps.contentstore.core.course_optimizer_provider.usage_key_with_run') - def test_generate_broken_links_descriptor_returns_correct_result( - self, - mock_usage_key_with_run, - mock_get_xblock, - mock_update_node_tree_and_dictionary, - # mock_create_dto_from_node_tree_recursive - ): - """ - Test generate_broken_links_descriptor to return expected dto - """ - # Mock data - mock_course = Mock() - mock_section = Mock( - location=Mock(block_id='section_id'), - display_name='Section Name' - ) - mock_section.get_parent.side_effect = mock_course - mock_subsection = Mock( - location=Mock(block_id='subsection_id'), - display_name='Subsection Name' - ) - mock_subsection.get_parent.side_effect = mock_section - mock_unit = Mock( - location=Mock(block_id='unit_id'), - display_name='Unit Name' - ) - mock_unit.get_parent.side_effect = mock_subsection - mock_block = Mock( - course_id='course-v1:test+course+2024', - location=Mock(block_id='block_id'), - display_name='Block Name' - ) - mock_block.get_parent.side_effect = mock_unit - mock_block.category = 'html' - # mock_block.get_parent.side_effect = [ - # Mock(location=Mock(block_id="unit_id"), display_name="Unit Name"), - # Mock(location=Mock(block_id="subsection_id"), display_name="Subsection Name"), - # Mock(location=Mock(block_id="section_id"), display_name="Section Name"), - # None, - # ] - - # Mock functions - mock_usage_key_with_run.return_value = "mock_usage_key" - mock_get_xblock.return_value = mock_block - mock_update_node_tree_and_dictionary.return_value = Mock() - # mock_create_dto_from_node_tree_recursive.return_value = 'test' - - # Mock input - mock_json_content = [ - ["block_id", "http://example.com/broken-link1", False], - ["block_id", "http://example.com/locked-link1", True], - ["block_id", "http://example.com/broken-link2", False], - ] - request_user = Mock() - - # Expected output - expected_result = { - 'sections': [ - { - 'id': 'section_id', - 'displayName': 'Section Name', - 'subsections': [ - { - 'id': 'subsection_id', - 'displayName': 'Subsection Name', - 'units': [ - { - 'id': 'unit_id', - 'displayName': 'Unit Name', - 'blocks': [ - { - 'id': 'block_id', - 'displayName': 'Block Name', - 'url': '/course/course-v1:test+course+2024/editor/html/mock_usage_key', - 'brokenLinks': [ - "http://example.com/broken-link1", - "http://example.com/broken-link2", - ], - 'lockedLinks': ["http://example.com/broken-link1"], - }, - ] - } - ] - } - ] - } - ] - } - - # Call the function - result = generate_broken_links_descriptor(mock_json_content, request_user) - - self.assertEqual(result, expected_result) + \ No newline at end of file