Commit 4d076fce by Eugeny Kolpakov

Merge pull request #7816 from open-craft/ekolpakov/children-import-fix

Fixed loosing children in drafts on import
parents 6ed41b22 6db974c8
...@@ -2,14 +2,15 @@ ...@@ -2,14 +2,15 @@
Tests for XML importer. Tests for XML importer.
""" """
import mock import mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from xblock.core import XBlock from xblock.core import XBlock
from xblock.fields import String, Scope, ScopeIds from xblock.fields import String, Scope, ScopeIds, List
from xblock.runtime import Runtime, KvsFieldData, DictKeyValueStore from xblock.runtime import Runtime, KvsFieldData, DictKeyValueStore
from xmodule.x_module import XModuleMixin from xmodule.x_module import XModuleMixin
from opaque_keys.edx.locations import Location from opaque_keys.edx.locations import Location
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.modulestore.xml_importer import _import_module_and_update_references from xmodule.modulestore.xml_importer import _import_module_and_update_references, _update_module_location
from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOST from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOST
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.tests import DATA_DIR from xmodule.tests import DATA_DIR
...@@ -229,3 +230,90 @@ class RemapNamespaceTest(ModuleStoreNoSettings): ...@@ -229,3 +230,90 @@ class RemapNamespaceTest(ModuleStoreNoSettings):
self.assertNotIn( self.assertNotIn(
'graded', new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings) 'graded', new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
) )
class StubXBlockWithMutableFields(StubXBlock):
"""
Stub XBlock used for testing mutable fields and children
"""
has_children = True
test_mutable_content_field = List(
help="A mutable content field that will be explicitly set",
scope=Scope.content,
)
test_mutable_settings_field = List(
help="A mutable settings field that will be explicitly set",
scope=Scope.settings,
)
class UpdateLocationTest(ModuleStoreNoSettings):
"""
Test that updating location preserves "is_set_on" status on fields
"""
CONTENT_FIELDS = ['test_content_field', 'test_mutable_content_field']
SETTINGS_FIELDS = ['test_settings_field', 'test_mutable_settings_field']
CHILDREN_FIELDS = ['children']
def setUp(self):
"""
Create a stub XBlock backed by in-memory storage.
"""
self.runtime = mock.MagicMock(Runtime)
self.field_data = KvsFieldData(kvs=DictKeyValueStore())
self.scope_ids = ScopeIds('Bob', 'mutablestubxblock', '123', 'import')
self.xblock = StubXBlockWithMutableFields(self.runtime, self.field_data, self.scope_ids)
self.fake_children_locations = [
BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'mutablestubxblock', 'child1'),
BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'mutablestubxblock', 'child2'),
]
super(UpdateLocationTest, self).setUp()
def _check_explicitly_set(self, block, scope, expected_explicitly_set_fields, should_be_set=False):
""" Gets fields that are explicitly set on block and checks if they are marked as explicitly set or not """
actual_explicitly_set_fields = block.get_explicitly_set_fields_by_scope(scope=scope)
assertion = self.assertIn if should_be_set else self.assertNotIn
for field in expected_explicitly_set_fields:
assertion(field, actual_explicitly_set_fields)
def test_update_locations_native_xblock(self):
""" Update locations updates location and keeps values and "is_set_on" status """
# Set the XBlock's location
self.xblock.location = Location("org", "import", "run", "category", "stubxblock")
# Explicitly set the content, settings and children fields
self.xblock.test_content_field = 'Explicitly set'
self.xblock.test_settings_field = 'Explicitly set'
self.xblock.test_mutable_content_field = [1, 2, 3]
self.xblock.test_mutable_settings_field = ["a", "s", "d"]
self.xblock.children = self.fake_children_locations # pylint:disable=attribute-defined-outside-init
self.xblock.save()
# Update location
target_location = self.xblock.location.replace(revision='draft')
_update_module_location(self.xblock, target_location)
new_version = self.xblock # _update_module_location updates in-place
# Check the XBlock's location
self.assertEqual(new_version.location, target_location)
# Check the values of the fields.
# The content, settings and children fields should be preserved
self.assertEqual(new_version.test_content_field, 'Explicitly set')
self.assertEqual(new_version.test_settings_field, 'Explicitly set')
self.assertEqual(new_version.test_mutable_content_field, [1, 2, 3])
self.assertEqual(new_version.test_mutable_settings_field, ["a", "s", "d"])
self.assertEqual(new_version.children, self.fake_children_locations)
# Expect that these fields are marked explicitly set
self._check_explicitly_set(new_version, Scope.content, self.CONTENT_FIELDS, should_be_set=True)
self._check_explicitly_set(new_version, Scope.settings, self.SETTINGS_FIELDS, should_be_set=True)
self._check_explicitly_set(new_version, Scope.children, self.CHILDREN_FIELDS, should_be_set=True)
# Expect these fields pass "is_set_on" test
for field in self.CONTENT_FIELDS + self.SETTINGS_FIELDS + self.CHILDREN_FIELDS:
self.assertTrue(new_version.fields[field].is_set_on(new_version))
...@@ -1154,7 +1154,8 @@ def _update_module_location(module, new_location): ...@@ -1154,7 +1154,8 @@ def _update_module_location(module, new_location):
else: else:
rekey_fields = ( rekey_fields = (
module.get_explicitly_set_fields_by_scope(Scope.content).keys() + module.get_explicitly_set_fields_by_scope(Scope.content).keys() +
module.get_explicitly_set_fields_by_scope(Scope.settings).keys() module.get_explicitly_set_fields_by_scope(Scope.settings).keys() +
module.get_explicitly_set_fields_by_scope(Scope.children).keys()
) )
module.location = new_location module.location = new_location
......
...@@ -492,10 +492,13 @@ class TestCCXGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -492,10 +492,13 @@ class TestCCXGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
# sure if there's a way to poke the test harness to do so. So, we'll # sure if there's a way to poke the test harness to do so. So, we'll
# just inject the override field storage in this brute force manner. # just inject the override field storage in this brute force manner.
OverrideFieldData.provider_classes = None OverrideFieldData.provider_classes = None
# pylint: disable=protected-access
for block in iter_blocks(course): for block in iter_blocks(course):
block._field_data = OverrideFieldData.wrap( # pylint: disable=protected-access block._field_data = OverrideFieldData.wrap(coach, block._field_data)
coach, block._field_data) # pylint: disable=protected-access new_cache = {'tabs': [], 'discussion_topics': []}
block._field_data_cache = {'tabs': [], 'discussion_topics': []} # pylint: disable=protected-access if 'grading_policy' in block._field_data_cache:
new_cache['grading_policy'] = block._field_data_cache['grading_policy']
block._field_data_cache = new_cache
def cleanup_provider_classes(): def cleanup_provider_classes():
""" """
......
...@@ -27,7 +27,7 @@ git+https://github.com/mfogel/django-settings-context-processor.git@b758c3930862 ...@@ -27,7 +27,7 @@ git+https://github.com/mfogel/django-settings-context-processor.git@b758c3930862
git+https://github.com/pmitros/pyfs.git@96e1922348bfe6d99201b9512a9ed946c87b7e0b git+https://github.com/pmitros/pyfs.git@96e1922348bfe6d99201b9512a9ed946c87b7e0b
# Our libraries: # Our libraries:
-e git+https://github.com/edx/XBlock.git@aed464a0e2f7478e93157150ac04133a745f5f46#egg=XBlock -e git+https://github.com/edx/XBlock.git@1934a2978cdd3e2414486c74b76e3040ff1fb138#egg=XBlock
-e git+https://github.com/edx/codejail.git@6b17c33a89bef0ac510926b1d7fea2748b73aadd#egg=codejail -e git+https://github.com/edx/codejail.git@6b17c33a89bef0ac510926b1d7fea2748b73aadd#egg=codejail
-e git+https://github.com/edx/js-test-tool.git@v0.1.6#egg=js_test_tool -e git+https://github.com/edx/js-test-tool.git@v0.1.6#egg=js_test_tool
-e git+https://github.com/edx/event-tracking.git@0.1.0#egg=event-tracking -e git+https://github.com/edx/event-tracking.git@0.1.0#egg=event-tracking
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment