Commit 0895e90a by Don Mitchell

Generate split test data via split

parent 542b146f
import unittest import unittest
from django.conf import settings
from xmodule import templates from xmodule import templates
from xmodule.modulestore.tests import persistent_factories from xmodule.modulestore.tests import persistent_factories
...@@ -10,8 +9,6 @@ from xmodule.capa_module import CapaDescriptor ...@@ -10,8 +9,6 @@ from xmodule.capa_module import CapaDescriptor
from xmodule.modulestore.locator import CourseLocator, BlockUsageLocator, LocalId from xmodule.modulestore.locator import CourseLocator, BlockUsageLocator, LocalId
from xmodule.modulestore.exceptions import ItemNotFoundError, DuplicateCourseError from xmodule.modulestore.exceptions import ItemNotFoundError, DuplicateCourseError
from xmodule.html_module import HtmlDescriptor from xmodule.html_module import HtmlDescriptor
from xmodule.modulestore import inheritance
from xblock.core import XBlock
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
...@@ -81,25 +78,25 @@ class TemplateTests(unittest.TestCase): ...@@ -81,25 +78,25 @@ class TemplateTests(unittest.TestCase):
def test_temporary_xblocks(self): def test_temporary_xblocks(self):
""" """
Test using load_from_json to create non persisted xblocks Test create_xblock to create non persisted xblocks
""" """
test_course = persistent_factories.PersistentCourseFactory.create( test_course = persistent_factories.PersistentCourseFactory.create(
course_id='testx.tempcourse', org='testx', course_id='testx.tempcourse', org='testx',
display_name='fun test course', user_id='testbot' display_name='fun test course', user_id='testbot'
) )
test_chapter = self.load_from_json({'category': 'chapter', test_chapter = modulestore('split').create_xblock(
'fields': {'display_name': 'chapter n'}}, test_course.system, 'chapter', {'display_name': 'chapter n'}, parent_xblock=test_course
test_course.system, parent_xblock=test_course) )
self.assertIsInstance(test_chapter, SequenceDescriptor) self.assertIsInstance(test_chapter, SequenceDescriptor)
self.assertEqual(test_chapter.display_name, 'chapter n') self.assertEqual(test_chapter.display_name, 'chapter n')
self.assertIn(test_chapter, test_course.get_children()) self.assertIn(test_chapter, test_course.get_children())
# test w/ a definition (e.g., a problem) # test w/ a definition (e.g., a problem)
test_def_content = '<problem>boo</problem>' test_def_content = '<problem>boo</problem>'
test_problem = self.load_from_json({'category': 'problem', test_problem = modulestore('split').create_xblock(
'fields': {'data': test_def_content}}, test_course.system, 'problem', {'data': test_def_content}, parent_xblock=test_chapter
test_course.system, parent_xblock=test_chapter) )
self.assertIsInstance(test_problem, CapaDescriptor) self.assertIsInstance(test_problem, CapaDescriptor)
self.assertEqual(test_problem.data, test_def_content) self.assertEqual(test_problem.data, test_def_content)
self.assertIn(test_problem, test_chapter.get_children()) self.assertIn(test_problem, test_chapter.get_children())
...@@ -114,18 +111,19 @@ class TemplateTests(unittest.TestCase): ...@@ -114,18 +111,19 @@ class TemplateTests(unittest.TestCase):
course_id='testx.tempcourse', org='testx', course_id='testx.tempcourse', org='testx',
display_name='fun test course', user_id='testbot' display_name='fun test course', user_id='testbot'
) )
test_chapter = self.load_from_json({'category': 'chapter', test_chapter = modulestore('split').create_xblock(
'fields': {'display_name': 'chapter n'}}, test_course.system, 'chapter', {'display_name': 'chapter n'}, parent_xblock=test_course
test_course.system, parent_xblock=test_course) )
self.assertEqual(test_chapter.display_name, 'chapter n')
test_def_content = '<problem>boo</problem>' test_def_content = '<problem>boo</problem>'
# create child # create child
new_block = self.load_from_json({ new_block = modulestore('split').create_xblock(
'category': 'problem', test_course.system,
'fields': { 'problem',
fields={
'data': test_def_content, 'data': test_def_content,
'display_name': 'problem' 'display_name': 'problem'
}}, },
test_course.system,
parent_xblock=test_chapter parent_xblock=test_chapter
) )
self.assertIsNotNone(new_block.definition_locator) self.assertIsNotNone(new_block.definition_locator)
...@@ -242,44 +240,3 @@ class TemplateTests(unittest.TestCase): ...@@ -242,44 +240,3 @@ class TemplateTests(unittest.TestCase):
mapper = loc_mapper() mapper = loc_mapper()
self.assertEqual(modulestore('split').loc_mapper, mapper) self.assertEqual(modulestore('split').loc_mapper, mapper)
# ================================= JSON PARSING ===========================
# These are example methods for creating xmodules in memory w/o persisting them.
# They were in x_module but since xblock is not planning to support them but will
# allow apps to use this type of thing, I put it here.
@staticmethod
def load_from_json(json_data, system, default_class=None, parent_xblock=None):
"""
This method instantiates the correct subclass of XModuleDescriptor based
on the contents of json_data. It does not persist it and can create one which
has no usage id.
parent_xblock is used to compute inherited metadata as well as to append the new xblock.
json_data:
- 'location' : must have this field
- 'category': the xmodule category (required or location must be a Location)
- 'metadata': a dict of locally set metadata (not inherited)
- 'children': a list of children's usage_ids w/in this course
- 'definition':
- '_id' (optional): the usage_id of this. Will generate one if not given one.
"""
class_ = XBlock.load_class(
json_data.get('category', json_data.get('location', {}).get('category')),
default_class,
select=settings.XBLOCK_SELECT_FUNCTION
)
usage_id = json_data.get('_id', None)
if not '_inherited_settings' in json_data and parent_xblock is not None:
json_data['_inherited_settings'] = parent_xblock.xblock_kvs.inherited_settings.copy()
json_fields = json_data.get('fields', {})
for field_name in inheritance.InheritanceMixin.fields:
if field_name in json_fields:
json_data['_inherited_settings'][field_name] = json_fields[field_name]
new_block = system.xblock_from_json(class_, usage_id, json_data)
if parent_xblock is not None:
parent_xblock.children.append(new_block.scope_ids.usage_id)
# decache pending children field settings
parent_xblock.save()
return new_block
...@@ -22,12 +22,14 @@ log = logging.getLogger(__name__) ...@@ -22,12 +22,14 @@ log = logging.getLogger(__name__)
class LocalId(object): class LocalId(object):
""" """
Class for local ids for non-persisted xblocks Class for local ids for non-persisted xblocks (which can have hardcoded block_ids if necessary)
Should be hashable and distinguishable, but nothing else
""" """
def __init__(self, block_id=None):
self.block_id = block_id
super(LocalId, self).__init__()
def __str__(self): def __str__(self):
return "localid_{}".format(id(self)) return "localid_{}".format(self.block_id or id(self))
class Locator(object): class Locator(object):
......
...@@ -953,7 +953,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -953,7 +953,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# check children # check children
original_entry = self._get_block_from_structure(original_structure, descriptor.location.block_id) original_entry = self._get_block_from_structure(original_structure, descriptor.location.block_id)
is_updated = is_updated or ( is_updated = is_updated or (
descriptor.has_children and original_entry['fields']['children'] != descriptor.children descriptor.has_children and original_entry['fields'].get('children', []) != descriptor.children
) )
# check metadata # check metadata
if not is_updated: if not is_updated:
...@@ -992,6 +992,40 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -992,6 +992,40 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# nothing changed, just return the one sent in # nothing changed, just return the one sent in
return descriptor return descriptor
def create_xblock(self, runtime, category, fields=None, block_id=None, definition_id=None, parent_xblock=None):
"""
This method instantiates the correct subclass of XModuleDescriptor based
on the contents of json_data. It does not persist it and can create one which
has no usage id.
parent_xblock is used to compute inherited metadata as well as to append the new xblock.
json_data:
- 'category': the xmodule category
- 'fields': a dict of locally set fields (not inherited) in json format not pythonic typed format!
- 'definition': the object id of the existing definition
"""
xblock_class = runtime.load_block_type(category)
json_data = {
'category': category,
'fields': fields or {},
}
if definition_id is not None:
json_data['definition'] = definition_id
if parent_xblock is not None:
json_data['_inherited_settings'] = parent_xblock.xblock_kvs.inherited_settings.copy()
if fields is not None:
for field_name in inheritance.InheritanceMixin.fields:
if field_name in fields:
json_data['_inherited_settings'][field_name] = fields[field_name]
new_block = runtime.xblock_from_json(xblock_class, block_id, json_data)
if parent_xblock is not None:
parent_xblock.children.append(new_block.scope_ids.usage_id)
# decache pending children field settings
parent_xblock.save()
return new_block
def persist_xblock_dag(self, xblock, user_id, force=False): def persist_xblock_dag(self, xblock, user_id, force=False):
""" """
create or update the xblock and all of its children. The xblock's location must specify a course. create or update the xblock and all of its children. The xblock's location must specify a course.
...@@ -1050,8 +1084,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1050,8 +1084,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# generate an id # generate an id
is_new = True is_new = True
is_updated = True is_updated = True
block_id = self._generate_block_id(structure_blocks, xblock.category) block_id = getattr(xblock.scope_ids.usage_id.block_id, 'block_id', None)
encoded_block_id = block_id if block_id is None:
block_id = self._generate_block_id(structure_blocks, xblock.category)
encoded_block_id = LocMapperStore.encode_key_for_mongo(block_id)
xblock.scope_ids.usage_id.block_id = block_id xblock.scope_ids.usage_id.block_id = block_id
else: else:
is_new = False is_new = False
......
[{"_id" : "GreekHero",
"org" : "testx",
"versions" : {
"draft" : { "$oid" : "1d00000000000000dddd0000" }
},
"edited_on" : {"$date" : 1364481713238},
"edited_by" : "test@edx.org"},
{"_id" : "wonderful",
"org" : "testx",
"versions" : {
"draft" : { "$oid" : "1d00000000000000dddd2222" },
"published" : { "$oid" : "1d00000000000000eeee0000" }
},
"edited_on" : {"$date" : 1364481313238},
"edited_by" : "test@edx.org"},
{"_id" : "contender",
"org" : "guestx",
"versions" : {
"draft" : { "$oid" : "1d00000000000000dddd5555" }},
"edited_on" : {"$date" : 1364491313238},
"edited_by" : "test@guestx.edu"}
]
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