Migrate to the open source XBlock repo
This commit is contained in:
@@ -33,7 +33,7 @@ def group_from_value(groups, v):
|
||||
|
||||
class ABTestFields(object):
|
||||
group_portions = Object(help="What proportions of students should go in each group", default={DEFAULT: 1}, scope=Scope.content)
|
||||
group_assignments = Object(help="What group this user belongs to", scope=Scope.student_preferences, default={})
|
||||
group_assignments = Object(help="What group this user belongs to", scope=Scope.preferences, default={})
|
||||
group_content = Object(help="What content to display to each group", scope=Scope.content, default={DEFAULT: []})
|
||||
experiment = String(help="Experiment that this A/B test belongs to", scope=Scope.content)
|
||||
has_children = True
|
||||
|
||||
@@ -83,7 +83,7 @@ class ComplexEncoder(json.JSONEncoder):
|
||||
|
||||
|
||||
class CapaFields(object):
|
||||
attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.student_state)
|
||||
attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state)
|
||||
max_attempts = StringyInteger(help="Maximum number of attempts that a student is allowed", scope=Scope.settings)
|
||||
due = Date(help="Date that this problem is due by", scope=Scope.settings)
|
||||
graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings)
|
||||
@@ -91,12 +91,12 @@ class CapaFields(object):
|
||||
force_save_button = Boolean(help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False)
|
||||
rerandomize = Randomization(help="When to rerandomize the problem", default="always", scope=Scope.settings)
|
||||
data = String(help="XML data for the problem", scope=Scope.content)
|
||||
correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.student_state, default={})
|
||||
input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.student_state)
|
||||
student_answers = Object(help="Dictionary with the current student responses", scope=Scope.student_state)
|
||||
done = Boolean(help="Whether the student has answered the problem", scope=Scope.student_state)
|
||||
correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.user_state, default={})
|
||||
input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.user_state)
|
||||
student_answers = Object(help="Dictionary with the current student responses", scope=Scope.user_state)
|
||||
done = Boolean(help="Whether the student has answered the problem", scope=Scope.user_state)
|
||||
display_name = String(help="Display name for this module", scope=Scope.settings)
|
||||
seed = StringyInteger(help="Random seed for this student", scope=Scope.student_state)
|
||||
seed = StringyInteger(help="Random seed for this student", scope=Scope.user_state)
|
||||
weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings)
|
||||
markdown = String(help="Markdown source of this module", scope=Scope.settings)
|
||||
|
||||
|
||||
@@ -50,14 +50,14 @@ class VersionInteger(Integer):
|
||||
|
||||
class CombinedOpenEndedFields(object):
|
||||
display_name = String(help="Display name for this module", default="Open Ended Grading", scope=Scope.settings)
|
||||
current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.student_state)
|
||||
task_states = List(help="List of state dictionaries of each task within this module.", scope=Scope.student_state)
|
||||
current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.user_state)
|
||||
task_states = List(help="List of state dictionaries of each task within this module.", scope=Scope.user_state)
|
||||
state = String(help="Which step within the current task that the student is on.", default="initial",
|
||||
scope=Scope.student_state)
|
||||
scope=Scope.user_state)
|
||||
student_attempts = Integer(help="Number of attempts taken by the student on this problem", default=0,
|
||||
scope=Scope.student_state)
|
||||
scope=Scope.user_state)
|
||||
ready_to_reset = Boolean(help="If the problem is ready to be reset or not.", default=False,
|
||||
scope=Scope.student_state)
|
||||
scope=Scope.user_state)
|
||||
attempts = Integer(help="Maximum number of attempts that a student is allowed.", default=1, scope=Scope.settings)
|
||||
is_graded = Boolean(help="Whether or not the problem is graded.", default=False, scope=Scope.settings)
|
||||
accept_file_upload = Boolean(help="Whether or not the problem accepts file uploads.", default=False,
|
||||
|
||||
@@ -38,7 +38,7 @@ class PeerGradingFields(object):
|
||||
max_grade = Integer(help="The maximum grade that a student can receieve for this problem.", default=MAX_SCORE,
|
||||
scope=Scope.settings)
|
||||
student_data_for_location = Object(help="Student data for a given peer grading problem.", default=json.dumps({}),
|
||||
scope=Scope.student_state)
|
||||
scope=Scope.user_state)
|
||||
weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings)
|
||||
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ class PollFields(object):
|
||||
# Name of poll to use in links to this poll
|
||||
display_name = String(help="Display name for this module", scope=Scope.settings)
|
||||
|
||||
voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.student_state, default=False)
|
||||
poll_answer = String(help="Student answer", scope=Scope.student_state, default='')
|
||||
voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.user_state, default=False)
|
||||
poll_answer = String(help="Student answer", scope=Scope.user_state, default='')
|
||||
poll_answers = Object(help="All possible answers for the poll fro other students", scope=Scope.content)
|
||||
|
||||
answers = List(help="Poll answers from xml", scope=Scope.content, default=[])
|
||||
|
||||
@@ -10,7 +10,7 @@ log = logging.getLogger('mitx.' + __name__)
|
||||
|
||||
|
||||
class RandomizeFields(object):
|
||||
choice = Integer(help="Which random child was chosen", scope=Scope.student_state)
|
||||
choice = Integer(help="Which random child was chosen", scope=Scope.user_state)
|
||||
|
||||
|
||||
class RandomizeModule(RandomizeFields, XModule):
|
||||
|
||||
@@ -23,7 +23,7 @@ class SequenceFields(object):
|
||||
|
||||
# NOTE: Position is 1-indexed. This is silly, but there are now student
|
||||
# positions saved on prod, so it's not easy to fix.
|
||||
position = Integer(help="Last tab viewed in this sequence", scope=Scope.student_state)
|
||||
position = Integer(help="Last tab viewed in this sequence", scope=Scope.user_state)
|
||||
|
||||
|
||||
class SequenceModule(SequenceFields, XModule):
|
||||
|
||||
@@ -16,9 +16,9 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TimeLimitFields(object):
|
||||
beginning_at = Float(help="The time this timer was started", scope=Scope.student_state)
|
||||
ending_at = Float(help="The time this timer will end", scope=Scope.student_state)
|
||||
accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.student_state)
|
||||
beginning_at = Float(help="The time this timer was started", scope=Scope.user_state)
|
||||
ending_at = Float(help="The time this timer will end", scope=Scope.user_state)
|
||||
accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.user_state)
|
||||
time_expired_redirect_url = String(help="Url to redirect users to after the timelimit has expired", scope=Scope.settings)
|
||||
duration = Float(help="The length of this timer", scope=Scope.settings)
|
||||
suppress_toplevel_navigation = Boolean(help="Whether the toplevel navigation should be suppressed when viewing this module", scope=Scope.settings)
|
||||
|
||||
@@ -19,7 +19,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class VideoFields(object):
|
||||
data = String(help="XML data for the problem", scope=Scope.content)
|
||||
position = Integer(help="Current position in the video", scope=Scope.student_state, default=0)
|
||||
position = Integer(help="Current position in the video", scope=Scope.user_state, default=0)
|
||||
display_name = String(help="Display name for this module", scope=Scope.settings)
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class VideoAlphaFields(object):
|
||||
data = String(help="XML data for the problem", scope=Scope.content)
|
||||
position = Integer(help="Current position in the video", scope=Scope.student_state, default=0)
|
||||
position = Integer(help="Current position in the video", scope=Scope.user_state, default=0)
|
||||
display_name = String(help="Display name for this module", scope=Scope.settings)
|
||||
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False
|
||||
# Create a fake key to pull out a StudentModule object from the ModelDataCache
|
||||
|
||||
key = LmsKeyValueStore.Key(
|
||||
Scope.student_state,
|
||||
Scope.user_state,
|
||||
student.id,
|
||||
moduledescriptor.location,
|
||||
None
|
||||
@@ -370,7 +370,7 @@ def get_score(course_id, user, problem_descriptor, module_creator, model_data_ca
|
||||
|
||||
# Create a fake KeyValueStore key to pull out the StudentModule
|
||||
key = LmsKeyValueStore.Key(
|
||||
Scope.student_state,
|
||||
Scope.user_state,
|
||||
user.id,
|
||||
problem_descriptor.location,
|
||||
None
|
||||
|
||||
@@ -134,7 +134,7 @@ class ModelDataCache(object):
|
||||
"""
|
||||
if scope in (Scope.children, Scope.parent):
|
||||
return []
|
||||
elif scope == Scope.student_state:
|
||||
elif scope == Scope.user_state:
|
||||
return self._chunked_query(
|
||||
StudentModule,
|
||||
'module_state_key__in',
|
||||
@@ -159,7 +159,7 @@ class ModelDataCache(object):
|
||||
),
|
||||
field_name__in=set(field.name for field in fields),
|
||||
)
|
||||
elif scope == Scope.student_preferences:
|
||||
elif scope == Scope.preferences:
|
||||
return self._chunked_query(
|
||||
XModuleStudentPrefsField,
|
||||
'module_type__in',
|
||||
@@ -167,7 +167,7 @@ class ModelDataCache(object):
|
||||
student=self.user.pk,
|
||||
field_name__in=set(field.name for field in fields),
|
||||
)
|
||||
elif scope == Scope.student_info:
|
||||
elif scope == Scope.user_info:
|
||||
return self._query(
|
||||
XModuleStudentInfoField,
|
||||
student=self.user.pk,
|
||||
@@ -190,15 +190,15 @@ class ModelDataCache(object):
|
||||
"""
|
||||
Return the key used in the ModelDataCache for the specified KeyValueStore key
|
||||
"""
|
||||
if key.scope == Scope.student_state:
|
||||
if key.scope == Scope.user_state:
|
||||
return (key.scope, key.block_scope_id.url())
|
||||
elif key.scope == Scope.content:
|
||||
return (key.scope, key.block_scope_id.url(), key.field_name)
|
||||
elif key.scope == Scope.settings:
|
||||
return (key.scope, '%s-%s' % (self.course_id, key.block_scope_id.url()), key.field_name)
|
||||
elif key.scope == Scope.student_preferences:
|
||||
elif key.scope == Scope.preferences:
|
||||
return (key.scope, key.block_scope_id, key.field_name)
|
||||
elif key.scope == Scope.student_info:
|
||||
elif key.scope == Scope.user_info:
|
||||
return (key.scope, key.field_name)
|
||||
|
||||
def _cache_key_from_field_object(self, scope, field_object):
|
||||
@@ -206,15 +206,15 @@ class ModelDataCache(object):
|
||||
Return the key used in the ModelDataCache for the specified scope and
|
||||
field
|
||||
"""
|
||||
if scope == Scope.student_state:
|
||||
if scope == Scope.user_state:
|
||||
return (scope, field_object.module_state_key)
|
||||
elif scope == Scope.content:
|
||||
return (scope, field_object.definition_id, field_object.field_name)
|
||||
elif scope == Scope.settings:
|
||||
return (scope, field_object.usage_id, field_object.field_name)
|
||||
elif scope == Scope.student_preferences:
|
||||
elif scope == Scope.preferences:
|
||||
return (scope, field_object.module_type, field_object.field_name)
|
||||
elif scope == Scope.student_info:
|
||||
elif scope == Scope.user_info:
|
||||
return (scope, field_object.field_name)
|
||||
|
||||
def find(self, key):
|
||||
@@ -237,7 +237,7 @@ class ModelDataCache(object):
|
||||
if field_object is not None:
|
||||
return field_object
|
||||
|
||||
if key.scope == Scope.student_state:
|
||||
if key.scope == Scope.user_state:
|
||||
field_object, _ = StudentModule.objects.get_or_create(
|
||||
course_id=self.course_id,
|
||||
student=self.user,
|
||||
@@ -255,13 +255,13 @@ class ModelDataCache(object):
|
||||
field_name=key.field_name,
|
||||
usage_id='%s-%s' % (self.course_id, key.block_scope_id.url()),
|
||||
)
|
||||
elif key.scope == Scope.student_preferences:
|
||||
elif key.scope == Scope.preferences:
|
||||
field_object, _ = XModuleStudentPrefsField.objects.get_or_create(
|
||||
field_name=key.field_name,
|
||||
module_type=key.block_scope_id,
|
||||
student=self.user,
|
||||
)
|
||||
elif key.scope == Scope.student_info:
|
||||
elif key.scope == Scope.user_info:
|
||||
field_object, _ = XModuleStudentInfoField.objects.get_or_create(
|
||||
field_name=key.field_name,
|
||||
student=self.user,
|
||||
@@ -281,12 +281,12 @@ class LmsKeyValueStore(KeyValueStore):
|
||||
If the scope to write to is not one of the 5 named scopes:
|
||||
Scope.content
|
||||
Scope.settings
|
||||
Scope.student_state
|
||||
Scope.student_preferences
|
||||
Scope.student_info
|
||||
Scope.user_state
|
||||
Scope.preferences
|
||||
Scope.user_info
|
||||
then an InvalidScopeError will be raised.
|
||||
|
||||
Data for Scope.student_state is stored as StudentModule objects via the django orm.
|
||||
Data for Scope.user_state is stored as StudentModule objects via the django orm.
|
||||
|
||||
Data for the other scopes is stored in individual objects that are named for the
|
||||
scope involved and have the field name as a key
|
||||
@@ -297,9 +297,9 @@ class LmsKeyValueStore(KeyValueStore):
|
||||
_allowed_scopes = (
|
||||
Scope.content,
|
||||
Scope.settings,
|
||||
Scope.student_state,
|
||||
Scope.student_preferences,
|
||||
Scope.student_info,
|
||||
Scope.user_state,
|
||||
Scope.preferences,
|
||||
Scope.user_info,
|
||||
Scope.children,
|
||||
)
|
||||
|
||||
@@ -321,7 +321,7 @@ class LmsKeyValueStore(KeyValueStore):
|
||||
if field_object is None:
|
||||
raise KeyError(key.field_name)
|
||||
|
||||
if key.scope == Scope.student_state:
|
||||
if key.scope == Scope.user_state:
|
||||
return json.loads(field_object.state)[key.field_name]
|
||||
else:
|
||||
return json.loads(field_object.value)
|
||||
@@ -335,7 +335,7 @@ class LmsKeyValueStore(KeyValueStore):
|
||||
if key.scope not in self._allowed_scopes:
|
||||
raise InvalidScopeError(key.scope)
|
||||
|
||||
if key.scope == Scope.student_state:
|
||||
if key.scope == Scope.user_state:
|
||||
state = json.loads(field_object.state)
|
||||
state[key.field_name] = value
|
||||
field_object.state = json.dumps(state)
|
||||
@@ -355,7 +355,7 @@ class LmsKeyValueStore(KeyValueStore):
|
||||
if field_object is None:
|
||||
raise KeyError(key.field_name)
|
||||
|
||||
if key.scope == Scope.student_state:
|
||||
if key.scope == Scope.user_state:
|
||||
state = json.loads(field_object.state)
|
||||
del state[key.field_name]
|
||||
field_object.state = json.dumps(state)
|
||||
@@ -377,7 +377,7 @@ class LmsKeyValueStore(KeyValueStore):
|
||||
if field_object is None:
|
||||
return False
|
||||
|
||||
if key.scope == Scope.student_state:
|
||||
if key.scope == Scope.user_state:
|
||||
return key.field_name in json.loads(field_object.state)
|
||||
else:
|
||||
return True
|
||||
|
||||
@@ -165,7 +165,7 @@ class XModuleSettingsField(models.Model):
|
||||
|
||||
class XModuleStudentPrefsField(models.Model):
|
||||
"""
|
||||
Stores data set in the Scope.student_preferences scope by an xmodule field
|
||||
Stores data set in the Scope.preferences scope by an xmodule field
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
@@ -199,7 +199,7 @@ class XModuleStudentPrefsField(models.Model):
|
||||
|
||||
class XModuleStudentInfoField(models.Model):
|
||||
"""
|
||||
Stores data set in the Scope.student_preferences scope by an xmodule field
|
||||
Stores data set in the Scope.preferences scope by an xmodule field
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -32,9 +32,9 @@ course_id = 'edX/test_course/test'
|
||||
|
||||
content_key = partial(LmsKeyValueStore.Key, Scope.content, None, location('def_id'))
|
||||
settings_key = partial(LmsKeyValueStore.Key, Scope.settings, None, location('def_id'))
|
||||
student_state_key = partial(LmsKeyValueStore.Key, Scope.student_state, 'user', location('def_id'))
|
||||
student_prefs_key = partial(LmsKeyValueStore.Key, Scope.student_preferences, 'user', 'problem')
|
||||
student_info_key = partial(LmsKeyValueStore.Key, Scope.student_info, 'user', None)
|
||||
user_state_key = partial(LmsKeyValueStore.Key, Scope.user_state, 'user', location('def_id'))
|
||||
prefs_key = partial(LmsKeyValueStore.Key, Scope.preferences, 'user', 'problem')
|
||||
user_info_key = partial(LmsKeyValueStore.Key, Scope.user_info, 'user', None)
|
||||
|
||||
|
||||
class UserFactory(factory.Factory):
|
||||
@@ -115,13 +115,13 @@ class TestInvalidScopes(TestCase):
|
||||
def setUp(self):
|
||||
self.desc_md = {}
|
||||
self.user = UserFactory.create()
|
||||
self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.student_state, 'a_field')])], course_id, self.user)
|
||||
self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user)
|
||||
self.kvs = LmsKeyValueStore(self.desc_md, self.mdc)
|
||||
|
||||
def test_invalid_scopes(self):
|
||||
for scope in (Scope(student=True, block=BlockScope.DEFINITION),
|
||||
Scope(student=False, block=BlockScope.TYPE),
|
||||
Scope(student=False, block=BlockScope.ALL)):
|
||||
for scope in (Scope(user=True, block=BlockScope.DEFINITION),
|
||||
Scope(user=False, block=BlockScope.TYPE),
|
||||
Scope(user=False, block=BlockScope.ALL)):
|
||||
self.assertRaises(InvalidScopeError, self.kvs.get, LmsKeyValueStore.Key(scope, None, None, 'field'))
|
||||
self.assertRaises(InvalidScopeError, self.kvs.set, LmsKeyValueStore.Key(scope, None, None, 'field'), 'value')
|
||||
self.assertRaises(InvalidScopeError, self.kvs.delete, LmsKeyValueStore.Key(scope, None, None, 'field'))
|
||||
@@ -134,48 +134,48 @@ class TestStudentModuleStorage(TestCase):
|
||||
self.desc_md = {}
|
||||
student_module = StudentModuleFactory(state=json.dumps({'a_field': 'a_value'}))
|
||||
self.user = student_module.student
|
||||
self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.student_state, 'a_field')])], course_id, self.user)
|
||||
self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user)
|
||||
self.kvs = LmsKeyValueStore(self.desc_md, self.mdc)
|
||||
|
||||
def test_get_existing_field(self):
|
||||
"Test that getting an existing field in an existing StudentModule works"
|
||||
self.assertEquals('a_value', self.kvs.get(student_state_key('a_field')))
|
||||
self.assertEquals('a_value', self.kvs.get(user_state_key('a_field')))
|
||||
|
||||
def test_get_missing_field(self):
|
||||
"Test that getting a missing field from an existing StudentModule raises a KeyError"
|
||||
self.assertRaises(KeyError, self.kvs.get, student_state_key('not_a_field'))
|
||||
self.assertRaises(KeyError, self.kvs.get, user_state_key('not_a_field'))
|
||||
|
||||
def test_set_existing_field(self):
|
||||
"Test that setting an existing student_state field changes the value"
|
||||
self.kvs.set(student_state_key('a_field'), 'new_value')
|
||||
"Test that setting an existing user_state field changes the value"
|
||||
self.kvs.set(user_state_key('a_field'), 'new_value')
|
||||
self.assertEquals(1, StudentModule.objects.all().count())
|
||||
self.assertEquals({'a_field': 'new_value'}, json.loads(StudentModule.objects.all()[0].state))
|
||||
|
||||
def test_set_missing_field(self):
|
||||
"Test that setting a new student_state field changes the value"
|
||||
self.kvs.set(student_state_key('not_a_field'), 'new_value')
|
||||
"Test that setting a new user_state field changes the value"
|
||||
self.kvs.set(user_state_key('not_a_field'), 'new_value')
|
||||
self.assertEquals(1, StudentModule.objects.all().count())
|
||||
self.assertEquals({'a_field': 'a_value', 'not_a_field': 'new_value'}, json.loads(StudentModule.objects.all()[0].state))
|
||||
|
||||
def test_delete_existing_field(self):
|
||||
"Test that deleting an existing field removes it from the StudentModule"
|
||||
self.kvs.delete(student_state_key('a_field'))
|
||||
self.kvs.delete(user_state_key('a_field'))
|
||||
self.assertEquals(1, StudentModule.objects.all().count())
|
||||
self.assertRaises(KeyError, self.kvs.get, student_state_key('not_a_field'))
|
||||
self.assertRaises(KeyError, self.kvs.get, user_state_key('not_a_field'))
|
||||
|
||||
def test_delete_missing_field(self):
|
||||
"Test that deleting a missing field from an existing StudentModule raises a KeyError"
|
||||
self.assertRaises(KeyError, self.kvs.delete, student_state_key('not_a_field'))
|
||||
self.assertRaises(KeyError, self.kvs.delete, user_state_key('not_a_field'))
|
||||
self.assertEquals(1, StudentModule.objects.all().count())
|
||||
self.assertEquals({'a_field': 'a_value'}, json.loads(StudentModule.objects.all()[0].state))
|
||||
|
||||
def test_has_existing_field(self):
|
||||
"Test that `has` returns True for existing fields in StudentModules"
|
||||
self.assertTrue(self.kvs.has(student_state_key('a_field')))
|
||||
self.assertTrue(self.kvs.has(user_state_key('a_field')))
|
||||
|
||||
def test_has_missing_field(self):
|
||||
"Test that `has` returns False for missing fields in StudentModule"
|
||||
self.assertFalse(self.kvs.has(student_state_key('not_a_field')))
|
||||
self.assertFalse(self.kvs.has(user_state_key('not_a_field')))
|
||||
|
||||
|
||||
class TestMissingStudentModule(TestCase):
|
||||
@@ -187,14 +187,14 @@ class TestMissingStudentModule(TestCase):
|
||||
|
||||
def test_get_field_from_missing_student_module(self):
|
||||
"Test that getting a field from a missing StudentModule raises a KeyError"
|
||||
self.assertRaises(KeyError, self.kvs.get, student_state_key('a_field'))
|
||||
self.assertRaises(KeyError, self.kvs.get, user_state_key('a_field'))
|
||||
|
||||
def test_set_field_in_missing_student_module(self):
|
||||
"Test that setting a field in a missing StudentModule creates the student module"
|
||||
self.assertEquals(0, len(self.mdc.cache))
|
||||
self.assertEquals(0, StudentModule.objects.all().count())
|
||||
|
||||
self.kvs.set(student_state_key('a_field'), 'a_value')
|
||||
self.kvs.set(user_state_key('a_field'), 'a_value')
|
||||
|
||||
self.assertEquals(1, len(self.mdc.cache))
|
||||
self.assertEquals(1, StudentModule.objects.all().count())
|
||||
@@ -207,11 +207,11 @@ class TestMissingStudentModule(TestCase):
|
||||
|
||||
def test_delete_field_from_missing_student_module(self):
|
||||
"Test that deleting a field from a missing StudentModule raises a KeyError"
|
||||
self.assertRaises(KeyError, self.kvs.delete, student_state_key('a_field'))
|
||||
self.assertRaises(KeyError, self.kvs.delete, user_state_key('a_field'))
|
||||
|
||||
def test_has_field_for_missing_student_module(self):
|
||||
"Test that `has` returns False for missing StudentModules"
|
||||
self.assertFalse(self.kvs.has(student_state_key('a_field')))
|
||||
self.assertFalse(self.kvs.has(user_state_key('a_field')))
|
||||
|
||||
|
||||
class StorageTestBase(object):
|
||||
@@ -286,13 +286,13 @@ class TestContentStorage(StorageTestBase, TestCase):
|
||||
|
||||
class TestStudentPrefsStorage(StorageTestBase, TestCase):
|
||||
factory = StudentPrefsFactory
|
||||
scope = Scope.student_preferences
|
||||
key_factory = student_prefs_key
|
||||
scope = Scope.preferences
|
||||
key_factory = prefs_key
|
||||
storage_class = XModuleStudentPrefsField
|
||||
|
||||
|
||||
class TestStudentInfoStorage(StorageTestBase, TestCase):
|
||||
factory = StudentInfoFactory
|
||||
scope = Scope.student_info
|
||||
key_factory = student_info_key
|
||||
scope = Scope.user_info
|
||||
key_factory = user_info_key
|
||||
storage_class = XModuleStudentInfoField
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
# XBlock:
|
||||
# Might change frequently, so put it in local-requirements.txt,
|
||||
# but conceptually is an external package, so it is in a separate repo.
|
||||
-e git+ssh://git@github.com/MITx/xmodule-debugger@9a4f883a#egg=XBlock
|
||||
-e git+https://github.com/edx/XBlock.git@96d8f5f4#egg=XBlock
|
||||
|
||||
Reference in New Issue
Block a user