From 152ba7f0e20af358a7e5a153dfc6e0ab1fe2711b Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 13:04:25 +0300 Subject: [PATCH 1/9] Added test to exercise library root paged rendering --- .../modulestore/tests/test_libraries.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py index ef8a6d4d69ca..6038e7ca81eb 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py @@ -207,6 +207,44 @@ def test_library_author_view(self): result = library.render(AUTHOR_VIEW, context) self.assertIn(message, result.content) + @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) + def test_library_author_view_with_paging(self): + """ + Test that LibraryRoot.author_view can apply paging + We have to patch the runtime (module system) in order to be able to + render blocks in our test environment. + """ + library = LibraryFactory.create(modulestore=self.store) + # Add five HTML blocks to the library: + blocks = [ + ItemFactory.create( + category="html", + parent_location=library.location, + user_id=self.user_id, + publish_item=False, + modulestore=self.store, + data="HtmlBlock"+str(i) + ) + for i in range(5) + ] + library = self.store.get_library(library.location.library_key) + + def render_and_check_contents(page, page_size): + context = {'reorderable_items': set(), 'paging': {'page_number': page, 'page_size': page_size}} + expected_blocks = blocks[page_size*page:page_size*(page+1)] + result = library.render(AUTHOR_VIEW, context) + + for expected_block in expected_blocks: + self.assertIn(expected_block.data, result.content) + + hello_render = lambda block, _: Fragment(block.data) + with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): + with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): + render_and_check_contents(0, 3) + render_and_check_contents(1, 3) + render_and_check_contents(0, 2) + render_and_check_contents(1, 2) + def test_xblock_in_lib_have_published_version_returns_false(self): library = LibraryFactory.create(modulestore=self.store) block = ItemFactory.create( From 691858dce70a95ef6619c60445b752bbe3fba3c9 Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 13:15:10 +0300 Subject: [PATCH 2/9] Created dedicated LibraryRoot test file and moved rendering tests from modulestore/tests/test_libraries --- .../modulestore/tests/test_libraries.py | 72 +----------------- .../xmodule/tests/test_library_root.py | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+), 70 deletions(-) create mode 100644 common/lib/xmodule/xmodule/tests/test_library_root.py diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py index 6038e7ca81eb..03ee84ae35fe 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py @@ -6,14 +6,12 @@ """ from bson.objectid import ObjectId import ddt -from mock import patch from opaque_keys.edx.locator import LibraryLocator -from xblock.fragment import Fragment -from xblock.runtime import Runtime as VanillaRuntime + from xmodule.modulestore.exceptions import DuplicateCourseError from xmodule.modulestore.tests.factories import LibraryFactory, ItemFactory, check_mongo_calls from xmodule.modulestore.tests.utils import MixedSplitTestCase -from xmodule.x_module import AUTHOR_VIEW + @ddt.ddt @@ -179,72 +177,6 @@ def test_get_lib_version(self): version = lib.location.library_key.version_guid self.assertIsInstance(version, ObjectId) - @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) - def test_library_author_view(self): - """ - Test that LibraryRoot.author_view can run and includes content from its - children. - We have to patch the runtime (module system) in order to be able to - render blocks in our test environment. - """ - library = LibraryFactory.create(modulestore=self.store) - # Add one HTML block to the library: - ItemFactory.create( - category="html", - parent_location=library.location, - user_id=self.user_id, - publish_item=False, - modulestore=self.store, - ) - library = self.store.get_library(library.location.library_key) - - context = {'reorderable_items': set(), } - # Patch the HTML block to always render "Hello world" - message = u"Hello world" - hello_render = lambda _, context: Fragment(message) - with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): - with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): - result = library.render(AUTHOR_VIEW, context) - self.assertIn(message, result.content) - - @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) - def test_library_author_view_with_paging(self): - """ - Test that LibraryRoot.author_view can apply paging - We have to patch the runtime (module system) in order to be able to - render blocks in our test environment. - """ - library = LibraryFactory.create(modulestore=self.store) - # Add five HTML blocks to the library: - blocks = [ - ItemFactory.create( - category="html", - parent_location=library.location, - user_id=self.user_id, - publish_item=False, - modulestore=self.store, - data="HtmlBlock"+str(i) - ) - for i in range(5) - ] - library = self.store.get_library(library.location.library_key) - - def render_and_check_contents(page, page_size): - context = {'reorderable_items': set(), 'paging': {'page_number': page, 'page_size': page_size}} - expected_blocks = blocks[page_size*page:page_size*(page+1)] - result = library.render(AUTHOR_VIEW, context) - - for expected_block in expected_blocks: - self.assertIn(expected_block.data, result.content) - - hello_render = lambda block, _: Fragment(block.data) - with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): - with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): - render_and_check_contents(0, 3) - render_and_check_contents(1, 3) - render_and_check_contents(0, 2) - render_and_check_contents(1, 2) - def test_xblock_in_lib_have_published_version_returns_false(self): library = LibraryFactory.create(modulestore=self.store) block = ItemFactory.create( diff --git a/common/lib/xmodule/xmodule/tests/test_library_root.py b/common/lib/xmodule/xmodule/tests/test_library_root.py new file mode 100644 index 000000000000..e17dafef85d5 --- /dev/null +++ b/common/lib/xmodule/xmodule/tests/test_library_root.py @@ -0,0 +1,76 @@ +from mock import patch + +from xblock.fragment import Fragment +from xblock.runtime import Runtime as VanillaRuntime +from xmodule.x_module import AUTHOR_VIEW + +from xmodule.modulestore.tests.factories import LibraryFactory, CourseFactory, ItemFactory +from xmodule.modulestore.tests.utils import MixedSplitTestCase + + +class TestLibraryRoot(MixedSplitTestCase): + @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) + def test_library_author_view(self): + """ + Test that LibraryRoot.author_view can run and includes content from its + children. + We have to patch the runtime (module system) in order to be able to + render blocks in our test environment. + """ + library = LibraryFactory.create(modulestore=self.store) + # Add one HTML block to the library: + ItemFactory.create( + category="html", + parent_location=library.location, + user_id=self.user_id, + publish_item=False, + modulestore=self.store, + ) + library = self.store.get_library(library.location.library_key) + + context = {'reorderable_items': set(), } + # Patch the HTML block to always render "Hello world" + message = u"Hello world" + hello_render = lambda _, context: Fragment(message) + with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): + with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): + result = library.render(AUTHOR_VIEW, context) + self.assertIn(message, result.content) + + @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) + def test_library_author_view_with_paging(self): + """ + Test that LibraryRoot.author_view can apply paging + We have to patch the runtime (module system) in order to be able to + render blocks in our test environment. + """ + library = LibraryFactory.create(modulestore=self.store) + # Add five HTML blocks to the library: + blocks = [ + ItemFactory.create( + category="html", + parent_location=library.location, + user_id=self.user_id, + publish_item=False, + modulestore=self.store, + data="HtmlBlock"+str(i) + ) + for i in range(5) + ] + library = self.store.get_library(library.location.library_key) + + def render_and_check_contents(page, page_size): + context = {'reorderable_items': set(), 'paging': {'page_number': page, 'page_size': page_size}} + expected_blocks = blocks[page_size*page:page_size*(page+1)] + result = library.render(AUTHOR_VIEW, context) + + for expected_block in expected_blocks: + self.assertIn(expected_block.data, result.content) + + hello_render = lambda block, _: Fragment(block.data) + with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): + with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): + render_and_check_contents(0, 3) + render_and_check_contents(1, 3) + render_and_check_contents(0, 2) + render_and_check_contents(1, 2) \ No newline at end of file From 8ad9fa59a8f80951c346de8503865c352769c7cc Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 14:17:24 +0300 Subject: [PATCH 3/9] Test for ValueError when updating_children for non-existing library --- .../contentstore/tests/test_libraries.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cms/djangoapps/contentstore/tests/test_libraries.py b/cms/djangoapps/contentstore/tests/test_libraries.py index a3414266bd47..957d8b0faa2b 100644 --- a/cms/djangoapps/contentstore/tests/test_libraries.py +++ b/cms/djangoapps/contentstore/tests/test_libraries.py @@ -419,6 +419,24 @@ def test_refreshes_children_if_capa_type_change(self): html_block = modulestore().get_item(lc_block.children[0]) self.assertEqual(html_block.display_name, name2) + def test_refresh_fails_for_unknown_library(self): + # Create a course: + with modulestore().default_store(ModuleStoreEnum.Type.split): + course = CourseFactory.create() + + # Add a LibraryContent block to the course: + lc_block = self._add_library_content_block(course, self.lib_key) + lc_block = self._refresh_children(lc_block) + self.assertEqual(len(lc_block.children), 0) + + # Now, change the block settings to have an invalid library key: + resp = self._update_item( + lc_block.location, + {"source_libraries": [["library-v1:NOT+FOUND", None]]}, + ) + self.assertEqual(resp.status_code, 200) + with self.assertRaises(ValueError): + self._refresh_children(lc_block, status_code_expected=400) @ddt.ddt class TestLibraryAccess(LibraryTestCase): From ed9c3f993ef7a946a4ae75c5752268b45737ac1c Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 14:31:08 +0300 Subject: [PATCH 4/9] Added docstrings --- cms/djangoapps/contentstore/tests/test_libraries.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cms/djangoapps/contentstore/tests/test_libraries.py b/cms/djangoapps/contentstore/tests/test_libraries.py index 957d8b0faa2b..1d022820f336 100644 --- a/cms/djangoapps/contentstore/tests/test_libraries.py +++ b/cms/djangoapps/contentstore/tests/test_libraries.py @@ -327,6 +327,7 @@ def test_change_after_first_sync(self): self.assertEqual(html_block.data, data_value) def test_refreshes_children_if_libraries_change(self): + """ Tests that children are automatically refreshed if libraries list changes """ library2key = self._create_library("org2", "lib2", "Library2") library2 = modulestore().get_library(library2key) data1, data2 = "Hello world!", "Hello other world!" @@ -370,6 +371,7 @@ def test_refreshes_children_if_libraries_change(self): self.assertEqual(html_block.data, data2) def test_refreshes_children_if_capa_type_change(self): + """ Tests that children are automatically refreshed if capa type field changes """ name1, name2 = "Option Problem", "Multiple Choice Problem" ItemFactory.create( category="problem", @@ -420,6 +422,7 @@ def test_refreshes_children_if_capa_type_change(self): self.assertEqual(html_block.display_name, name2) def test_refresh_fails_for_unknown_library(self): + """ Tests that refresh children fails if unknown library is configured """ # Create a course: with modulestore().default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() From 67a980234ab35a6a85b1e9661a32adcbb253068b Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 17:10:38 +0300 Subject: [PATCH 5/9] Render tests for library content block preview and author views --- .../xmodule/tests/test_library_content.py | 51 +++++++++++++++++-- .../xmodule/tests/test_library_root.py | 27 +++++----- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index a9b924503d20..4c88a40e6de9 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -5,6 +5,12 @@ Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`. """ import ddt +from mock import patch + +from xblock.fragment import Fragment +from xblock.runtime import Runtime as VanillaRuntime + +from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW from xmodule.library_content_module import LibraryVersionReference, ANY_CAPA_TYPE_VALUE, LibraryContentDescriptor from xmodule.modulestore.tests.factories import LibraryFactory, CourseFactory, ItemFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase @@ -12,13 +18,15 @@ from xmodule.validation import StudioValidationMessage -@ddt.ddt -class TestLibraries(MixedSplitTestCase): +_dummy_render = lambda block, _: Fragment(block.data) + + +class BaseTestLibraryContainer(MixedSplitTestCase): """ - Basic unit tests for LibraryContentModule (library_content_module.py) + Base class for TestLibraryContainer and TestLibraryContainerRender """ def setUp(self): - super(TestLibraries, self).setUp() + super(BaseTestLibraryContainer, self).setUp() self.library = LibraryFactory.create(modulestore=self.store) self.lib_blocks = [ @@ -62,7 +70,7 @@ def setUp(self): } ) - def _bind_course_module(self, module): + def _bind_course_module(self, module, render=None): """ Bind a module (part of self.course) so we can access student-specific data. """ @@ -108,6 +116,11 @@ def _create_capa_problems(self): modulestore=self.store, ) +@ddt.ddt +class TestLibraryContainer(BaseTestLibraryContainer): + """ + Basic unit tests for LibraryContentModule (library_content_module.py) + """ def test_lib_content_block(self): """ Test that blocks from a library are copied and added as children @@ -250,3 +263,31 @@ def test_non_editable_settings(self): non_editable_metadata_fields = self.lc_block.non_editable_metadata_fields self.assertIn(LibraryContentDescriptor.mode, non_editable_metadata_fields) self.assertNotIn(LibraryContentDescriptor.display_name, non_editable_metadata_fields) + + +@patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) +@patch('xmodule.html_module.HtmlModule.author_view', _dummy_render, create=True) +@patch('xmodule.html_module.HtmlModule.student_view', _dummy_render, create=True) +@patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []) +class TestLibraryContentRender(BaseTestLibraryContainer): + """ + Rendering unit tests for LibraryContentModule (library_content_module.py) + """ + def test_preivew_view(self): + """ Test preview view rendering """ + self.lc_block.refresh_children() + self.lc_block = self.store.get_item(self.lc_block.location) + self.assertEqual(len(self.lc_block.children), len(self.lib_blocks)) + self._bind_course_module(self.lc_block) + rendered = self.lc_block.render(AUTHOR_VIEW, {'root_xblock': self.lc_block}) + self.assertIn("Hello world from block 1", rendered.content) + + def test_author_view(self): + """ Test author view rendering """ + self.lc_block.refresh_children() + self.lc_block = self.store.get_item(self.lc_block.location) + self.assertEqual(len(self.lc_block.children), len(self.lib_blocks)) + self._bind_course_module(self.lc_block) + rendered = self.lc_block.render(AUTHOR_VIEW, {}) + self.assertEqual("", rendered.content) # content should be empty + self.assertEqual("LibraryContentAuthorView", rendered.js_init_fn) # but some js initialization should happen \ No newline at end of file diff --git a/common/lib/xmodule/xmodule/tests/test_library_root.py b/common/lib/xmodule/xmodule/tests/test_library_root.py index e17dafef85d5..0dc0d1d7d34c 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_root.py +++ b/common/lib/xmodule/xmodule/tests/test_library_root.py @@ -7,9 +7,13 @@ from xmodule.modulestore.tests.factories import LibraryFactory, CourseFactory, ItemFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase +_dummy_render = lambda block, _: Fragment(block.data) + +@patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) +@patch('xmodule.html_module.HtmlDescriptor.author_view', _dummy_render, create=True) +@patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []) class TestLibraryRoot(MixedSplitTestCase): - @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) def test_library_author_view(self): """ Test that LibraryRoot.author_view can run and includes content from its @@ -17,6 +21,7 @@ def test_library_author_view(self): We have to patch the runtime (module system) in order to be able to render blocks in our test environment. """ + message = u"Hello world" library = LibraryFactory.create(modulestore=self.store) # Add one HTML block to the library: ItemFactory.create( @@ -25,19 +30,16 @@ def test_library_author_view(self): user_id=self.user_id, publish_item=False, modulestore=self.store, + data=message ) library = self.store.get_library(library.location.library_key) context = {'reorderable_items': set(), } # Patch the HTML block to always render "Hello world" - message = u"Hello world" - hello_render = lambda _, context: Fragment(message) - with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): - with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): - result = library.render(AUTHOR_VIEW, context) + + result = library.render(AUTHOR_VIEW, context) self.assertIn(message, result.content) - @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) def test_library_author_view_with_paging(self): """ Test that LibraryRoot.author_view can apply paging @@ -67,10 +69,7 @@ def render_and_check_contents(page, page_size): for expected_block in expected_blocks: self.assertIn(expected_block.data, result.content) - hello_render = lambda block, _: Fragment(block.data) - with patch('xmodule.html_module.HtmlDescriptor.author_view', hello_render, create=True): - with patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []): - render_and_check_contents(0, 3) - render_and_check_contents(1, 3) - render_and_check_contents(0, 2) - render_and_check_contents(1, 2) \ No newline at end of file + render_and_check_contents(0, 3) + render_and_check_contents(1, 3) + render_and_check_contents(0, 2) + render_and_check_contents(1, 2) \ No newline at end of file From fc8da72bc7b4acdc90f11bc8f9077074966623bf Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 19:13:19 +0300 Subject: [PATCH 6/9] Tests for LibraryList --- .../xmodule/tests/test_library_content.py | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index 4c88a40e6de9..49495dce3a69 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -6,12 +6,16 @@ """ import ddt from mock import patch +from unittest import TestCase +from bson.objectid import ObjectId + +from opaque_keys.edx.locator import LibraryLocator from xblock.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW -from xmodule.library_content_module import LibraryVersionReference, ANY_CAPA_TYPE_VALUE, LibraryContentDescriptor +from xmodule.library_content_module import LibraryVersionReference, LibraryList, ANY_CAPA_TYPE_VALUE, LibraryContentDescriptor from xmodule.modulestore.tests.factories import LibraryFactory, CourseFactory, ItemFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase from xmodule.tests import get_test_system @@ -290,4 +294,45 @@ def test_author_view(self): self._bind_course_module(self.lc_block) rendered = self.lc_block.render(AUTHOR_VIEW, {}) self.assertEqual("", rendered.content) # content should be empty - self.assertEqual("LibraryContentAuthorView", rendered.js_init_fn) # but some js initialization should happen \ No newline at end of file + self.assertEqual("LibraryContentAuthorView", rendered.js_init_fn) # but some js initialization should happen + + +class TestLibraryList(TestCase): + """ Tests for LibraryList XBlock Field """ + def test_from_json_runtime_style(self): + """ + Test that LibraryList can parse raw libraries list as passed by runtime + """ + lib_list = LibraryList() + lib1_key, lib1_version = u'library-v1:Org1+Lib1', '5436ffec56c02c13806a4c1b' + lib2_key, lib2_version = u'library-v1:Org2+Lib2', '112dbaf312c0daa019ce9992' + raw = [[lib1_key, lib1_version], [lib2_key, lib2_version]] + parsed = lib_list.from_json(raw) + self.assertEqual(len(parsed), 2) + self.assertEquals(parsed[0].library_id, LibraryLocator.from_string(lib1_key)) + self.assertEquals(parsed[0].version, ObjectId(lib1_version)) + self.assertEquals(parsed[1].library_id, LibraryLocator.from_string(lib2_key)) + self.assertEquals(parsed[1].version, ObjectId(lib2_version)) + + def test_from_json_studio_editor_style(self): + """ + Test that LibraryList can parse raw libraries list as passed by studio editor + """ + lib_list = LibraryList() + lib1_key, lib1_version = u'library-v1:Org1+Lib1', '5436ffec56c02c13806a4c1b' + lib2_key, lib2_version = u'library-v1:Org2+Lib2', '112dbaf312c0daa019ce9992' + raw = [lib1_key+','+lib1_version, lib2_key+','+lib2_version] + parsed = lib_list.from_json(raw) + self.assertEqual(len(parsed), 2) + self.assertEquals(parsed[0].library_id, LibraryLocator.from_string(lib1_key)) + self.assertEquals(parsed[0].version, ObjectId(lib1_version)) + self.assertEquals(parsed[1].library_id, LibraryLocator.from_string(lib2_key)) + self.assertEquals(parsed[1].version, ObjectId(lib2_version)) + + def test_from_json_invalid_value(self): + """ + Test that LibraryList raises Value error if invalid library key is given + """ + lib_list = LibraryList() + with self.assertRaises(ValueError): + lib_list.from_json(["Not-a-library-key,whatever"]) \ No newline at end of file From 973bde1094e65886cf0c663acfd8f30aac894e7a Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 20:26:18 +0300 Subject: [PATCH 7/9] Test for paging in items.py --- .../contentstore/tests/test_libraries.py | 1 + .../contentstore/views/tests/test_item.py | 57 +++++++++++++++++-- .../xmodule/tests/test_library_content.py | 18 +++--- .../xmodule/tests/test_library_root.py | 18 ++++-- 4 files changed, 77 insertions(+), 17 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_libraries.py b/cms/djangoapps/contentstore/tests/test_libraries.py index 1d022820f336..b2e748fd5556 100644 --- a/cms/djangoapps/contentstore/tests/test_libraries.py +++ b/cms/djangoapps/contentstore/tests/test_libraries.py @@ -441,6 +441,7 @@ def test_refresh_fails_for_unknown_library(self): with self.assertRaises(ValueError): self._refresh_children(lc_block, status_code_expected=400) + @ddt.ddt class TestLibraryAccess(LibraryTestCase): """ diff --git a/cms/djangoapps/contentstore/views/tests/test_item.py b/cms/djangoapps/contentstore/views/tests/test_item.py index 6b595ae00755..69898bfbe2fb 100644 --- a/cms/djangoapps/contentstore/views/tests/test_item.py +++ b/cms/djangoapps/contentstore/views/tests/test_item.py @@ -3,7 +3,7 @@ from datetime import datetime, timedelta import ddt -from mock import patch +from mock import patch, Mock, PropertyMock from pytz import UTC from webob import Response @@ -18,6 +18,7 @@ component_handler, get_component_templates ) + from contentstore.views.item import create_xblock_info, ALWAYS, VisibilityState, _xblock_type_and_display_name from contentstore.tests.utils import CourseTestCase from student.tests.factories import UserFactory @@ -86,12 +87,18 @@ def _create_vertical(self, parent_usage_key=None): class GetItemTest(ItemTest): """Tests for '/xblock' GET url.""" - def _get_container_preview(self, usage_key): + def _get_preview(self, usage_key, data=None): + """ Makes a request to xblock preview handler """ + preview_url = reverse_usage_url("xblock_view_handler", usage_key, {'view_name': 'container_preview'}) + data = data if data else {} + resp = self.client.get(preview_url, data, HTTP_ACCEPT='application/json') + return resp + + def _get_container_preview(self, usage_key, data=None): """ Returns the HTML and resources required for the xblock at the specified UsageKey """ - preview_url = reverse_usage_url("xblock_view_handler", usage_key, {'view_name': 'container_preview'}) - resp = self.client.get(preview_url, HTTP_ACCEPT='application/json') + resp = self._get_preview(usage_key, data) self.assertEqual(resp.status_code, 200) resp_content = json.loads(resp.content) html = resp_content['html'] @@ -100,6 +107,14 @@ def _get_container_preview(self, usage_key): self.assertIsNotNone(resources) return html, resources + def _get_container_preview_with_error(self, usage_key, expected_code, data=None, content_contains=None): + """ Make request and asserts on response code and response contents """ + resp = self._get_preview(usage_key, data) + self.assertEqual(resp.status_code, expected_code) + if content_contains: + self.assertIn(content_contains, resp.content) + return resp + @ddt.data( (1, 21, 23, 35, 37), (2, 22, 24, 38, 39), @@ -247,6 +262,40 @@ def test_split_test_edited(self): self.assertIn('New_NAME_A', html) self.assertIn('New_NAME_B', html) + def test_valid_paging(self): + """ + Tests that valid paging is passed along to underlying block + """ + with patch('contentstore.views.item.get_preview_fragment') as patched_get_preview_fragment: + retval = Mock() + type(retval).content = PropertyMock(return_value="Some content") + type(retval).resources = PropertyMock(return_value=[]) + patched_get_preview_fragment.return_value = retval + + root_usage_key = self._create_vertical() + _, _ = self._get_container_preview( + root_usage_key, + {'enable_paging': 'true', 'page_number': 0, 'page_size': 2} + ) + call_args = patched_get_preview_fragment.call_args[0] + _, _, context = call_args + self.assertIn('paging', context) + self.assertEqual({'page_number': 0, 'page_size': 2}, context['paging']) + + @ddt.data([1, 'invalid'], ['invalid', 2]) + @ddt.unpack + def test_invalid_paging(self, page_number, page_size): + """ + Tests that valid paging is passed along to underlying block + """ + root_usage_key = self._create_vertical() + self._get_container_preview_with_error( + root_usage_key, + 400, + data={'enable_paging': 'true', 'page_number': page_number, 'page_size': page_size}, + content_contains="Couldn't parse paging parameters" + ) + class DeleteItem(ItemTest): """Tests for '/xblock' DELETE url.""" diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index 49495dce3a69..50046ba9e078 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -14,15 +14,17 @@ from xblock.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime -from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW -from xmodule.library_content_module import LibraryVersionReference, LibraryList, ANY_CAPA_TYPE_VALUE, LibraryContentDescriptor +from xmodule.x_module import AUTHOR_VIEW +from xmodule.library_content_module import ( + LibraryVersionReference, LibraryList, ANY_CAPA_TYPE_VALUE, LibraryContentDescriptor +) from xmodule.modulestore.tests.factories import LibraryFactory, CourseFactory, ItemFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase from xmodule.tests import get_test_system from xmodule.validation import StudioValidationMessage -_dummy_render = lambda block, _: Fragment(block.data) +dummy_render = lambda block, _: Fragment(block.data) class BaseTestLibraryContainer(MixedSplitTestCase): @@ -74,7 +76,7 @@ def setUp(self): } ) - def _bind_course_module(self, module, render=None): + def _bind_course_module(self, module): """ Bind a module (part of self.course) so we can access student-specific data. """ @@ -120,6 +122,7 @@ def _create_capa_problems(self): modulestore=self.store, ) + @ddt.ddt class TestLibraryContainer(BaseTestLibraryContainer): """ @@ -270,8 +273,7 @@ def test_non_editable_settings(self): @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) -@patch('xmodule.html_module.HtmlModule.author_view', _dummy_render, create=True) -@patch('xmodule.html_module.HtmlModule.student_view', _dummy_render, create=True) +@patch('xmodule.html_module.HtmlModule.author_view', dummy_render, create=True) @patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []) class TestLibraryContentRender(BaseTestLibraryContainer): """ @@ -321,7 +323,7 @@ def test_from_json_studio_editor_style(self): lib_list = LibraryList() lib1_key, lib1_version = u'library-v1:Org1+Lib1', '5436ffec56c02c13806a4c1b' lib2_key, lib2_version = u'library-v1:Org2+Lib2', '112dbaf312c0daa019ce9992' - raw = [lib1_key+','+lib1_version, lib2_key+','+lib2_version] + raw = [lib1_key + ',' + lib1_version, lib2_key + ',' + lib2_version] parsed = lib_list.from_json(raw) self.assertEqual(len(parsed), 2) self.assertEquals(parsed[0].library_id, LibraryLocator.from_string(lib1_key)) @@ -335,4 +337,4 @@ def test_from_json_invalid_value(self): """ lib_list = LibraryList() with self.assertRaises(ValueError): - lib_list.from_json(["Not-a-library-key,whatever"]) \ No newline at end of file + lib_list.from_json(["Not-a-library-key,whatever"]) diff --git a/common/lib/xmodule/xmodule/tests/test_library_root.py b/common/lib/xmodule/xmodule/tests/test_library_root.py index 0dc0d1d7d34c..a3ea602496c1 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_root.py +++ b/common/lib/xmodule/xmodule/tests/test_library_root.py @@ -1,19 +1,26 @@ +# -*- coding: utf-8 -*- +""" +Basic unit tests for LibraryRoot +""" from mock import patch from xblock.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime from xmodule.x_module import AUTHOR_VIEW -from xmodule.modulestore.tests.factories import LibraryFactory, CourseFactory, ItemFactory +from xmodule.modulestore.tests.factories import LibraryFactory, ItemFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase -_dummy_render = lambda block, _: Fragment(block.data) +dummy_render = lambda block, _: Fragment(block.data) @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) -@patch('xmodule.html_module.HtmlDescriptor.author_view', _dummy_render, create=True) +@patch('xmodule.html_module.HtmlDescriptor.author_view', dummy_render, create=True) @patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []) class TestLibraryRoot(MixedSplitTestCase): + """ + Basic unit tests for LibraryRoot (library_root_xblock.py) + """ def test_library_author_view(self): """ Test that LibraryRoot.author_view can run and includes content from its @@ -62,8 +69,9 @@ def test_library_author_view_with_paging(self): library = self.store.get_library(library.location.library_key) def render_and_check_contents(page, page_size): + """ Renders block and asserts on returned content """ context = {'reorderable_items': set(), 'paging': {'page_number': page, 'page_size': page_size}} - expected_blocks = blocks[page_size*page:page_size*(page+1)] + expected_blocks = blocks[page_size * page:page_size * (page + 1)] result = library.render(AUTHOR_VIEW, context) for expected_block in expected_blocks: @@ -72,4 +80,4 @@ def render_and_check_contents(page, page_size): render_and_check_contents(0, 3) render_and_check_contents(1, 3) render_and_check_contents(0, 2) - render_and_check_contents(1, 2) \ No newline at end of file + render_and_check_contents(1, 2) From c14a8d6b68dc2cab55d5392618c715cd6f841d6f Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Thu, 8 Jan 2015 21:05:54 +0300 Subject: [PATCH 8/9] pylint fixes --- .../lib/xmodule/xmodule/modulestore/tests/test_libraries.py | 1 - common/lib/xmodule/xmodule/tests/test_library_content.py | 2 +- common/lib/xmodule/xmodule/tests/test_library_root.py | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py index 03ee84ae35fe..7381692239af 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py @@ -13,7 +13,6 @@ from xmodule.modulestore.tests.utils import MixedSplitTestCase - @ddt.ddt class TestLibraries(MixedSplitTestCase): """ diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index 50046ba9e078..f8d45f640d2f 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -24,7 +24,7 @@ from xmodule.validation import StudioValidationMessage -dummy_render = lambda block, _: Fragment(block.data) +dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-name class BaseTestLibraryContainer(MixedSplitTestCase): diff --git a/common/lib/xmodule/xmodule/tests/test_library_root.py b/common/lib/xmodule/xmodule/tests/test_library_root.py index a3ea602496c1..8774e7bb3295 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_root.py +++ b/common/lib/xmodule/xmodule/tests/test_library_root.py @@ -11,7 +11,7 @@ from xmodule.modulestore.tests.factories import LibraryFactory, ItemFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase -dummy_render = lambda block, _: Fragment(block.data) +dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-name @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) @@ -62,7 +62,7 @@ def test_library_author_view_with_paging(self): user_id=self.user_id, publish_item=False, modulestore=self.store, - data="HtmlBlock"+str(i) + data="HtmlBlock" + str(i) ) for i in range(5) ] From fc76600519d435f669bce8b600d9e7eeb29f2efa Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Thu, 8 Jan 2015 17:10:01 -0800 Subject: [PATCH 9/9] Minor tweaks to reduce conflicts with PR 6492 --- .../xmodule/tests/test_library_content.py | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index f8d45f640d2f..5f32dab130e7 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -4,12 +4,10 @@ Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`. """ -import ddt -from mock import patch -from unittest import TestCase from bson.objectid import ObjectId - +from mock import patch from opaque_keys.edx.locator import LibraryLocator +from unittest import TestCase from xblock.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime @@ -27,12 +25,12 @@ dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-name -class BaseTestLibraryContainer(MixedSplitTestCase): +class LibraryContentTest(MixedSplitTestCase): """ - Base class for TestLibraryContainer and TestLibraryContainerRender + Base class for tests of LibraryContentModule (library_content_module.py) """ def setUp(self): - super(BaseTestLibraryContainer, self).setUp() + super(LibraryContentTest, self).setUp() self.library = LibraryFactory.create(modulestore=self.store) self.lib_blocks = [ @@ -123,10 +121,9 @@ def _create_capa_problems(self): ) -@ddt.ddt -class TestLibraryContainer(BaseTestLibraryContainer): +class TestLibraryContentModule(LibraryContentTest): """ - Basic unit tests for LibraryContentModule (library_content_module.py) + Basic unit tests for LibraryContentModule """ def test_lib_content_block(self): """ @@ -275,9 +272,9 @@ def test_non_editable_settings(self): @patch('xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render) @patch('xmodule.html_module.HtmlModule.author_view', dummy_render, create=True) @patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: []) -class TestLibraryContentRender(BaseTestLibraryContainer): +class TestLibraryContentRender(LibraryContentTest): """ - Rendering unit tests for LibraryContentModule (library_content_module.py) + Rendering unit tests for LibraryContentModule """ def test_preivew_view(self): """ Test preview view rendering """