refactor: move xmodule folder to root
- Moving xmodule folder to root as we're dissolving sub-projects of common folder in edx-platform
- More info: https://openedx.atlassian.net/browse/BOM-2579
- -e common/lib/xmodule has been removed from the requirements as xmodule has itself become the part of edx-platform and not being installed through requirements
- The test files common/lib/xmodule/test_files/ have been removed as they are not being used anymore
This commit is contained in:
161
xmodule/modulestore/tests/test_xml.py
Normal file
161
xmodule/modulestore/tests/test_xml.py
Normal file
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
Tests around our XML modulestore, including importing
|
||||
well-formed and not-well-formed XML.
|
||||
"""
|
||||
|
||||
|
||||
import os.path
|
||||
from glob import glob
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from opaque_keys.edx.locator import CourseLocator
|
||||
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.test_modulestore import check_has_course_method
|
||||
from xmodule.modulestore.tests.utils import TILDA_FILES_DICT, add_temp_files_from_dict, remove_temp_files_from_list
|
||||
from xmodule.modulestore.xml import XMLModuleStore
|
||||
from xmodule.tests import DATA_DIR
|
||||
from xmodule.x_module import XModuleMixin
|
||||
|
||||
|
||||
def glob_tildes_at_end(path):
|
||||
"""
|
||||
A wrapper for the `glob.glob` function, but it always returns
|
||||
files that end in a tilde (~) at the end of the list of results.
|
||||
"""
|
||||
result = glob(path)
|
||||
with_tildes = [f for f in result if f.endswith("~")]
|
||||
no_tildes = [f for f in result if not f.endswith("~")]
|
||||
return no_tildes + with_tildes
|
||||
|
||||
|
||||
class TestXMLModuleStore(TestCase):
|
||||
"""
|
||||
Test around the XML modulestore
|
||||
"""
|
||||
|
||||
@patch('xmodule.tabs.CourseTabList.initialize_default', Mock())
|
||||
def test_unicode_chars_in_xml_content(self):
|
||||
# edX/full/6.002_Spring_2012 has non-ASCII chars, and during
|
||||
# uniquification of names, would raise a UnicodeError. It no longer does.
|
||||
|
||||
# Ensure that there really is a non-ASCII character in the course.
|
||||
with open(os.path.join(DATA_DIR, "toy/sequential/vertical_sequential.xml"), 'rb') as xmlf:
|
||||
xml = xmlf.read()
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
xml.decode('ascii')
|
||||
|
||||
# Load the course, but don't make error modules. This will succeed,
|
||||
# but will record the errors.
|
||||
modulestore = XMLModuleStore(
|
||||
DATA_DIR,
|
||||
source_dirs=['toy'],
|
||||
xblock_mixins=(XModuleMixin,),
|
||||
load_error_modules=False)
|
||||
|
||||
# Look up the errors during load. There should be none.
|
||||
errors = modulestore.get_course_errors(CourseKey.from_string("edX/toy/2012_Fall"))
|
||||
assert errors == []
|
||||
|
||||
def test_get_courses_for_wiki(self):
|
||||
"""
|
||||
Test the get_courses_for_wiki method
|
||||
"""
|
||||
store = XMLModuleStore(DATA_DIR, source_dirs=['toy', 'simple'])
|
||||
for course in store.get_courses():
|
||||
course_locations = store.get_courses_for_wiki(course.wiki_slug)
|
||||
assert len(course_locations) == 1
|
||||
assert course.location.course_key in course_locations
|
||||
|
||||
course_locations = store.get_courses_for_wiki('no_such_wiki')
|
||||
assert len(course_locations) == 0
|
||||
|
||||
# now set toy course to share the wiki with simple course
|
||||
toy_course = store.get_course(CourseKey.from_string('edX/toy/2012_Fall'))
|
||||
toy_course.wiki_slug = 'simple'
|
||||
|
||||
course_locations = store.get_courses_for_wiki('toy')
|
||||
assert len(course_locations) == 0
|
||||
|
||||
course_locations = store.get_courses_for_wiki('simple')
|
||||
assert len(course_locations) == 2
|
||||
for course_number in ['toy', 'simple']:
|
||||
assert CourseKey.from_string('/'.join(['edX', course_number, '2012_Fall'])) in course_locations
|
||||
|
||||
def test_has_course(self):
|
||||
"""
|
||||
Test the has_course method
|
||||
"""
|
||||
check_has_course_method(
|
||||
XMLModuleStore(DATA_DIR, source_dirs=['toy', 'simple']),
|
||||
CourseKey.from_string('edX/toy/2012_Fall'),
|
||||
locator_key_fields=CourseLocator.KEY_FIELDS
|
||||
)
|
||||
|
||||
def test_branch_setting(self):
|
||||
"""
|
||||
Test the branch setting context manager
|
||||
"""
|
||||
store = XMLModuleStore(DATA_DIR, source_dirs=['toy'])
|
||||
course = store.get_courses()[0]
|
||||
|
||||
# XML store allows published_only branch setting
|
||||
with store.branch_setting(ModuleStoreEnum.Branch.published_only, course.id):
|
||||
store.get_item(course.location)
|
||||
|
||||
# XML store does NOT allow draft_preferred branch setting
|
||||
with pytest.raises(ValueError):
|
||||
with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id):
|
||||
# verify that the above context manager raises a ValueError
|
||||
pass # pragma: no cover
|
||||
|
||||
@patch('xmodule.modulestore.xml.log')
|
||||
def test_dag_course(self, mock_logging):
|
||||
"""
|
||||
Test a course whose structure is not a tree.
|
||||
"""
|
||||
store = XMLModuleStore(
|
||||
DATA_DIR,
|
||||
source_dirs=['xml_dag'],
|
||||
xblock_mixins=(XModuleMixin,),
|
||||
)
|
||||
course_key = store.get_courses()[0].id
|
||||
|
||||
mock_logging.warning.assert_called_with(
|
||||
"%s has more than one definition", course_key.make_usage_key('discussion', 'duplicate_def')
|
||||
)
|
||||
|
||||
shared_item_loc = course_key.make_usage_key('html', 'toyhtml')
|
||||
shared_item = store.get_item(shared_item_loc)
|
||||
parent = shared_item.get_parent()
|
||||
assert parent is not None, 'get_parent failed to return a value'
|
||||
parent_loc = course_key.make_usage_key('vertical', 'vertical_test')
|
||||
assert parent.location == parent_loc
|
||||
assert shared_item.location in [x.location for x in parent.get_children()]
|
||||
# ensure it's still a child of the other parent even tho it doesn't claim the other parent as its parent
|
||||
other_parent_loc = course_key.make_usage_key('vertical', 'zeta')
|
||||
other_parent = store.get_item(other_parent_loc)
|
||||
# children rather than get_children b/c the instance returned by get_children != shared_item
|
||||
assert shared_item_loc in other_parent.children
|
||||
|
||||
|
||||
class TestModuleStoreIgnore(TestXMLModuleStore): # lint-amnesty, pylint: disable=missing-class-docstring, test-inherits-tests
|
||||
course_dir = DATA_DIR / "course_ignore"
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.addCleanup(remove_temp_files_from_list, list(TILDA_FILES_DICT.keys()), self.course_dir / "static")
|
||||
add_temp_files_from_dict(TILDA_FILES_DICT, self.course_dir / "static")
|
||||
|
||||
@patch("xmodule.modulestore.xml.glob.glob", side_effect=glob_tildes_at_end)
|
||||
def test_tilde_files_ignored(self, _fake_glob):
|
||||
modulestore = XMLModuleStore(DATA_DIR, source_dirs=['course_ignore'], load_error_modules=False)
|
||||
about_location = CourseKey.from_string('edX/course_ignore/2014_Fall').make_usage_key(
|
||||
'about', 'index',
|
||||
)
|
||||
about_module = modulestore.get_item(about_location)
|
||||
assert 'GREEN' in about_module.data
|
||||
assert 'RED' not in about_module.data
|
||||
Reference in New Issue
Block a user