Skip to content

Commit

Permalink
Merge pull request openedx#6499 from open-craft/content_libraries/cov…
Browse files Browse the repository at this point in the history
…erage-increase

Test coverage improvements
  • Loading branch information
antoviaque committed Jan 9, 2015
2 parents 49c4500 + fc76600 commit a622c71
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 42 deletions.
22 changes: 22 additions & 0 deletions cms/djangoapps/contentstore/tests/test_libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -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!"
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -419,6 +421,26 @@ 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):
""" Tests that refresh children fails if unknown library is configured """
# 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):
Expand Down
57 changes: 53 additions & 4 deletions cms/djangoapps/contentstore/views/tests/test_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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']
Expand All @@ -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),
Expand Down Expand Up @@ -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."""
Expand Down
33 changes: 1 addition & 32 deletions common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
"""
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
Expand Down Expand Up @@ -179,34 +176,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)

def test_xblock_in_lib_have_published_version_returns_false(self):
library = LibraryFactory.create(modulestore=self.store)
block = ItemFactory.create(
Expand Down
97 changes: 91 additions & 6 deletions common/lib/xmodule/xmodule/tests/test_library_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,33 @@
Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`.
"""
import ddt
from xmodule.library_content_module import LibraryVersionReference, ANY_CAPA_TYPE_VALUE, LibraryContentDescriptor
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

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


@ddt.ddt
class TestLibraries(MixedSplitTestCase):
dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-name


class LibraryContentTest(MixedSplitTestCase):
"""
Basic unit tests for LibraryContentModule (library_content_module.py)
Base class for tests of LibraryContentModule (library_content_module.py)
"""
def setUp(self):
super(TestLibraries, self).setUp()
super(LibraryContentTest, self).setUp()

self.library = LibraryFactory.create(modulestore=self.store)
self.lib_blocks = [
Expand Down Expand Up @@ -108,6 +120,11 @@ def _create_capa_problems(self):
modulestore=self.store,
)


class TestLibraryContentModule(LibraryContentTest):
"""
Basic unit tests for LibraryContentModule
"""
def test_lib_content_block(self):
"""
Test that blocks from a library are copied and added as children
Expand Down Expand Up @@ -250,3 +267,71 @@ 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.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: [])
class TestLibraryContentRender(LibraryContentTest):
"""
Rendering unit tests for LibraryContentModule
"""
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


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"])
83 changes: 83 additions & 0 deletions common/lib/xmodule/xmodule/tests/test_library_root.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# -*- 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, ItemFactory
from xmodule.modulestore.tests.utils import MixedSplitTestCase

dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-name


@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):
"""
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
children.
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(
category="html",
parent_location=library.location,
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"

result = library.render(AUTHOR_VIEW, context)
self.assertIn(message, result.content)

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):
""" 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)]
result = library.render(AUTHOR_VIEW, context)

for expected_block in expected_blocks:
self.assertIn(expected_block.data, result.content)

render_and_check_contents(0, 3)
render_and_check_contents(1, 3)
render_and_check_contents(0, 2)
render_and_check_contents(1, 2)

0 comments on commit a622c71

Please sign in to comment.