diff --git a/lms/djangoapps/mobile_api/tests/test_course_info_views.py b/lms/djangoapps/mobile_api/tests/test_course_info_views.py index 5f9a48b96616..9d4c24f1bc18 100644 --- a/lms/djangoapps/mobile_api/tests/test_course_info_views.py +++ b/lms/djangoapps/mobile_api/tests/test_course_info_views.py @@ -480,3 +480,30 @@ def test_extend_block_info_with_offline_data( self.assertEqual(response.status_code, status.HTTP_200_OK) for block_info in response.data['blocks'].values(): self.assertDictEqual(block_info['offline_download'], expected_offline_download_data) + + @patch('lms.djangoapps.mobile_api.course_info.views.is_offline_mode_enabled') + @ddt.data( + ('v0.5', True), + ('v0.5', False), + ('v1', True), + ('v1', False), + ('v2', True), + ('v2', False), + ('v3', True), + ('v3', False), + ) + @ddt.unpack + def test_not_extend_block_info_with_offline_data_for_version_less_v4_and_any_waffle_flag( + self, + api_version: str, + offline_mode_waffle_flag_mock: MagicMock, + is_offline_mode_enabled_mock: MagicMock, + ) -> None: + url = reverse('blocks_info_in_course', kwargs={'api_version': api_version}) + is_offline_mode_enabled_mock.return_value = offline_mode_waffle_flag_mock + + response = self.verify_response(url=url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + for block_info in response.data['blocks'].values(): + self.assertNotIn('offline_download', block_info) diff --git a/openedx/features/offline_mode/tests/test_html_manipulator.py b/openedx/features/offline_mode/tests/test_html_manipulator.py index d085a0ebf8c3..a3e8c776ff32 100644 --- a/openedx/features/offline_mode/tests/test_html_manipulator.py +++ b/openedx/features/offline_mode/tests/test_html_manipulator.py @@ -84,13 +84,13 @@ def test_replace_static_links(self, save_asset_file_mock: MagicMock) -> None: @patch('openedx.features.offline_mode.html_manipulator.save_asset_file') def test_replace_asset_links(self, save_asset_file_mock: MagicMock) -> None: - html_data_mock = '
' + html_data_mock = '/assets/courseware/v1/5b628a18f2ee3303081ffe4d6ab64ee4/asset-v1:OpenedX+DemoX+DemoCourse+type@asset+block/Pendleton_Sinking_Ship.jpeg' # lint-amnesty, pylint: disable=line-too-long xblock_mock = Mock() temp_dir_mock = 'temp_dir_mock' html_manipulator = HtmlManipulator(xblock_mock, html_data_mock, temp_dir_mock) expected_html_data_after_replacing = ( - '
' + 'assets/courseware/v1/5b628a18f2ee3303081ffe4d6ab64ee4/asset-v1:OpenedX+DemoX+DemoCourse+type@asset+block/Pendleton_Sinking_Ship.jpeg' # lint-amnesty, pylint: disable=line-too-long ) self.assertEqual(html_manipulator.html_data, html_data_mock) @@ -100,8 +100,8 @@ def test_replace_asset_links(self, save_asset_file_mock: MagicMock) -> None: save_asset_file_mock.assert_called_once_with( html_manipulator.temp_dir, html_manipulator.xblock, - '/assets/images/professor-sandel.jpg', - 'assets/images/professor-sandel.jpg', + html_data_mock, + expected_html_data_after_replacing, ) self.assertEqual(html_manipulator.html_data, expected_html_data_after_replacing) diff --git a/openedx/features/offline_mode/tests/test_renderer.py b/openedx/features/offline_mode/tests/test_renderer.py index e9afe0a62507..91975c50990c 100644 --- a/openedx/features/offline_mode/tests/test_renderer.py +++ b/openedx/features/offline_mode/tests/test_renderer.py @@ -34,12 +34,13 @@ def setup_course(self): self.html_block = BlockFactory.create( # lint-amnesty, pylint: disable=attribute-defined-outside-init parent=self.vertical_block, category='html', - data="

Test HTML Content

" + display_name='HTML xblock for Offline', + data='

Test HTML Content

' ) self.problem_block = BlockFactory.create( # lint-amnesty, pylint: disable=attribute-defined-outside-init parent=self.vertical_block, category='problem', - display_name='Problem', + display_name='Problem xblock for Offline', data=problem_xml ) @@ -51,6 +52,8 @@ def test_render_xblock_from_lms_html_block(self): self.assertIsNotNone(result) self.assertEqual(type(result), str) + self.assertIn('HTML xblock for Offline', result) + self.assertIn('

Test HTML Content

', result) def test_render_xblock_from_lms_problem_block(self): self.setup_course() @@ -60,3 +63,4 @@ def test_render_xblock_from_lms_problem_block(self): self.assertIsNotNone(result) self.assertEqual(type(result), str) + self.assertIn('Problem xblock for Offline', result) diff --git a/openedx/features/offline_mode/tests/test_tasks.py b/openedx/features/offline_mode/tests/test_tasks.py index eaa503498193..a4a4a8ea6c1b 100644 --- a/openedx/features/offline_mode/tests/test_tasks.py +++ b/openedx/features/offline_mode/tests/test_tasks.py @@ -6,11 +6,12 @@ from unittest.mock import MagicMock, Mock, call, patch from opaque_keys.edx.keys import CourseKey, UsageKey -from openedx.features.offline_mode.constants import OFFLINE_SUPPORTED_XBLOCKS +from openedx.features.offline_mode.constants import MAX_RETRY_ATTEMPTS, OFFLINE_SUPPORTED_XBLOCKS from openedx.features.offline_mode.tasks import ( generate_offline_content_for_block, generate_offline_content_for_course, ) +from xmodule.modulestore.exceptions import ItemNotFoundError class GenerateOfflineContentTasksTestCase(TestCase): @@ -20,7 +21,7 @@ class GenerateOfflineContentTasksTestCase(TestCase): @patch('openedx.features.offline_mode.tasks.generate_offline_content') @patch('openedx.features.offline_mode.tasks.modulestore') - def test_generate_offline_content_for_block( + def test_generate_offline_content_for_block_success( self, modulestore_mock: MagicMock, generate_offline_content_mock: MagicMock, @@ -36,6 +37,36 @@ def test_generate_offline_content_for_block( modulestore_mock.return_value.get_item.return_value, html_data_mock ) + @patch('openedx.features.offline_mode.tasks.generate_offline_content') + @patch('openedx.features.offline_mode.tasks.modulestore', side_effect=ItemNotFoundError) + def test_generate_offline_content_for_block_with_exception_in_modulestore( + self, + modulestore_mock: MagicMock, + generate_offline_content_mock: MagicMock, + ) -> None: + block_id_mock = 'block-v1:a+a+a+type@problem+block@fb81e4dbfd4945cb9318d6bc460a956c' + html_data_mock = 'html_markup_data_mock' + + generate_offline_content_for_block.delay(block_id_mock, html_data_mock) + + self.assertEqual(modulestore_mock.call_count, MAX_RETRY_ATTEMPTS + 1) + generate_offline_content_mock.assert_not_called() + + @patch('openedx.features.offline_mode.tasks.generate_offline_content', side_effect=FileNotFoundError) + @patch('openedx.features.offline_mode.tasks.modulestore') + def test_generate_offline_content_for_block_with_exception_in_offline_content_generation( + self, + modulestore_mock: MagicMock, + generate_offline_content_mock: MagicMock, + ) -> None: + block_id_mock = 'block-v1:a+a+a+type@problem+block@fb81e4dbfd4945cb9318d6bc460a956c' + html_data_mock = 'html_markup_data_mock' + + generate_offline_content_for_block.delay(block_id_mock, html_data_mock) + + self.assertEqual(modulestore_mock.call_count, MAX_RETRY_ATTEMPTS + 1) + self.assertEqual(generate_offline_content_mock.call_count, MAX_RETRY_ATTEMPTS + 1) + @patch('openedx.features.offline_mode.tasks.generate_offline_content_for_block') @patch('openedx.features.offline_mode.tasks.XBlockRenderer') @patch('openedx.features.offline_mode.tasks.modulestore')