def test_field_serialization(): # Some Fields can define their own serialization mechanisms. # This test ensures that we are using them properly. class CustomField(Field): """ Specifiy a custom field that defines its own serialization """ def from_json(self, value): return value['value'] def to_json(self, value): return {'value': value} class FieldTester(XBlock): """Test XBlock for field serialization testing""" field = CustomField() field_data = DictFieldData({ 'field': {'value': 4} }) field_tester = FieldTester( TestRuntime(services={'field-data': field_data}), None, Mock(), ) assert_equals(4, field_tester.field) field_tester.field = 5 field_tester.save() assert_equals({'value': 5}, field_data.get(field_tester, 'field'))
def test_xblock_write_then_delete(): # Tests that setting a field, then deleting it later, doesn't # cause an erroneous write of the originally set value after # a call to `XBlock.save` class FieldTester(XBlock): """Test XBlock with two fields""" field_a = Integer(scope=Scope.settings) field_b = Integer(scope=Scope.content, default=10) field_data = DictFieldData({"field_a": 5}) field_tester = FieldTester(TestRuntime(services={"field-data": field_data}), scope_ids=Mock(spec=ScopeIds)) # Verify that the fields have been set correctly assert_equals(5, field_tester.field_a) assert_equals(10, field_tester.field_b) # Set the fields to new values field_tester.field_a = 20 field_tester.field_b = 20 # Assert that we've correctly cached the value of both fields to the newly set values. assert_equals(20, field_tester.field_a) assert_equals(20, field_tester.field_b) # Before saving, delete all the fields. Deletes are performed immediately for now, # so the field should immediately not be present in the field_data after the delete. # However, we copy the default values into the cache, so after the delete we expect the # cached values to be the default values, but the fields to be removed from the field_data. del field_tester.field_a del field_tester.field_b # Assert that we're now finding the right cached values - these should be the default values # that the fields have from the class since we've performed a delete, and XBlock.__delete__ # inserts the default values into the cache as an optimization. assert_equals(None, field_tester.field_a) assert_equals(10, field_tester.field_b) # Perform explicit save field_tester.save() # Now that we've done the save, double-check that we still have the correct cached values (the defaults) assert_equals(None, field_tester.field_a) assert_equals(10, field_tester.field_b) # Additionally assert that in the model data, we don't have any values actually set for these fields. # Basically, we want to ensure that the `save` didn't overwrite anything in the actual field_data # Note this test directly accessess field_data and is thus somewhat fragile. assert_false(field_data.has(field_tester, "field_a")) assert_false(field_data.has(field_tester, "field_b"))
def test_default_values(): # Check that values that are deleted are restored to their default values class FieldTester(XBlock): """Test XBlock for field access testing""" dic1 = Dict(scope=Scope.settings) dic2 = Dict(scope=Scope.content, default={"a": 1, "b": 2, "c": 3}) list1 = List(scope=Scope.settings) list2 = List(scope=Scope.content, default=[1, 2, 3]) field_data = DictFieldData({"dic1": {"a": 200}, "list1": ["a", "b"]}) field_tester = FieldTester(TestRuntime(services={"field-data": field_data}), scope_ids=Mock(spec=ScopeIds)) assert_equals({"a": 200}, field_tester.dic1) assert_equals({"a": 1, "b": 2, "c": 3}, field_tester.dic2) assert_equals(["a", "b"], field_tester.list1) assert_equals([1, 2, 3], field_tester.list2) # Modify the fields & save field_tester.dic1.popitem() field_tester.dic2.clear() field_tester.list1.pop() field_tester.list2.remove(2) field_tester.save() # Test that after save, new values exist and fields are present in the underlying kvstore assert_equals({}, field_tester.dic1) assert_equals({}, field_tester.dic2) assert_equals(["a"], field_tester.list1) assert_equals([1, 3], field_tester.list2) for fname in ["dic1", "dic2", "list1", "list2"]: assert field_data.has(field_tester, fname) # Now delete each field del field_tester.dic1 del field_tester.dic2 del field_tester.list1 del field_tester.list2 # Test that default values return after a delete, but fields not actually # in the underlying kvstore # Defaults not explicitly set assert_equals({}, field_tester.dic1) assert_equals([], field_tester.list1) # Defaults explicitly set assert_equals({"a": 1, "b": 2, "c": 3}, field_tester.dic2) assert_equals([1, 2, 3], field_tester.list2) for fname in ["dic1", "dic2", "list1", "list2"]: assert_false(field_data.has(field_tester, fname))
def test_field_access(): class FieldTester(XBlock): """Test XBlock for field access testing""" field_a = Integer(scope=Scope.settings) field_b = Integer(scope=Scope.content, default=10) field_c = Integer(scope=Scope.user_state, default=42) float_a = Float(scope=Scope.settings, default=5.8) float_b = Float(scope=Scope.settings) field_data = DictFieldData({'field_a': 5, 'float_a': 6.1, 'field_x': 15}) field_tester = FieldTester(TestRuntime(services={'field-data': field_data}), scope_ids=Mock()) # Verify that the fields have been set assert field_tester.field_a == 5 assert field_tester.field_b == 10 assert field_tester.field_c == 42 assert field_tester.float_a == 6.1 assert field_tester.float_b is None assert not hasattr(field_tester, 'field_x') # Set two of the fields. field_tester.field_a = 20 field_tester.float_a = 20.5 # field_a should be updated in the cache, but /not/ in the underlying db. assert field_tester.field_a == 20 assert field_tester.float_a == 20.5 assert field_data.get(field_tester, 'field_a') == 5 assert field_data.get(field_tester, 'float_a') == 6.1 # save the XBlock field_tester.save() # verify that the fields have been updated correctly assert field_tester.field_a == 20 assert field_tester.float_a == 20.5 # Now, field_a should be updated in the underlying db assert field_data.get(field_tester, 'field_a') == 20 assert field_data.get(field_tester, 'float_a') == 20.5 assert field_tester.field_b == 10 assert field_tester.field_c == 42 assert field_tester.float_b is None # Deletes happen immediately (do not require a save) del field_tester.field_a del field_tester.float_a # After delete, we should find default values in the cache assert field_tester.field_a is None assert field_tester.float_a == 5.8 # But the fields should not actually be present in the underlying kvstore with pytest.raises(KeyError): field_data.get(field_tester, 'field_a') assert not field_data.has(field_tester, 'field_a') with pytest.raises(KeyError): field_data.get(field_tester, 'float_a') assert not field_data.has(field_tester, 'float_a')
def test_default_values(): # Check that values that are deleted are restored to their default values class FieldTester(XBlock): """Test XBlock for field access testing""" dic1 = Dict(scope=Scope.settings) dic2 = Dict(scope=Scope.content, default={'a': 1, 'b': 2, 'c': 3}) list1 = List(scope=Scope.settings) list2 = List(scope=Scope.content, default=[1, 2, 3]) field_data = DictFieldData({'dic1': {'a': 200}, 'list1': ['a', 'b']}) field_tester = FieldTester(TestRuntime(services={'field-data': field_data}), scope_ids=Mock(spec=ScopeIds)) assert {'a': 200} == field_tester.dic1 assert {'a': 1, 'b': 2, 'c': 3} == field_tester.dic2 assert ['a', 'b'] == field_tester.list1 assert [1, 2, 3] == field_tester.list2 # Modify the fields & save field_tester.dic1.popitem() field_tester.dic2.clear() field_tester.list1.pop() field_tester.list2.remove(2) field_tester.save() # Test that after save, new values exist and fields are present in the underlying kvstore assert {} == field_tester.dic1 assert {} == field_tester.dic2 assert ['a'] == field_tester.list1 assert [1, 3] == field_tester.list2 for fname in ['dic1', 'dic2', 'list1', 'list2']: assert field_data.has(field_tester, fname) # Now delete each field del field_tester.dic1 del field_tester.dic2 del field_tester.list1 del field_tester.list2 # Test that default values return after a delete, but fields not actually # in the underlying kvstore # Defaults not explicitly set assert {} == field_tester.dic1 assert [] == field_tester.list1 # Defaults explicitly set assert {'a': 1, 'b': 2, 'c': 3} == field_tester.dic2 assert [1, 2, 3] == field_tester.list2 for fname in ['dic1', 'dic2', 'list1', 'list2']: assert not field_data.has(field_tester, fname)
def test_change_mutable_default(): """ Ensure that mutating the default value for a field causes the changes to be saved, and doesn't corrupt other instances """ class MutableTester(XBlock): """Test class with mutable fields.""" list_field = List() field_data_a = DictFieldData({}) mutable_test_a = MutableTester(TestRuntime(services={'field-data': field_data_a}), scope_ids=Mock(spec=ScopeIds)) field_data_b = DictFieldData({}) mutable_test_b = MutableTester(TestRuntime(services={'field-data': field_data_b}), scope_ids=Mock(spec=ScopeIds)) # Saving without changing the default value shouldn't write to field_data mutable_test_a.list_field # pylint: disable=W0104 mutable_test_a.save() with assert_raises(KeyError): field_data_a.get(mutable_test_a, 'list_field') mutable_test_a.list_field.append(1) mutable_test_a.save() assert_equals([1], field_data_a.get(mutable_test_a, 'list_field')) with assert_raises(KeyError): field_data_b.get(mutable_test_b, 'list_field')
def test_dict_field_access(): # Check that dicts are correctly saved when not directly set class FieldTester(XBlock): """Test XBlock for field access testing""" field_a = Dict(scope=Scope.settings) field_b = Dict(scope=Scope.content, default={'a': 1, 'b': 2, 'c': 3}) field_c = Dict(scope=Scope.content, default={'a': 4, 'b': 5, 'c': 6}) field_d = Dict(scope=Scope.settings) field_data = DictFieldData({ 'field_a': {'a': 200}, 'field_b': {'a': 11, 'b': 12, 'c': 13} }) field_tester = FieldTester( TestRuntime(services={'field-data': field_data}), None, Mock() ) # Check initial values have been set properly assert_equals({'a': 200}, field_tester.field_a) assert_equals({'a': 11, 'b': 12, 'c': 13}, field_tester.field_b) assert_equals({'a': 4, 'b': 5, 'c': 6}, field_tester.field_c) assert_equals({}, field_tester.field_d) # Update the fields field_tester.field_a['a'] = 250 field_tester.field_b['d'] = 14 field_tester.field_c['a'] = 0 field_tester.field_d['new'] = 'value' # The fields should be update in the cache, but /not/ in the underlying kvstore. assert_equals({'a': 250}, field_tester.field_a) assert_equals({'a': 11, 'b': 12, 'c': 13, 'd': 14}, field_tester.field_b) assert_equals({'a': 0, 'b': 5, 'c': 6}, field_tester.field_c) assert_equals({'new': 'value'}, field_tester.field_d) # Examine model data directly # Caveat: there's not a clean way to copy the originally provided values for `field_a` and `field_b` # when we instantiate the XBlock. So, the values for those two in both `field_data` and `_field_data_cache` # point at the same object. Thus, `field_a` and `field_b` actually have the correct values in # `field_data` right now. `field_c` does not, because it has never been written to the `field_data`. assert_false(field_data.has(field_tester, 'field_c')) assert_false(field_data.has(field_tester, 'field_d')) field_tester.save() # verify that the fields have been updated correctly assert_equals({'a': 250}, field_tester.field_a) assert_equals({'a': 11, 'b': 12, 'c': 13, 'd': 14}, field_tester.field_b) assert_equals({'a': 0, 'b': 5, 'c': 6}, field_tester.field_c) assert_equals({'new': 'value'}, field_tester.field_d) # Now, the fields should be updated in the underlying kvstore assert_equals({'a': 250}, field_data.get(field_tester, 'field_a')) assert_equals({'a': 11, 'b': 12, 'c': 13, 'd': 14}, field_data.get(field_tester, 'field_b')) assert_equals({'a': 0, 'b': 5, 'c': 6}, field_data.get(field_tester, 'field_c')) assert_equals({'new': 'value'}, field_data.get(field_tester, 'field_d'))
def test_list_field_access(): # Check that lists are correctly saved when not directly set class FieldTester(XBlock): """Test XBlock for field access testing""" field_a = List(scope=Scope.settings) field_b = List(scope=Scope.content, default=[1, 2, 3]) field_c = List(scope=Scope.content, default=[4, 5, 6]) field_d = List(scope=Scope.settings) field_data = DictFieldData({"field_a": [200], "field_b": [11, 12, 13]}) field_tester = FieldTester(TestRuntime(services={"field-data": field_data}), scope_ids=Mock(spec=ScopeIds)) # Check initial values have been set properly assert_equals([200], field_tester.field_a) assert_equals([11, 12, 13], field_tester.field_b) assert_equals([4, 5, 6], field_tester.field_c) assert_equals([], field_tester.field_d) # Update the fields field_tester.field_a.append(1) field_tester.field_b.append(14) field_tester.field_c.append(7) field_tester.field_d.append(1) # The fields should be update in the cache, but /not/ in the underlying kvstore. assert_equals([200, 1], field_tester.field_a) assert_equals([11, 12, 13, 14], field_tester.field_b) assert_equals([4, 5, 6, 7], field_tester.field_c) assert_equals([1], field_tester.field_d) # Examine model data directly # Caveat: there's not a clean way to copy the originally provided values for `field_a` and `field_b` # when we instantiate the XBlock. So, the values for those two in both `field_data` and `_field_data_cache` # point at the same object. Thus, `field_a` and `field_b` actually have the correct values in # `field_data` right now. `field_c` does not, because it has never been written to the `field_data`. assert_false(field_data.has(field_tester, "field_c")) assert_false(field_data.has(field_tester, "field_d")) # save the XBlock field_tester.save() # verify that the fields have been updated correctly assert_equals([200, 1], field_tester.field_a) assert_equals([11, 12, 13, 14], field_tester.field_b) assert_equals([4, 5, 6, 7], field_tester.field_c) assert_equals([1], field_tester.field_d) # Now, the fields should be updated in the underlying kvstore assert_equals([200, 1], field_data.get(field_tester, "field_a")) assert_equals([11, 12, 13, 14], field_data.get(field_tester, "field_b")) assert_equals([4, 5, 6, 7], field_data.get(field_tester, "field_c")) assert_equals([1], field_data.get(field_tester, "field_d"))
def setUp(self): """ Makes sure that the Module is declared and mocked with the sample xml above. """ # return anything except None to test LMS def test_real_user(useless): useless_user = Mock(email='*****@*****.**', id=useless) return useless_user # test to make sure that role is checked in LMS def test_user_role(): return 'staff' self.system = get_test_system() self.system.get_real_user = test_real_user self.system.get_user_role = test_user_role self.system.anonymous_student_id = None self.mod = TextAnnotationModule( Mock(), self.system, DictFieldData({'data': self.sample_xml}), ScopeIds(None, None, None, None))
def initialize_module(self, **kwargs): kwargs.update({ 'parent_location': self.section.location, 'category': self.CATEGORY }) self.item_descriptor = ItemFactory.create(**kwargs) self.runtime = self.new_descriptor_runtime() field_data = {} field_data.update(self.MODEL_DATA) student_data = DictFieldData(field_data) self.item_descriptor._field_data = LmsFieldData( self.item_descriptor._field_data, student_data) self.item_descriptor.xmodule_runtime = self.new_module_runtime() #self.item_module = self.item_descriptor.xmodule_runtime.xmodule_instance #self.item_module is None at this time self.item_url = self.item_descriptor.location.to_deprecated_string()
def test_type_and_options(self): # test_display_name_field verifies that a String field is of type "Generic". # test_integer_field verifies that a Integer field is of type "Integer". descriptor = self.get_descriptor(DictFieldData({})) editable_fields = descriptor.editable_metadata_fields # Tests for select self.assert_field_values( editable_fields, 'string_select', TestFields.string_select, explicitly_set=False, value='default value', default_value='default value', type='Select', options=[{'display_name': 'first', 'value': 'value a JSON'}, {'display_name': 'second', 'value': 'value b JSON'}] ) self.assert_field_values( editable_fields, 'float_select', TestFields.float_select, explicitly_set=False, value=.999, default_value=.999, type='Select', options=[1.23, 0.98] ) self.assert_field_values( editable_fields, 'boolean_select', TestFields.boolean_select, explicitly_set=False, value=None, default_value=None, type='Select', options=[{'display_name': "True", "value": True}, {'display_name': "False", "value": False}] ) # Test for float self.assert_field_values( editable_fields, 'float_non_select', TestFields.float_non_select, explicitly_set=False, value=.999, default_value=.999, type='Float', options={'min': 0, 'step': .3} ) self.assert_field_values( editable_fields, 'list_field', TestFields.list_field, explicitly_set=False, value=[], default_value=[], type='List' )
def setUp(self): self.runtime_mock = mock.Mock() self.activity_mock = mock.create_autospec(GroupActivityXBlock) self.activity_mock.content_id = '123456' # can't use create_autospec here, as most methods are wrapped in decorators and mock fails signature checks # with "Too many positional arguments" because of this self.project_api_mock = mock.Mock(spec_set=TypedProjectAPI) # pylint: disable=not-callable self.block = self.block_to_test(self.runtime_mock, field_data=DictFieldData({}), scope_ids=mock.Mock()) self.make_patch(self.block_to_test, 'project_api', mock.PropertyMock(return_value=self.project_api_mock)) self.make_patch(self.block_to_test, 'activity', mock.PropertyMock(return_value=self.activity_mock)) self.real_user_id_mock = self.make_patch(self.block, 'real_user_id', mock.Mock(side_effect=lambda u_id: u_id)) self.workgroup_mock = self.make_patch( self.block_to_test, 'workgroup', mock.PropertyMock(return_value=self.workgroup_data) ) self.user_id_mock = self.make_patch( self.block_to_test, 'user_id', mock.PropertyMock(return_value=self.user_id) ) self.runtime_mock.anonymous_student_id = self.user_id self.runtime_mock.get_real_user.side_effect = lambda uid: mock.Mock(id=uid)
def setUp(self): super(TabsEditingDescriptorTestCase, self).setUp() system = get_test_descriptor_system() system.render_template = Mock( return_value="<div>Test Template HTML</div>") self.tabs = [{ 'name': "Test_css", 'template': "tabs/codemirror-edit.html", 'current': True, 'css': { 'scss': [ resource_string( __name__, '../../test_files/test_tabseditingdescriptor.scss') ], 'css': [ resource_string( __name__, '../../test_files/test_tabseditingdescriptor.css') ] } }, { 'name': "Subtitles", 'template': "video/subtitles.html", }, { 'name': "Settings", 'template': "tabs/video-metadata-edit-tab.html" }] TabsEditingDescriptor.tabs = self.tabs self.descriptor = system.construct_xblock_from_class( TabsEditingDescriptor, scope_ids=ScopeIds( None, None, None, BlockUsageLocator( CourseLocator('org', 'course', 'run', branch='revision'), 'category', 'name')), field_data=DictFieldData({}), )
def _section_send_email(course, access): """ Provide data for the corresponding bulk email section """ course_key = course.id # Monkey-patch applicable_aside_types to return no asides for the duration of this render with patch.object(course.runtime, 'applicable_aside_types', null_applicable_aside_types): # This HtmlDescriptor is only being used to generate a nice text editor. html_module = HtmlDescriptor( course.system, DictFieldData({'data': ''}), ScopeIds(None, None, None, course_key.make_usage_key('html', 'fake')) ) fragment = course.system.render(html_module, 'studio_view') fragment = wrap_xblock( 'LmsRuntime', html_module, 'studio_view', fragment, None, extra_data={"course-id": unicode(course_key)}, usage_id_serializer=lambda usage_id: quote_slashes(unicode(usage_id)), # Generate a new request_token here at random, because this module isn't connected to any other # xblock rendering. request_token=uuid.uuid1().get_hex() ) email_editor = fragment.content section_data = { 'section_key': 'send_email', 'section_display_name': _('Email'), 'access': access, 'send_email': reverse('send_email', kwargs={'course_id': unicode(course_key)}), 'editor': email_editor, 'list_instructor_tasks_url': reverse( 'list_instructor_tasks', kwargs={'course_id': unicode(course_key)} ), 'email_background_tasks_url': reverse( 'list_background_email_tasks', kwargs={'course_id': unicode(course_key)} ), 'email_content_history_url': reverse( 'list_email_content', kwargs={'course_id': unicode(course_key)} ), } return section_data
def setUp(self): self.student = '*****@*****.**' self.instructor = '*****@*****.**' self.password = '******' self.create_account('u1', self.student, self.password) self.create_account('u2', self.instructor, self.password) self.activate_user(self.student) self.activate_user(self.instructor) self.course_id = SlashSeparatedCourseKey("edX", "toy", "2012_Fall") self.location_string = self.course_id.make_usage_key( 'html', 'TestLocation').to_deprecated_string() self.toy = modulestore().get_course(self.course_id) location = "i4x://edX/toy/peergrading/init" field_data = DictFieldData({ 'data': "<peergrading/>", 'location': location, 'category': 'peergrading' }) self.mock_service = peer_grading_service.MockPeerGradingService() self.system = LmsModuleSystem( static_url=settings.STATIC_URL, track_function=None, get_module=None, render_template=render_to_string, replace_urls=None, s3_interface=test_util_open_ended.S3_INTERFACE, open_ended_grading_interface=test_util_open_ended. OPEN_ENDED_GRADING_INTERFACE, mixins=settings.XBLOCK_MIXINS, error_descriptor_class=ErrorDescriptor, descriptor_runtime=None, ) self.descriptor = peer_grading_module.PeerGradingDescriptor( self.system, field_data, ScopeIds(None, None, None, None)) self.descriptor.xmodule_runtime = self.system self.peer_module = self.descriptor self.peer_module.peer_gs = self.mock_service self.logout()
def make_one(self, display_name=None, **kw): """ Creates a XBlock SGA for testing purpose. """ field_data = DictFieldData(kw) block = StaffAssignmentXBlock(self.runtime, field_data, self.scope_ids) block.location = Location('foo', 'bar', 'baz', 'category', 'name', 'revision') block.xmodule_runtime = self.runtime block.course_id = self.course_id block.category = 'problem' if display_name: block.display_name = display_name block.start = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=pytz.utc) modulestore().create_item(self.staff.username, block.location.course_key, block.location.block_type, block.location.block_id) return block
def test_student_view_data(self): def get_mock_components(): child_a = Mock(spec=['student_view_data']) child_a.block_id = 'child_a' child_a.category = 'text' child_a.student_view_data.return_value = 'child_a_json' child_b = Mock(spec=[]) child_b.block_id = 'child_b' child_b.category = 'html' return [child_a, child_b] shared_data = { 'max_attempts': 3, 'extended_feedback': True, 'feedback_label': 'Feedback label', } children = get_mock_components() children_by_id = {child.block_id: child for child in children} display_name = "I'm problem builder" block_data = {'display_name': display_name, 'children': children} block_data.update(shared_data) block = MentoringBlock(Mock(usage_id=1), DictFieldData(block_data), Mock(usage_id=1)) block.runtime = Mock( get_block=lambda block: children_by_id[block.block_id], load_block_type=lambda block: Mock, id_reader=Mock(get_definition_id=lambda block: block, get_block_type=lambda block: block), ) expected = { 'block_id': '1', 'display_name': display_name, 'components': ['child_a_json'], 'messages': { 'completed': None, 'incomplete': None, 'max_attempts_reached': None, } } expected.update(shared_data) self.assertEqual(block.student_view_data(), expected)
def test_json_field_access(): # Check that values are correctly converted to and from json in accessors. class Date(Field): """Date needs to convert between JSON-compatible persistence and a datetime object""" def from_json(self, field): """Convert a string representation of a date to a datetime object""" return datetime.strptime(field, "%m/%d/%Y") def to_json(self, value): """Convert a datetime object to a string""" return value.strftime("%m/%d/%Y") class FieldTester(ScopedStorageMixin): """Toy class for ModelMetaclass and field access testing""" field_a = Date(scope=Scope.settings) field_b = Date(scope=Scope.content, default=datetime(2013, 4, 1)) field_tester = FieldTester( runtime=TestRuntime(services={'field-data': DictFieldData({})}), scope_ids=MagicMock(spec=ScopeIds)) # Check initial values assert_equals(None, field_tester.field_a) assert_equals(datetime(2013, 4, 1), field_tester.field_b) # Test no default specified field_tester.field_a = datetime(2013, 1, 2) assert_equals(datetime(2013, 1, 2), field_tester.field_a) del field_tester.field_a assert_equals(None, field_tester.field_a) # Test default explicitly specified field_tester.field_b = datetime(2013, 1, 2) assert_equals(datetime(2013, 1, 2), field_tester.field_b) del field_tester.field_b assert_equals(datetime(2013, 4, 1), field_tester.field_b)
def make_an_xblock(**kwargs): """ Helper method that creates a Free-text Response XBlock """ course_id = SlashSeparatedCourseKey('foo', 'bar', 'baz') services = { 'i18n': Mock(ugettext=lambda string: string), 'user': Mock(get_current_user=lambda: Mock( emails=['*****@*****.**'], opt_attrs={}, ), ) } runtime = Mock( course_id=course_id, service=lambda _, service: services.get(service), ) scope_ids = Mock() field_data = DictFieldData(kwargs) xblock = GradeMeButton(runtime, field_data, scope_ids) xblock.xmodule_runtime = runtime return xblock
def test_conditional_module_parse_sources(self): dummy_system = Mock() dummy_location = Location("edX", "conditional_test", "test_run", "conditional", "SampleConditional", None) dummy_scope_ids = ScopeIds(None, None, dummy_location, dummy_location) dummy_field_data = DictFieldData({ 'data': '<conditional/>', 'xml_attributes': { 'sources': 'i4x://HarvardX/ER22x/poll_question/T15_poll;i4x://HarvardX/ER22x/poll_question/T16_poll' }, 'children': None, }) conditional = ConditionalDescriptor( dummy_system, dummy_field_data, dummy_scope_ids, ) self.assertEqual(conditional.parse_sources(conditional.xml_attributes), [ 'i4x://HarvardX/ER22x/poll_question/T15_poll', 'i4x://HarvardX/ER22x/poll_question/T16_poll' ])
def test_conditional_module_parse_sources(self): dummy_system = Mock() dummy_location = BlockUsageLocator( CourseLocator("edX", "conditional_test", "test_run"), "conditional", "SampleConditional") dummy_scope_ids = ScopeIds(None, None, dummy_location, dummy_location) dummy_field_data = DictFieldData({ 'data': '<conditional/>', 'xml_attributes': { 'sources': 'i4x://HarvardX/ER22x/poll_question/T15_poll;i4x://HarvardX/ER22x/poll_question/T16_poll' }, # lint-amnesty, pylint: disable=line-too-long 'children': None, }) conditional = ConditionalBlock( dummy_system, dummy_field_data, dummy_scope_ids, ) assert conditional.parse_sources(conditional.xml_attributes) == [ 'i4x://HarvardX/ER22x/poll_question/T15_poll', 'i4x://HarvardX/ER22x/poll_question/T16_poll' ]
def test_conditional_module_with_empty_sources_list(self): """ If a ConditionalBlock is initialized with an empty sources_list, we assert that the sources_list is set via generating UsageKeys from the values in xml_attributes['sources'] """ dummy_system = Mock() dummy_location = BlockUsageLocator(CourseLocator("edX", "conditional_test", "test_run"), "conditional", "SampleConditional") dummy_scope_ids = ScopeIds(None, None, dummy_location, dummy_location) dummy_field_data = DictFieldData({ 'data': '<conditional/>', 'xml_attributes': {'sources': 'i4x://HarvardX/ER22x/poll_question/T15_poll'}, 'children': None, }) conditional = ConditionalBlock( dummy_system, dummy_field_data, dummy_scope_ids, ) new_run = conditional.location.course_key.run # lint-amnesty, pylint: disable=unused-variable assert conditional.sources_list[0] == BlockUsageLocator.from_string(conditional.xml_attributes['sources'])\ .replace(run=dummy_location.course_key.run)
def _create_peer_grading_with_linked_problem(self, location, valid_linked_descriptor=True): """ Create a peer grading problem with a linked location. """ # Mock the linked problem descriptor. linked_descriptor = Mock() linked_descriptor.location = location # Mock the peer grading descriptor. pg_descriptor = Mock() pg_descriptor.location = self.problem_location if valid_linked_descriptor: pg_descriptor.get_required_module_descriptors = lambda: [ linked_descriptor, ] else: pg_descriptor.get_required_module_descriptors = lambda: [] # Setup the proper field data for the peer grading module. field_data = DictFieldData({ 'data': '<peergrading/>', 'location': self.problem_location, 'use_for_single_location': True, 'link_to_location': self.coe_location.url(), 'graded': True, }) # Initialize the peer grading module. peer_grading = PeerGradingModule( pg_descriptor, self.test_system, field_data, ScopeIds(None, None, self.problem_location, self.problem_location)) return peer_grading
def test_export_default_discussion_id(self): """ Test that default discussion_id values are not exported. Historically, the OLX format allowed omitting discussion ID values; in such case, the IDs are generated deterministically based on the course ID and the usage ID. Moreover, Studio does not allow course authors to edit discussion_id, so all courses authored in Studio have discussion_id omitted in OLX. Forcing Studio to always export discussion_id can cause data loss when switching between an older and newer export, in a course with a course ID different from the one from which the export was created - because the discussion ID would be different. """ target_node = etree.Element('dummy') block = DiscussionXBlock(self.runtime_mock, scope_ids=self.keys, field_data=DictFieldData({})) discussion_id_field = block.fields['discussion_id'] # pylint: disable=unsubscriptable-object # precondition checks - discussion_id does not have a value and uses UNIQUE_ID assert discussion_id_field._get_cached_value(block) == NO_CACHE_VALUE # pylint: disable=W0212 assert discussion_id_field.default == UNIQUE_ID block.add_xml_to_node(target_node) assert target_node.tag == 'discussion' # pylint: disable=W0212 assert 'discussion_id' not in target_node.attrib
def test_constructor(self): sample_xml = ''' <video display_name="Test Video" youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8" show_captions="false" download_track="true" download_video="true" start_time="00:00:01" end_time="00:01:00"> <source src="http://www.example.com/source.mp4"/> <source src="http://www.example.com/source.ogg"/> <track src="http://www.example.com/track"/> </video> ''' location = Location(["i4x", "edX", "video", "default", "SampleProblem1"]) field_data = DictFieldData({ 'data': sample_xml, 'location': location }) system = DummySystem(load_error_modules=True) descriptor = VideoDescriptor(system, field_data, Mock()) self.assert_attributes_equal(descriptor, { 'youtube_id_0_75': 'izygArpw-Qo', 'youtube_id_1_0': 'p2Q6BrNhdh8', 'youtube_id_1_25': '1EeWXzPdhSA', 'youtube_id_1_5': 'rABDYkeK0x8', 'download_video': True, 'show_captions': False, 'start_time': datetime.timedelta(seconds=1), 'end_time': datetime.timedelta(seconds=60), 'track': 'http://www.example.com/track', 'download_track': True, 'html5_sources': ['http://www.example.com/source.mp4', 'http://www.example.com/source.ogg'], 'data': '' })
def setUp(self): self.student = '*****@*****.**' self.instructor = '*****@*****.**' self.password = '******' self.location = 'TestLocation' self.create_account('u1', self.student, self.password) self.create_account('u2', self.instructor, self.password) self.activate_user(self.student) self.activate_user(self.instructor) self.course_id = "edX/toy/2012_Fall" self.toy = modulestore().get_course(self.course_id) location = "i4x://edX/toy/peergrading/init" field_data = DictFieldData({ 'data': "<peergrading/>", 'location': location, 'category': 'peergrading' }) self.mock_service = peer_grading_service.MockPeerGradingService() self.system = ModuleSystem( ajax_url=location, track_function=None, get_module=None, render_template=render_to_string, replace_urls=None, xmodule_field_data=lambda d: d._field_data, s3_interface=test_util_open_ended.S3_INTERFACE, open_ended_grading_interface=test_util_open_ended. OPEN_ENDED_GRADING_INTERFACE, mixins=settings.XBLOCK_MIXINS, ) self.descriptor = peer_grading_module.PeerGradingDescriptor( self.system, field_data, ScopeIds(None, None, None, None)) self.peer_module = self.descriptor.xmodule(self.system) self.peer_module.peer_gs = self.mock_service self.logout()
def test_partial_completion_status_migration(self): """ Changed `completed` to `status` in `self.student_results` to accomodate partial responses """ # Instantiate a mentoring block with the old format student_results = [ [ u'goal', { u'completed': True, u'score': 1, u'student_input': u'test', u'weight': 1 } ], [ u'mcq_1_1', { u'completed': False, u'score': 0, u'submission': u'maybenot', u'weight': 1 } ], ] mentoring = MentoringBlock( MagicMock(), DictFieldData({'student_results': student_results}), Mock()) self.assertEqual(copy.deepcopy(student_results), mentoring.student_results) migrated_student_results = copy.deepcopy(student_results) migrated_student_results[0][1]['status'] = 'correct' migrated_student_results[1][1]['status'] = 'incorrect' del migrated_student_results[0][1]['completed'] del migrated_student_results[1][1]['completed'] mentoring.migrate_fields() self.assertEqual(migrated_student_results, mentoring.student_results)
def setUp(self): """ Test case setup """ super(TestPollBlock, self).setUp() self.runtime = MockRuntime() self.poll_data = { 'display_name': 'My Poll', 'question': 'What is your favorite color?', 'answers': [ ['R', { 'label': 'Red' }], ['B', { 'label': 'Blue' }], ['G', { 'label': 'Green' }], ['O', { 'label': 'Other' }], ], 'submissions_count': 5, 'max_submissions': 1, 'private_results': False, 'feedback': 'My Feedback', } self.poll_block = PollBlock(self.runtime, DictFieldData(self.poll_data), None)
def make_one(self, display_name=None, **kw): """ Creates a XBlock SGA for testing purpose. """ from edx_sga.sga import StaffGradedXBlock as cls field_data = DictFieldData(kw) block = cls(self.runtime, field_data, self.scope_ids) block.location = Location('foo', 'bar', 'baz', 'category', 'name', 'revision') block.xmodule_runtime = self.runtime block.course_id = self.course_id block.scope_ids.usage_id = "i4x://foo/bar/category/name" block.category = 'problem' if display_name: block.display_name = display_name block.start = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=pytz.utc) modulestore().create_item(self.staff.username, block.location.course_key, block.location.block_type, block.location.block_id) return block
def setUp(self): """ Create a XBlock VideoXBlock for testing purpose. """ super(VideoXBlockTestBase, self).setUp() runtime = TestRuntime() # pylint: disable=abstract-class-instantiated self.xblock = VideoXBlock(runtime, DictFieldData({ 'account_id': 'account_id', 'metadata': { 'client_id': 'api_key', 'client_secret': 'api_secret' } }), scope_ids=mock.Mock(spec=[])) # Mocked objects is a list containing info about mocked entities. # Example: # self.mocked_objects.append({ # 'obj': requests, # object that contains entity to be mocked # 'attrs': ['get', ], # list of methods/fields to be mocked # 'value': [copy.copy(requests.get), ] # save here original values # }) self.mocked_objects = []
def _section_send_email(course_key, access, course): """ Provide data for the corresponding bulk email section """ html_module = HtmlDescriptor( course.system, DictFieldData({'data': ''}), ScopeIds(None, None, None, course_key.make_usage_key('html', 'fake'))) fragment = course.system.render(html_module, 'studio_view') fragment = wrap_xblock( 'LmsRuntime', html_module, 'studio_view', fragment, None, extra_data={"course-id": course_key.to_deprecated_string()}, usage_id_serializer=lambda usage_id: quote_slashes( usage_id.to_deprecated_string())) email_editor = fragment.content section_data = { 'section_key': 'send_email', 'section_display_name': _('Email'), 'access': access, 'send_email': reverse('send_email', kwargs={'course_id': course_key.to_deprecated_string()}), 'editor': email_editor, 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_key.to_deprecated_string()}), 'email_background_tasks_url': reverse('list_background_email_tasks', kwargs={'course_id': course_key.to_deprecated_string()}), } return section_data
def _load_extra_content(self, system, course_descriptor, category, content_path, course_dir): """ Import fields data content from files """ for filepath in glob.glob(content_path / '*'): if not os.path.isfile(filepath): continue if filepath.endswith('~'): # skip *~ files continue with open(filepath) as f: try: if filepath.find('.json') != -1: # json file with json data content slug, loc, data_content = self._import_field_content( course_descriptor, category, filepath) if data_content is None: continue else: try: # get and update data field in xblock runtime module = system.load_item(loc) for key, value in data_content.items(): setattr(module, key, value) module.save() except ItemNotFoundError: module = None data_content['location'] = loc data_content['category'] = category else: slug = os.path.splitext(os.path.basename(filepath))[0] loc = course_descriptor.scope_ids.usage_id.replace( category=category, name=slug) # html file with html data content html = f.read() try: module = system.load_item(loc) module.data = html module.save() except ItemNotFoundError: module = None data_content = { 'data': html, 'location': loc, 'category': category } if module is None: module = system.construct_xblock( category, # We're loading a descriptor, so student_id is meaningless # We also don't have separate notions of definition and usage ids yet, # so we use the location for both ScopeIds(None, category, loc, loc), DictFieldData(data_content), ) # VS[compat]: # Hack because we need to pull in the 'display_name' for static tabs (because we need to edit them) # lint-amnesty, pylint: disable=line-too-long # from the course policy if category == "static_tab": tab = CourseTabList.get_tab_by_slug( tab_list=course_descriptor.tabs, url_slug=slug) if tab: module.display_name = tab.name module.course_staff_only = tab.course_staff_only module.data_dir = course_dir module.save() self.modules[course_descriptor.id][ module.scope_ids.usage_id] = module except Exception as exc: # pylint: disable=broad-except logging.exception( "Failed to load %s. Skipping... \ Exception: %s", filepath, str(exc)) system.error_tracker("ERROR: " + str(exc))
def setUp(self): self.runtime_mock = mock.Mock(spec=Runtime) self.block = ActiveTableXBlock(self.runtime_mock, DictFieldData({}), mock.Mock())
def _make_block(self, block_type=None): """ Creates a test block """ block_type = block_type if block_type else self.TestXBlock runtime_mock = mock.Mock(spec=Runtime) scope_ids = ScopeIds("user_id", block_type.etree_node_tag, "def_id", "usage_id") return block_type(runtime=runtime_mock, field_data=DictFieldData({}), scope_ids=scope_ids)
def create(system, source_is_error_module=False): """ return a dict of modules: the conditional with a single source and a single child. Keys are 'cond_module', 'source_module', and 'child_module'. if the source_is_error_module flag is set, create a real ErrorModule for the source. """ descriptor_system = get_test_descriptor_system() # construct source descriptor and module: source_location = Location("edX", "conditional_test", "test_run", "problem", "SampleProblem", None) if source_is_error_module: # Make an error descriptor and module source_descriptor = NonStaffErrorDescriptor.from_xml( 'some random xml data', system, id_generator=CourseLocationManager(source_location.course_key), error_msg='random error message') else: source_descriptor = Mock(name='source_descriptor') source_descriptor.location = source_location source_descriptor.runtime = descriptor_system source_descriptor.render = lambda view, context=None: descriptor_system.render( source_descriptor, view, context) # construct other descriptors: child_descriptor = Mock(name='child_descriptor') child_descriptor._xmodule.student_view.return_value.content = u'<p>This is a secret</p>' child_descriptor.student_view = child_descriptor._xmodule.student_view child_descriptor.displayable_items.return_value = [child_descriptor] child_descriptor.runtime = descriptor_system child_descriptor.xmodule_runtime = get_test_system() child_descriptor.render = lambda view, context=None: descriptor_system.render( child_descriptor, view, context) child_descriptor.location = source_location.replace(category='html', name='child') descriptor_system.load_item = { child_descriptor.location: child_descriptor, source_location: source_descriptor }.get system.descriptor_runtime = descriptor_system # construct conditional module: cond_location = Location("edX", "conditional_test", "test_run", "conditional", "SampleConditional", None) field_data = DictFieldData({ 'data': '<conditional/>', 'xml_attributes': { 'attempted': 'true' }, 'children': [child_descriptor.location], }) cond_descriptor = ConditionalDescriptor( descriptor_system, field_data, ScopeIds(None, None, cond_location, cond_location)) cond_descriptor.xmodule_runtime = system system.get_module = lambda desc: desc cond_descriptor.get_required_module_descriptors = Mock( return_value=[source_descriptor]) # return dict: return { 'cond_module': cond_descriptor, 'source_module': source_descriptor, 'child_module': child_descriptor }
def test_field_access(): class FieldTester(XBlock): """Test XBlock for field access testing""" field_a = Integer(scope=Scope.settings) field_b = Integer(scope=Scope.content, default=10) field_c = Integer(scope=Scope.user_state, default=42) float_a = Float(scope=Scope.settings, default=5.8) float_b = Float(scope=Scope.settings) field_data = DictFieldData({"field_a": 5, "float_a": 6.1, "field_x": 15}) field_tester = FieldTester(TestRuntime(services={"field-data": field_data}), scope_ids=Mock()) # Verify that the fields have been set assert_equals(5, field_tester.field_a) assert_equals(10, field_tester.field_b) assert_equals(42, field_tester.field_c) assert_equals(6.1, field_tester.float_a) assert_equals(None, field_tester.float_b) assert not hasattr(field_tester, "field_x") # Set two of the fields. field_tester.field_a = 20 field_tester.float_a = 20.5 # field_a should be updated in the cache, but /not/ in the underlying db. assert_equals(20, field_tester.field_a) assert_equals(20.5, field_tester.float_a) assert_equals(5, field_data.get(field_tester, "field_a")) assert_equals(6.1, field_data.get(field_tester, "float_a")) # save the XBlock field_tester.save() # verify that the fields have been updated correctly assert_equals(20, field_tester.field_a) assert_equals(20.5, field_tester.float_a) # Now, field_a should be updated in the underlying db assert_equals(20, field_data.get(field_tester, "field_a")) assert_equals(20.5, field_data.get(field_tester, "float_a")) assert_equals(10, field_tester.field_b) assert_equals(42, field_tester.field_c) assert_equals(None, field_tester.float_b) # Deletes happen immediately (do not require a save) del field_tester.field_a del field_tester.float_a # After delete, we should find default values in the cache assert_equals(None, field_tester.field_a) assert_equals(5.8, field_tester.float_a) # But the fields should not actually be present in the underlying kvstore with assert_raises(KeyError): field_data.get(field_tester, "field_a") assert_false(field_data.has(field_tester, "field_a")) with assert_raises(KeyError): field_data.get(field_tester, "float_a") assert_false(field_data.has(field_tester, "float_a"))
def make_one(self): return OverrideModulestoreFieldData.wrap( self.course, DictFieldData({ 'foo': 'bar', 'bees': 'knees', }))
def test_get_tip_content(self): self.mcq_block = MCQBlock(self.runtime_mock, DictFieldData({'name': 'test_mcq'}), Mock()) self.mcq_block.get_review_tip = Mock() self.mcq_block.get_review_tip.return_value = self.message_block.content self.assertEqual(self.block.review_tips, [])
def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())