class CachingTestCase(TestCase): """ Tests for https://edx.lighthouseapp.com/projects/102637/tickets/112-updating-asset-does-not-refresh-the-cached-copy """ unicodeLocation = Location(u'c4x', u'mitX', u'800', u'run', u'thumbnail', u'monsters.jpg') # Note that some of the parts are strings instead of unicode strings nonUnicodeLocation = Location('c4x', u'mitX', u'800', u'run', 'thumbnail', 'monsters.jpg') mockAsset = Content(unicodeLocation, 'my content') def test_put_and_get(self): set_cached_content(self.mockAsset) self.assertEqual(self.mockAsset.content, get_cached_content(self.unicodeLocation).content, 'should be stored in cache with unicodeLocation') self.assertEqual(self.mockAsset.content, get_cached_content(self.nonUnicodeLocation).content, 'should be stored in cache with nonUnicodeLocation') def test_delete(self): set_cached_content(self.mockAsset) del_cached_content(self.nonUnicodeLocation) self.assertEqual(None, get_cached_content(self.unicodeLocation), 'should not be stored in cache with unicodeLocation') self.assertEqual( None, get_cached_content(self.nonUnicodeLocation), 'should not be stored in cache with nonUnicodeLocation')
def test_has_changes_non_direct_only_children(self): """ Tests that has_changes() returns true after editing the child of a vertical (both not direct only categories). """ parent_location = Location('edX', 'toy', '2012_Fall', 'vertical', 'parent') child_location = Location('edX', 'toy', '2012_Fall', 'html', 'child') parent = self.draft_store.create_item( self.dummy_user, parent_location.course_key, parent_location.block_type, block_id=parent_location.block_id) child = self.draft_store.create_child(self.dummy_user, parent_location, child_location.block_type, block_id=child_location.block_id) self.draft_store.publish(parent_location, self.dummy_user) # Verify that there are no changes self.assertFalse(self.draft_store.has_changes(parent_location)) self.assertFalse(self.draft_store.has_changes(child_location)) # Change the child child.display_name = 'Changed Display Name' self.draft_store.update_item(child, user_id=self.dummy_user) # Verify that both parent and child have changes self.assertTrue(self.draft_store.has_changes(parent_location)) self.assertTrue(self.draft_store.has_changes(child_location))
def test_remap_namespace_native_xblock_default_values(self): # Set the XBlock's location self.xblock.location = Location("org", "import", "run", "category", "stubxblock") # Do NOT set any values, so the fields should use the defaults self.xblock.save() # Remap the namespace target_location_namespace = Location("org", "course", "run", "category", "stubxblock") new_version = import_module(self.xblock, modulestore(), self.xblock.location.course_key, target_location_namespace.course_key, do_import_static=False) # Check the values of the fields. # The content and settings fields should be the default values self.assertEqual(new_version.test_content_field, 'default value') self.assertEqual(new_version.test_settings_field, 'default value') # The fields should NOT appear in the explicitly set fields self.assertNotIn( 'test_content_field', new_version.get_explicitly_set_fields_by_scope( scope=Scope.content)) self.assertNotIn( 'test_settings_field', new_version.get_explicitly_set_fields_by_scope( scope=Scope.settings))
def test_remap_namespace_native_xblock_inherited_values(self): # Set the XBlock's location self.xblock.location = Location("org", "import", "run", "category", "stubxblock") self.xblock.save() # Remap the namespace target_location_namespace = Location("org", "course", "run", "category", "stubxblock") new_version = import_module(self.xblock, modulestore(), self.xblock.location.course_key, target_location_namespace.course_key, do_import_static=False) # Inherited fields should NOT be explicitly set self.assertNotIn( 'start', new_version.get_explicitly_set_fields_by_scope( scope=Scope.settings)) self.assertNotIn( 'graded', new_version.get_explicitly_set_fields_by_scope( scope=Scope.settings))
def _create_test_tree(self, name, user_id=None): """ Creates and returns a tree with the following structure: Grandparent Parent Sibling Parent Child Child Sibling """ if user_id is None: user_id = self.dummy_user org = 'edX' course = 'tree{}'.format(name) run = name if not self.draft_store.has_course( SlashSeparatedCourseKey(org, course, run)): self.draft_store.create_course(org, course, run, user_id) locations = { 'grandparent': Location(org, course, run, 'chapter', 'grandparent'), 'parent_sibling': Location(org, course, run, 'sequential', 'parent_sibling'), 'parent': Location(org, course, run, 'sequential', 'parent'), 'child_sibling': Location(org, course, run, 'vertical', 'child_sibling'), 'child': Location(org, course, run, 'vertical', 'child'), } for key in locations: self.draft_store.create_item(user_id, locations[key].course_key, locations[key].block_type, block_id=locations[key].block_id) grandparent = self.draft_store.get_item(locations['grandparent']) grandparent.children += [ locations['parent_sibling'], locations['parent'] ] self.draft_store.update_item(grandparent, user_id=user_id) parent = self.draft_store.get_item(locations['parent']) parent.children += [locations['child_sibling'], locations['child']] self.draft_store.update_item(parent, user_id=user_id) self.draft_store.publish(locations['parent'], user_id) self.draft_store.publish(locations['parent_sibling'], user_id) return locations
def test_find_one(self): assert_not_none( self.draft_store._find_one(Location('edX', 'toy', '2012_Fall', 'course', '2012_Fall')), ) assert_not_none( self.draft_store._find_one(Location('edX', 'simple', '2012_Fall', 'course', '2012_Fall')), ) assert_not_none( self.draft_store._find_one(Location('edX', 'toy', '2012_Fall', 'video', 'Welcome')), )
def test_loads(self): assert_not_none( self.draft_store.get_item(Location('edX', 'toy', '2012_Fall', 'course', '2012_Fall')) ) assert_not_none( self.draft_store.get_item(Location('edX', 'simple', '2012_Fall', 'course', '2012_Fall')), ) assert_not_none( self.draft_store.get_item(Location('edX', 'toy', '2012_Fall', 'video', 'Welcome')), )
def test_export_course_with_peer_component(self): """ Test export course when link_to_location is given in peer grading interface settings. """ name = "export_peer_component" locations = self._create_test_tree(name) # Insert the test block directly into the module store problem_location = Location('edX', 'tree{}'.format(name), name, 'combinedopenended', 'test_peer_problem') self.draft_store.create_child( self.dummy_user, locations["child"], problem_location.block_type, block_id=problem_location.block_id ) interface_location = Location('edX', 'tree{}'.format(name), name, 'peergrading', 'test_peer_interface') self.draft_store.create_child( self.dummy_user, locations["child"], interface_location.block_type, block_id=interface_location.block_id ) self.draft_store._update_single_item( as_draft(interface_location), { 'definition.data': {}, 'metadata': { 'link_to_location': unicode(problem_location), 'use_for_single_location': True, }, }, ) component = self.draft_store.get_item(interface_location) self.assertEqual(unicode(component.link_to_location), unicode(problem_location)) root_dir = path(mkdtemp()) # export_course_to_xml should work. try: export_course_to_xml( self.draft_store, self.content_store, interface_location.course_key, root_dir, 'test_export' ) finally: shutil.rmtree(root_dir)
def test_static_tabs_import(self): """Make sure that the static tabs are imported correctly""" modulestore = XMLModuleStore(DATA_DIR, source_dirs=['toy']) location_tab_syllabus = Location("edX", "toy", "2012_Fall", "static_tab", "syllabus", None) toy_tab_syllabus = modulestore.get_item(location_tab_syllabus) self.assertEqual(toy_tab_syllabus.display_name, 'Syllabus') self.assertEqual(toy_tab_syllabus.course_staff_only, False) location_tab_resources = Location("edX", "toy", "2012_Fall", "static_tab", "resources", None) toy_tab_resources = modulestore.get_item(location_tab_resources) self.assertEqual(toy_tab_resources.display_name, 'Resources') self.assertEqual(toy_tab_resources.course_staff_only, True)
def test_has_changes_add_remove_child(self): """ Tests that has_changes() returns true for the parent when a child with changes is added and false when that child is removed. """ locations = self._create_test_tree('has_changes_add_remove_child') # Test that the ancestors don't have changes self.assertFalse(self.draft_store.has_changes( locations['grandparent'])) self.assertFalse(self.draft_store.has_changes(locations['parent'])) # Create a new child and attach it to parent new_child_location = Location('edX', 'tree', 'has_changes_add_remove_child', 'vertical', 'new_child') self.draft_store.create_child(self.dummy_user, locations['parent'], new_child_location.block_type, block_id=new_child_location.block_id) # Verify that the ancestors now have changes self.assertTrue(self.draft_store.has_changes(locations['grandparent'])) self.assertTrue(self.draft_store.has_changes(locations['parent'])) # Remove the child from the parent parent = self.draft_store.get_item(locations['parent']) parent.children = [locations['child'], locations['child_sibling']] self.draft_store.update_item(parent, user_id=self.dummy_user) # Verify that ancestors now have no changes self.assertFalse(self.draft_store.has_changes( locations['grandparent'])) self.assertFalse(self.draft_store.has_changes(locations['parent']))
def test_has_changes(self): """ Tests that has_changes() only returns true when changes are present """ location = Location('edX', 'toy', '2012_Fall', 'vertical', 'test_vertical') # Create a dummy component to test against self.draft_store.create_item(self.dummy_user, location.course_key, location.block_type, block_id=location.block_id) # Not yet published, so changes are present self.assertTrue(self.draft_store.has_changes(location)) # Publish and verify that there are no unpublished changes self.draft_store.publish(location, self.dummy_user) self.assertFalse(self.draft_store.has_changes(location)) # Change the component, then check that there now are changes component = self.draft_store.get_item(location) component.display_name = 'Changed Display Name' self.draft_store.update_item(component, self.dummy_user) self.assertTrue(self.draft_store.has_changes(location)) # Publish and verify again self.draft_store.publish(location, self.dummy_user) self.assertFalse(self.draft_store.has_changes(location))
def setUp(self): self.course_id = SlashSeparatedCourseKey("edX", "open_ended", "2012_Fall") self.problem_location = Location("edX", "open_ended", "2012_Fall", "combinedopenended", "SampleQuestion") self.self_assessment_task_number = 0 self.open_ended_task_number = 1 self.student_on_initial = UserFactory() self.student_on_accessing = UserFactory() self.student_on_post_assessment = UserFactory() StudentModuleFactory.create(course_id=self.course_id, module_state_key=self.problem_location, student=self.student_on_initial, grade=0, max_grade=1, state=STATE_INITIAL) StudentModuleFactory.create(course_id=self.course_id, module_state_key=self.problem_location, student=self.student_on_accessing, grade=0, max_grade=1, state=STATE_ACCESSING) StudentModuleFactory.create(course_id=self.course_id, module_state_key=self.problem_location, student=self.student_on_post_assessment, grade=0, max_grade=1, state=STATE_POST_ASSESSMENT)
def test_get_courses_for_wiki(self): """ Test the get_courses_for_wiki method """ store = XMLModuleStore(DATA_DIR, course_dirs=['toy', 'simple']) for course in store.get_courses(): course_locations = store.get_courses_for_wiki(course.wiki_slug) self.assertEqual(len(course_locations), 1) self.assertIn(course.location, course_locations) course_locations = store.get_courses_for_wiki('no_such_wiki') self.assertEqual(len(course_locations), 0) # now set toy course to share the wiki with simple course toy_course = store.get_course( SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')) toy_course.wiki_slug = 'simple' course_locations = store.get_courses_for_wiki('toy') self.assertEqual(len(course_locations), 0) course_locations = store.get_courses_for_wiki('simple') self.assertEqual(len(course_locations), 2) for course_number in ['toy', 'simple']: self.assertIn( Location('edX', course_number, '2012_Fall', 'course', '2012_Fall'), course_locations)
def initdb(self, default): """ Initialize the database and create one test course in it """ # set the default modulestore self.options['stores']['default'] = self.options['stores'][default] self.store = MixedModuleStore(**self.options) self.addCleanup(self.store.close_all_connections) # convert to CourseKeys self.course_locations = { course_id: SlashSeparatedCourseKey.from_deprecated_string(course_id) for course_id in [self.MONGO_COURSEID, self.XML_COURSEID1, self.XML_COURSEID2] } # and then to the root UsageKey self.course_locations = { course_id: course_key.make_usage_key('course', course_key.run) for course_id, course_key in self.course_locations.iteritems() # pylint: disable=maybe-no-member } self.fake_location = Location('foo', 'bar', 'slowly', 'vertical', 'baz') self.import_chapter_location = self.course_locations[ self.MONGO_COURSEID].replace(category='chapter', name='Overview') self.xml_chapter_location = self.course_locations[ self.XML_COURSEID1].replace(category='chapter', name='Overview') # get Locators and set up the loc mapper if app is Locator based if default == 'split': self.fake_location = loc_mapper().translate_location( self.fake_location) self._create_course( default, self.course_locations[self.MONGO_COURSEID].course_key)
def setUp(self): self.annotatable = AnnotatableModule( Mock(), get_test_system(), DictFieldData({'data': self.sample_xml}), ScopeIds(None, None, None, Location('org', 'course', 'run', 'category', 'name', None)) )
def test_definition_loading(self): """When two courses share the same org and course name and both have a module with the same url_name, the definitions shouldn't clash. TODO (vshnayder): once we have a CMS, this shouldn't happen--locations should uniquely name definitions. But in our imperfect XML world, it can (and likely will) happen.""" modulestore = XMLModuleStore(DATA_DIR, source_dirs=['toy', 'two_toys']) location = Location("edX", "toy", "2012_Fall", "video", "Welcome", None) toy_video = modulestore.get_item(location) location_two = Location("edX", "toy", "TT_2012_Fall", "video", "Welcome", None) two_toy_video = modulestore.get_item(location_two) self.assertEqual(toy_video.youtube_id_1_0, "p2Q6BrNhdh8") self.assertEqual(two_toy_video.youtube_id_1_0, "p2Q6BrNhdh9")
def test_update_edit_info(self): """ Tests that edited_on and edited_by are set correctly during an update """ location = Location('edX', 'toy', '2012_Fall', 'html', 'test_html') # Create a dummy component to test against self.draft_store.create_item(self.dummy_user, location.course_key, location.block_type, block_id=location.block_id) # Store the current edit time and verify that dummy_user created the component component = self.draft_store.get_item(location) self.assertEqual(component.edited_by, self.dummy_user) old_edited_on = component.edited_on # Change the component component.display_name = component.display_name + ' Changed' self.draft_store.update_item(component, self.dummy_user) updated_component = self.draft_store.get_item(location) # Verify the ordering of edit times and that dummy_user made the edit self.assertLess(old_edited_on, updated_component.edited_on) self.assertEqual(updated_component.edited_by, self.dummy_user)
def _create(cls, target_class, **kwargs): # All class attributes (from this class and base classes) are # passed in via **kwargs. However, some of those aren't actual field values, # so pop those off for use separately org = kwargs.pop('org', None) # because the factory provides a default 'number' arg, prefer the non-defaulted 'course' arg if any number = kwargs.pop('course', kwargs.pop('number', None)) store = kwargs.pop('modulestore') name = kwargs.get('name', kwargs.get('run', Location.clean(kwargs.get('display_name')))) run = kwargs.get('run', name) user_id = kwargs.pop('user_id', ModuleStoreEnum.UserID.test) location = Location(org, number, run, 'course', name) with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred): # Write the data to the mongo datastore new_course = store.create_xmodule(location, metadata=kwargs.get('metadata', None)) # The rest of kwargs become attributes on the course: for k, v in kwargs.iteritems(): setattr(new_course, k, v) # Save the attributes we just set new_course.save() # Update the data in the mongo datastore store.update_item(new_course, user_id) return new_course
def test_migrate_published_info(self): """ Tests that blocks that were storing published_date and published_by through CMSBlockMixin are loaded correctly """ # Insert the test block directly into the module store location = Location('edX', 'migration', '2012_Fall', 'html', 'test_html') published_date = datetime(1970, 1, 1, tzinfo=UTC) published_by = 123 self.draft_store._update_single_item( as_draft(location), { 'definition.data': {}, 'metadata': { # published_date was previously stored as a list of time components, not a datetime 'published_date': list(published_date.timetuple()), 'published_by': published_by, }, }, allow_not_found=True, ) # Retrieve the block and verify its fields component = self.draft_store.get_item(location) self.assertEqual(component.published_on, published_date) self.assertEqual(component.published_by, published_by)
def test_conditional_module_with_empty_sources_list(self): """ If a ConditionalDescriptor 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 = 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' }, 'children': None, }) conditional = ConditionalDescriptor( dummy_system, dummy_field_data, dummy_scope_ids, ) self.assertEqual( conditional.sources_list[0], conditional.location.course_key. make_usage_key_from_deprecated_string( conditional.xml_attributes['sources']))
def test_jumpto_id_invalid_location(self): location = Location('edX', 'toy', 'NoSuchPlace', None, None, None) jumpto_url = '{0}/{1}/jump_to_id/{2}'.format( '/courses', self.course_key.to_deprecated_string(), location.to_deprecated_string()) response = self.client.get(jumpto_url) self.assertEqual(response.status_code, 404)
def test_unicode_loads(self): """ Test that getting items from the test_unicode course works """ assert_not_none( self.draft_store.get_item(Location('edX', 'test_unicode', '2012_Fall', 'course', '2012_Fall')), ) # All items with ascii-only filenames should load properly. assert_not_none( self.draft_store.get_item(Location('edX', 'test_unicode', '2012_Fall', 'video', 'Welcome')), ) assert_not_none( self.draft_store.get_item(Location('edX', 'test_unicode', '2012_Fall', 'video', 'Welcome')), ) assert_not_none( self.draft_store.get_item(Location('edX', 'test_unicode', '2012_Fall', 'chapter', 'Overview')), )
def setUp(self): system = get_test_descriptor_system() location = Location('org', 'course', 'run', 'video', 'name', None) self.descriptor = system.construct_xblock_from_class( VideoDescriptor, scope_ids=ScopeIds(None, None, location, location), field_data=DictFieldData({}), )
def make_one(self, **kw): from edx_mfu.mfu import MultipleFileUploadXBlock as cls field_data = DictFieldData(kw) block = cls(self.runtime, field_data, self.scope_ids) block.location = Location( 'org', 'course', 'run', 'category', 'name', 'revision' ) block.xmodule_runtime = self.runtime return block
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"/> <handout src="http://www.example.com/handout"/> <transcript language="ua" src="ukrainian_translation.srt" /> <transcript language="ge" src="german_translation.srt" /> </video> ''' location = Location("edX", 'course', 'run', "video", "SampleProblem1", None) 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', 'handout': 'http://www.example.com/handout', 'download_track': True, 'html5_sources': [ 'http://www.example.com/source.mp4', 'http://www.example.com/source.ogg' ], 'data': '', 'transcripts': { 'ua': 'ukrainian_translation.srt', 'ge': 'german_translation.srt' } })
def test_has_changes_direct_only(self): """ Tests that has_changes() returns false when a new xblock in a direct only category is checked """ course_location = Location('edX', 'toy', '2012_Fall', 'course', '2012_Fall') chapter_location = Location('edX', 'toy', '2012_Fall', 'chapter', 'vertical_container') # Create dummy direct only xblocks self.draft_store.create_item(self.dummy_user, chapter_location.course_key, chapter_location.block_type, block_id=chapter_location.block_id) # Check that neither xblock has changes self.assertFalse(self.draft_store.has_changes(course_location)) self.assertFalse(self.draft_store.has_changes(chapter_location))
def test_has_changes_missing_child(self): """ Tests that has_changes() returns False when a published parent points to a child that doesn't exist. """ location = Location('edX', 'toy', '2012_Fall', 'sequential', 'parent') # Create the parent and point it to a fake child parent = self.draft_store.create_item(self.dummy_user, location.course_key, location.block_type, block_id=location.block_id) parent.children += [ Location('edX', 'toy', '2012_Fall', 'vertical', 'does_not_exist') ] self.draft_store.update_item(parent, self.dummy_user) # Check the parent for changes should return False and not throw an exception self.assertFalse(self.draft_store.has_changes(location))
def test_get_courses_for_wiki(self): """ Test the get_courses_for_wiki method """ for course_number in self.courses: course_locations = self.store.get_courses_for_wiki(course_number) assert_equals(len(course_locations), 1) assert_equals( Location('edX', course_number, '2012_Fall', 'course', '2012_Fall'), course_locations[0]) course_locations = self.store.get_courses_for_wiki('no_such_wiki') assert_equals(len(course_locations), 0) # set toy course to share the wiki with simple course toy_course = self.store.get_course( SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')) toy_course.wiki_slug = 'simple' self.store.update_item(toy_course) # now toy_course should not be retrievable with old wiki_slug course_locations = self.store.get_courses_for_wiki('toy') assert_equals(len(course_locations), 0) # but there should be two courses with wiki_slug 'simple' course_locations = self.store.get_courses_for_wiki('simple') assert_equals(len(course_locations), 2) for course_number in ['toy', 'simple']: assert_in( Location('edX', course_number, '2012_Fall', 'course', '2012_Fall'), course_locations) # configure simple course to use unique wiki_slug. simple_course = self.store.get_course( SlashSeparatedCourseKey('edX', 'simple', '2012_Fall')) simple_course.wiki_slug = 'edX.simple.2012_Fall' self.store.update_item(simple_course) # it should be retrievable with its new wiki_slug course_locations = self.store.get_courses_for_wiki( 'edX.simple.2012_Fall') assert_equals(len(course_locations), 1) assert_in( Location('edX', 'simple', '2012_Fall', 'course', '2012_Fall'), course_locations)
def setUp(self): field_data = Mock(spec=FieldData) self.descriptor = BrokenDescriptor( TestRuntime(Mock(spec=IdReader), field_data), field_data, ScopeIds(None, None, None, Location('org', 'course', 'run', 'broken', 'name', None))) self.descriptor.xmodule_runtime = TestRuntime(Mock(spec=IdReader), field_data) self.descriptor.xmodule_runtime.error_descriptor_class = ErrorDescriptor self.descriptor.xmodule_runtime.xmodule_instance = None
def test___find_corresponding_module_for_location_exceptions(self): """ Unit test for the exception cases of __find_corresponding_module_for_location Mainly for diff coverage @return: """ # pylint: disable=protected-access with self.assertRaises(ItemNotFoundError): self.peer_grading._find_corresponding_module_for_location( Location('org', 'course', 'run', 'category', 'name', 'revision'))