diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index 4382c05764..2bb272bcfe 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -735,6 +735,29 @@ class MiscCourseTests(ContentStoreTestCase): # Remove tempdir shutil.rmtree(root_dir) + @mock.patch( + 'lms.djangoapps.ccx.modulestore.CCXModulestoreWrapper.get_item', + mock.Mock(return_value=mock.Mock(children=[])) + ) + def test_export_with_orphan_vertical(self): + """ + Tests that, export does not fail when a parent xblock does not have draft child xblock + information but the draft child xblock has parent information. + """ + # Make an existing unit a draft + self.store.convert_to_draft(self.problem.location, self.user.id) + root_dir = path(mkdtemp_clean()) + export_course_to_xml(self.store, None, self.course.id, root_dir, 'test_export') + + # Verify that problem is exported in the drafts. This is expected because we are + # mocking get_item to for drafts. Expect no draft is exported. + # Specifically get_item is used in `xmodule.modulestore.xml_exporter._export_drafts` + export_draft_dir = OSFS(root_dir / 'test_export/drafts') + self.assertEqual(len(export_draft_dir.listdir()), 0) + + # Remove tempdir + shutil.rmtree(root_dir) + def test_assets_overwrite(self): """ Tests that assets will similar 'displayname' will be overwritten during export """ content_store = contentstore() diff --git a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py index 7468e6755a..473236aefa 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py @@ -41,7 +41,6 @@ def _export_drafts(modulestore, course_key, export_fs, xml_centric_course_key): # Check to see if the returned draft modules have changes w.r.t. the published module. # Only modules with changes will be exported into the /drafts directory. draft_modules = [module for module in draft_modules if modulestore.has_changes(module)] - if draft_modules: draft_course_dir = export_fs.makeopendir(DRAFT_DIR) @@ -85,9 +84,12 @@ def _export_drafts(modulestore, course_key, export_fs, xml_centric_course_key): continue logging.debug('parent_loc = %s', draft_node.parent_location) - draft_node.module.xml_attributes['parent_url'] = draft_node.parent_url parent = modulestore.get_item(draft_node.parent_location) + + # Don't try to export orphaned items + if draft_node.module.location not in parent.children: + continue index = parent.children.index(draft_node.module.location) draft_node.module.xml_attributes['index_in_children_list'] = str(index)