def check_export_roundtrip(self, data_dir, course_dir, mock_get): # Patch network calls to retrieve the textbook TOC mock_get.return_value.text = dedent(""" <?xml version="1.0"?><table_of_contents> <entry page="5" page_label="ii" name="Table of Contents"/> </table_of_contents> """).strip() root_dir = path(self.temp_dir) print("Copying test course to temp dir {0}".format(root_dir)) data_dir = path(data_dir) shutil.copytree(data_dir / course_dir, root_dir / course_dir) print("Starting import") initial_import = XMLModuleStore(root_dir, course_dirs=[course_dir]) courses = initial_import.get_courses() self.assertEquals(len(courses), 1) initial_course = courses[0] # export to the same directory--that way things like the custom_tags/ folder # will still be there. print("Starting export") fs = OSFS(root_dir) export_fs = fs.makeopendir(course_dir) xml = initial_course.export_to_xml(export_fs) with export_fs.open('course.xml', 'w') as course_xml: course_xml.write(xml) print("Starting second import") second_import = XMLModuleStore(root_dir, course_dirs=[course_dir]) courses2 = second_import.get_courses() self.assertEquals(len(courses2), 1) exported_course = courses2[0] print("Checking course equality") # HACK: filenames change when changing file formats # during imports from old-style courses. Ignore them. strip_filenames(initial_course) strip_filenames(exported_course) self.assertEquals(initial_course, exported_course) self.assertEquals(initial_course.id, exported_course.id) course_id = initial_course.id print("Checking key equality") self.assertEquals(sorted(initial_import.modules[course_id].keys()), sorted(second_import.modules[course_id].keys())) print("Checking module equality") for location in initial_import.modules[course_id].keys(): print("Checking", location) self.assertEquals(initial_import.modules[course_id][location], second_import.modules[course_id][location])
def check_export_roundtrip(self, data_dir, course_dir): root_dir = path(self.temp_dir) print("Copying test course to temp dir {0}".format(root_dir)) data_dir = path(data_dir) shutil.copytree(data_dir / course_dir, root_dir / course_dir) print("Starting import") initial_import = XMLModuleStore(root_dir, course_dirs=[course_dir]) courses = initial_import.get_courses() self.assertEquals(len(courses), 1) initial_course = courses[0] # export to the same directory--that way things like the custom_tags/ folder # will still be there. print("Starting export") fs = OSFS(root_dir) export_fs = fs.makeopendir(course_dir) xml = initial_course.export_to_xml(export_fs) with export_fs.open('course.xml', 'w') as course_xml: course_xml.write(xml) print("Starting second import") second_import = XMLModuleStore(root_dir, course_dirs=[course_dir]) courses2 = second_import.get_courses() self.assertEquals(len(courses2), 1) exported_course = courses2[0] print("Checking course equality") # HACK: filenames change when changing file formats # during imports from old-style courses. Ignore them. strip_filenames(initial_course) strip_filenames(exported_course) self.assertEquals(initial_course, exported_course) self.assertEquals(initial_course.id, exported_course.id) course_id = initial_course.id print("Checking key equality") self.assertEquals(sorted(initial_import.modules[course_id].keys()), sorted(second_import.modules[course_id].keys())) print("Checking module equality") for location in initial_import.modules[course_id].keys(): print("Checking", location) if location.category == 'html': print( "Skipping html modules--they can't import in" " final form without writing files..." ) continue self.assertEquals(initial_import.modules[course_id][location], second_import.modules[course_id][location])
def check_export_roundtrip(self, data_dir, course_dir): root_dir = path(self.temp_dir) print("Copying test course to temp dir {0}".format(root_dir)) data_dir = path(data_dir) shutil.copytree(data_dir / course_dir, root_dir / course_dir) print("Starting import") initial_import = XMLModuleStore(root_dir, course_dirs=[course_dir]) courses = initial_import.get_courses() self.assertEquals(len(courses), 1) initial_course = courses[0] # export to the same directory--that way things like the custom_tags/ folder # will still be there. print("Starting export") fs = OSFS(root_dir) export_fs = fs.makeopendir(course_dir) xml = initial_course.export_to_xml(export_fs) with export_fs.open('course.xml', 'w') as course_xml: course_xml.write(xml) print("Starting second import") second_import = XMLModuleStore(root_dir, course_dirs=[course_dir]) courses2 = second_import.get_courses() self.assertEquals(len(courses2), 1) exported_course = courses2[0] print("Checking course equality") # HACK: filenames change when changing file formats # during imports from old-style courses. Ignore them. strip_filenames(initial_course) strip_filenames(exported_course) self.assertEquals(initial_course, exported_course) self.assertEquals(initial_course.id, exported_course.id) course_id = initial_course.id print("Checking key equality") self.assertEquals(sorted(initial_import.modules[course_id].keys()), sorted(second_import.modules[course_id].keys())) print("Checking module equality") for location in initial_import.modules[course_id].keys(): print("Checking", location) if location.category == 'html': print( "Skipping html modules--they can't import in" " final form without writing files..." ) continue self.assertEquals(initial_import.modules[course_id][location], second_import.modules[course_id][location])
def test_colon_in_url_name(self): """Ensure that colons in url_names convert to file paths properly""" print "Starting import" # Not using get_courses because we need the modulestore object too afterward modulestore = XMLModuleStore(DATA_DIR, source_dirs=['toy']) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) course = courses[0] print "course errors:" for (msg, err) in modulestore.get_course_errors(course.id): print msg print err chapters = course.get_children() self.assertEquals(len(chapters), 5) ch2 = chapters[1] self.assertEquals(ch2.url_name, "secret:magic") print "Ch2 location: ", ch2.location also_ch2 = modulestore.get_item(ch2.location) self.assertEquals(ch2, also_ch2) print "making sure html loaded" loc = course.id.make_usage_key('html', 'secret:toylab') html = modulestore.get_item(loc) self.assertEquals(html.display_name, "Toy lab")
def test_unicode(self): """Check that courses with unicode characters in filenames and in org/course/name import properly. Currently, this means: (a) Having files with unicode names does not prevent import; (b) if files are not loaded because of unicode filenames, there are appropriate exceptions/errors to that effect.""" print("Starting import") modulestore = XMLModuleStore(DATA_DIR, course_dirs=['test_unicode']) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) course = courses[0] print("course errors:") # Expect to find an error/exception about characters in "®esources" expect = "InvalidKeyError" errors = [ (msg.encode("utf-8"), err.encode("utf-8")) for msg, err in modulestore.get_course_errors(course.id) ] self.assertTrue(any( expect in msg or expect in err for msg, err in errors )) chapters = course.get_children() self.assertEqual(len(chapters), 4)
def test_poll_and_conditional_import(self): modulestore = XMLModuleStore(DATA_DIR, course_dirs=['conditional_and_poll']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) conditional_location = course.id.make_usage_key('conditional', 'condone') module = modulestore.get_item(conditional_location) self.assertEqual(len(module.children), 1) poll_location = course.id.make_usage_key('poll_question', 'first_poll') module = modulestore.get_item(poll_location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.voted, False) self.assertEqual(module.poll_answer, '') self.assertEqual(module.poll_answers, {}) self.assertEqual( module.answers, [ {'text': u'Yes', 'id': 'Yes'}, {'text': u'No', 'id': 'No'}, {'text': u"Don't know", 'id': 'Dont_know'} ] )
def test_unicode(self): """Check that courses with unicode characters in filenames and in org/course/name import properly. Currently, this means: (a) Having files with unicode names does not prevent import; (b) if files are not loaded because of unicode filenames, there are appropriate exceptions/errors to that effect.""" print("Starting import") modulestore = XMLModuleStore(DATA_DIR, source_dirs=['test_unicode']) courses = modulestore.get_courses() assert len(courses) == 1 course = courses[0] print("course errors:") # Expect to find an error/exception about characters in "®esources" expect = "InvalidKeyError" errors = [ (msg, err) for msg, err # lint-amnesty, pylint: disable=unnecessary-comprehension in modulestore.get_course_errors(course.id) ] assert any( ((expect in msg) or (expect in err)) for (msg, err) in errors) chapters = course.get_children() assert len(chapters) == 4
def test_dag_course(self, mock_logging): """ Test a course whose structure is not a tree. """ store = XMLModuleStore( DATA_DIR, source_dirs=['xml_dag'], xblock_mixins=(XModuleMixin, ), ) course_key = store.get_courses()[0].id mock_logging.warning.assert_called_with( "%s has more than one definition", course_key.make_usage_key('discussion', 'duplicate_def')) shared_item_loc = course_key.make_usage_key('html', 'toyhtml') shared_item = store.get_item(shared_item_loc) parent = shared_item.get_parent() self.assertIsNotNone(parent, "get_parent failed to return a value") parent_loc = course_key.make_usage_key('vertical', 'vertical_test') self.assertEqual(parent.location, parent_loc) self.assertIn(shared_item.location, [x.location for x in parent.get_children()]) # ensure it's still a child of the other parent even tho it doesn't claim the other parent as its parent other_parent_loc = course_key.make_usage_key('vertical', 'zeta') other_parent = store.get_item(other_parent_loc) # children rather than get_children b/c the instance returned by get_children != shared_item self.assertIn(shared_item_loc, other_parent.children)
def test_get_courses_for_wiki(self): """ Test the get_courses_for_wiki method """ store = XMLModuleStore(DATA_DIR, source_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_key, 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( CourseKey.from_string('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( CourseKey.from_string('/'.join( ['edX', course_number, '2012_Fall'])), course_locations)
def import_course(course_dir, verbose=True): course_dir = path(course_dir) data_dir = course_dir.dirname() course_dirs = [course_dir.basename()] # No default class--want to complain if it doesn't find plugins for any # module. modulestore = XMLModuleStore(data_dir, default_class=None, course_dirs=course_dirs) def str_of_err(tpl): (msg, exc_str) = tpl return '{msg}\n{exc}'.format(msg=msg, exc=exc_str) courses = modulestore.get_courses() n = len(courses) if n != 1: sys.stderr.write('ERROR: Expect exactly 1 course. Loaded {n}: {lst}\n'.format( n=n, lst=courses)) return None course = courses[0] errors = modulestore.get_item_errors(course.location) if len(errors) != 0: sys.stderr.write('ERRORs during import: {0}\n'.format( '\n'.join(map(str_of_err, errors)))) return course
def test_colon_in_url_name(self): """Ensure that colons in url_names convert to file paths properly""" print("Starting import") # Not using get_courses because we need the modulestore object too afterward modulestore = XMLModuleStore(DATA_DIR, source_dirs=['toy']) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) course = courses[0] print("course errors:") for (msg, err) in modulestore.get_course_errors(course.id): print(msg) print(err) chapters = course.get_children() self.assertEquals(len(chapters), 5) ch2 = chapters[1] self.assertEquals(ch2.url_name, "secret:magic") print("Ch2 location: ", ch2.location) also_ch2 = modulestore.get_item(ch2.location) self.assertEquals(ch2, also_ch2) print("making sure html loaded") loc = course.id.make_usage_key('html', 'secret:toylab') html = modulestore.get_item(loc) self.assertEquals(html.display_name, "Toy lab")
def test_poll_and_conditional_import(self): modulestore = XMLModuleStore(DATA_DIR, source_dirs=['conditional_and_poll']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) conditional_location = course.id.make_usage_key( 'conditional', 'condone') module = modulestore.get_item(conditional_location) self.assertEqual(len(module.children), 1) poll_location = course.id.make_usage_key('poll_question', 'first_poll') module = modulestore.get_item(poll_location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.voted, False) self.assertEqual(module.poll_answer, '') self.assertEqual(module.poll_answers, {}) self.assertEqual(module.answers, [{ 'text': u'Yes', 'id': 'Yes' }, { 'text': u'No', 'id': 'No' }, { 'text': u"Don't know", 'id': 'Dont_know' }])
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 test_poll_and_conditional_import(self): modulestore = XMLModuleStore(DATA_DIR, course_dirs=["conditional_and_poll"]) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) location = course.location conditional_location = Location(location.tag, location.org, location.course, "conditional", "condone") module = modulestore.get_instance(course.id, conditional_location) self.assertEqual(len(module.children), 1) poll_location = Location(location.tag, location.org, location.course, "poll_question", "first_poll") module = modulestore.get_instance(course.id, poll_location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.voted, False) self.assertEqual(module.poll_answer, "") self.assertEqual(module.poll_answers, {}) self.assertEqual( module.answers, [{"text": u"Yes", "id": "Yes"}, {"text": u"No", "id": "No"}, {"text": u"Don't know", "id": "Dont_know"}], )
def test_colon_in_url_name(self): """Ensure that colons in url_names convert to file paths properly""" print("Starting import") # Not using get_courses because we need the modulestore object too afterward modulestore = XMLModuleStore(DATA_DIR, course_dirs=['toy']) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) course = courses[0] course_id = course.id print("course errors:") for (msg, err) in modulestore.get_item_errors(course.location): print(msg) print(err) chapters = course.get_children() self.assertEquals(len(chapters), 2) ch2 = chapters[1] self.assertEquals(ch2.url_name, "secret:magic") print("Ch2 location: ", ch2.location) also_ch2 = modulestore.get_instance(course_id, ch2.location) self.assertEquals(ch2, also_ch2) print("making sure html loaded") cloc = course.location loc = Location(cloc.tag, cloc.org, cloc.course, 'html', 'secret:toylab') html = modulestore.get_instance(course_id, loc) self.assertEquals(html.display_name, "Toy lab")
def test_unicode(self): """Check that courses with unicode characters in filenames and in org/course/name import properly. Currently, this means: (a) Having files with unicode names does not prevent import; (b) if files are not loaded because of unicode filenames, there are appropriate exceptions/errors to that effect.""" print "Starting import" modulestore = XMLModuleStore(DATA_DIR, source_dirs=['test_unicode']) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) course = courses[0] print "course errors:" # Expect to find an error/exception about characters in "®esources" expect = "InvalidKeyError" errors = [ (msg.encode("utf-8"), err.encode("utf-8")) for msg, err in modulestore.get_course_errors(course.id) ] self.assertTrue(any( expect in msg or expect in err for msg, err in errors )) chapters = course.get_children() self.assertEqual(len(chapters), 4)
def test_dag_course(self, mock_logging): """ Test a course whose structure is not a tree. """ store = XMLModuleStore( DATA_DIR, source_dirs=['xml_dag'], xblock_mixins=(XModuleMixin,), ) course_key = store.get_courses()[0].id mock_logging.warning.assert_called_with( "%s has more than one definition", course_key.make_usage_key('discussion', 'duplicate_def') ) shared_item_loc = course_key.make_usage_key('html', 'toyhtml') shared_item = store.get_item(shared_item_loc) parent = shared_item.get_parent() self.assertIsNotNone(parent, "get_parent failed to return a value") parent_loc = course_key.make_usage_key('vertical', 'vertical_test') self.assertEqual(parent.location, parent_loc) self.assertIn(shared_item, parent.get_children()) # ensure it's still a child of the other parent even tho it doesn't claim the other parent as its parent other_parent_loc = course_key.make_usage_key('vertical', 'zeta') other_parent = store.get_item(other_parent_loc) # children rather than get_children b/c the instance returned by get_children != shared_item self.assertIn(shared_item_loc, other_parent.children)
def import_course(course_dir, verbose=True): course_dir = path(course_dir) data_dir = course_dir.dirname() course_dirs = [course_dir.basename()] # No default class--want to complain if it doesn't find plugins for any # module. modulestore = XMLModuleStore(data_dir, default_class=None, course_dirs=course_dirs) def str_of_err(tpl): (msg, exc_str) = tpl return '{msg}\n{exc}'.format(msg=msg, exc=exc_str) courses = modulestore.get_courses() n = len(courses) if n != 1: sys.stderr.write( 'ERROR: Expect exactly 1 course. Loaded {n}: {lst}\n'.format( n=n, lst=courses)) return None course = courses[0] errors = modulestore.get_course_errors(course.id) if len(errors) != 0: sys.stderr.write('ERRORs during import: {0}\n'.format('\n'.join( map(str_of_err, errors)))) return course
def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" print("Importing {0}".format(name)) modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name]) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) return courses[0]
def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" print("Importing {0}".format(name)) modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name]) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) return courses[0]
def import_with_checks(course_dir): all_ok = True print('Attempting to load "{}"'.format(course_dir)) course_dir = path(course_dir) data_dir = course_dir.dirname() source_dirs = [course_dir.basename()] # No default class--want to complain if it doesn't find plugins for any # module. modulestore = XMLModuleStore( data_dir, default_class=None, source_dirs=source_dirs ) def str_of_err(tpl): (msg, exc_str) = tpl return '{msg}\n{exc}'.format(msg=msg, exc=exc_str) courses = modulestore.get_courses() n = len(courses) if n != 1: print('ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format(n=n, lst=courses)) return (False, None) course = courses[0] errors = modulestore.get_course_errors(course.id) if len(errors) != 0: all_ok = False print( '\n' + '========================================' + 'ERRORs during import:' + '\n'.join(map(str_of_err, errors)) + '========================================' + '\n' ) # print course validators = ( traverse_tree, ) print('========================================') print('Running validators...') for validate in validators: print('Running {}'.format(validate.__name__)) all_ok = validate(course) and all_ok if all_ok: print('Course passes all checks!') else: print('Course fails some checks. See above for errors.') return all_ok, course
def import_with_checks(course_dir): all_ok = True print(u'Attempting to load "{}"'.format(course_dir)) course_dir = path(course_dir) data_dir = course_dir.dirname() source_dirs = [course_dir.basename()] # No default class--want to complain if it doesn't find plugins for any # module. modulestore = XMLModuleStore( data_dir, default_class=None, source_dirs=source_dirs ) def str_of_err(tpl): (msg, exc_str) = tpl return '{msg}\n{exc}'.format(msg=msg, exc=exc_str) courses = modulestore.get_courses() n = len(courses) if n != 1: print(u'ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format(n=n, lst=courses)) return (False, None) course = courses[0] errors = modulestore.get_course_errors(course.id) if len(errors) != 0: all_ok = False print( '\n' + '========================================' + 'ERRORs during import:' + '\n'.join(map(str_of_err, errors)) + '========================================' + '\n' ) # print course validators = ( traverse_tree, ) print('========================================') print('Running validators...') for validate in validators: print(u'Running {}'.format(validate.__name__)) all_ok = validate(course) and all_ok if all_ok: print('Course passes all checks!') else: print('Course fails some checks. See above for errors.') return all_ok, course
def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" print(f"Importing {name}") modulestore = XMLModuleStore(DATA_DIR, source_dirs=[name]) courses = modulestore.get_courses() self.modulestore = modulestore # lint-amnesty, pylint: disable=attribute-defined-outside-init assert len(courses) == 1 return courses[0]
def import_with_checks(course_dir, verbose=True): all_ok = True print "Attempting to load '{0}'".format(course_dir) course_dir = path(course_dir) data_dir = course_dir.dirname() course_dirs = [course_dir.basename()] # No default class--want to complain if it doesn't find plugins for any # module. modulestore = XMLModuleStore(data_dir, default_class=None, course_dirs=course_dirs) def str_of_err(tpl): (msg, exc_str) = tpl return '{msg}\n{exc}'.format(msg=msg, exc=exc_str) courses = modulestore.get_courses() n = len(courses) if n != 1: print 'ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format( n=n, lst=courses) return (False, None) course = courses[0] errors = modulestore.get_item_errors(course.location) if len(errors) != 0: all_ok = False print '\n' print "=" * 40 print 'ERRORs during import:' print '\n'.join(map(str_of_err, errors)) print "=" * 40 print '\n' #print course validators = ( traverse_tree, ) print "=" * 40 print "Running validators..." for validate in validators: print 'Running {0}'.format(validate.__name__) all_ok = validate(course) and all_ok if all_ok: print 'Course passes all checks!' else: print "Course fails some checks. See above for errors." return all_ok, course
def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" print("Importing {0}".format(name)) modulestore = XMLModuleStore( DATA_DIR, course_dirs=[name], xblock_mixins=(InheritanceMixin,), xblock_select=only_xmodules ) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) return courses[0]
def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" print("Importing {0}".format(name)) modulestore = XMLModuleStore( DATA_DIR, source_dirs=[name], xblock_mixins=(InheritanceMixin, ), xblock_select=only_xmodules, ) courses = modulestore.get_courses() self.assertEquals(len(courses), 1) return courses[0]
def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" print(f"Importing {name}") modulestore = XMLModuleStore( DATA_DIR, source_dirs=[name], xblock_mixins=(InheritanceMixin, ), xblock_select=only_xmodules, ) courses = modulestore.get_courses() assert len(courses) == 1 return courses[0]
def test_word_cloud_import(self): modulestore = XMLModuleStore(DATA_DIR, course_dirs=['word_cloud']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) location = course.id.make_usage_key('word_cloud', 'cloud1') module = modulestore.get_item(location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.num_inputs, 5) self.assertEqual(module.num_top_words, 250)
def test_word_cloud_import(self): modulestore = XMLModuleStore(DATA_DIR, source_dirs=['word_cloud']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() assert len(sections) == 1 location = course.id.make_usage_key('word_cloud', 'cloud1') module = modulestore.get_item(location) assert len(module.get_children()) == 0 assert module.num_inputs == 5 assert module.num_top_words == 250
def test_word_cloud_import(self): modulestore = XMLModuleStore(DATA_DIR, source_dirs=['word_cloud']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) location = course.id.make_usage_key('word_cloud', 'cloud1') module = modulestore.get_item(location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.num_inputs, 5) self.assertEqual(module.num_top_words, 250)
def test_course(directory): """Import the course, run tests that require the course objects, and generate reports Args: directory (str): Path to directory that contains the course folders """ # Set django settings to studio test settings os.environ['DJANGO_SETTINGS_MODULE'] = 'cms.envs.test' # Setup logging level and capture stream root = logging.getLogger() root.setLevel(logging.DEBUG) output = StringIO() handler = logging.StreamHandler(output) handler.setLevel(logging.DEBUG) handler.setFormatter(logging.Formatter('%(levelname)s|%(message)s')) root.addHandler(handler) modulestore = XMLModuleStore(directory) courses = modulestore.get_courses() # Validate we have one and only one course results = [] import_test = TestResultList('Test Importability') result = TestResult('Course import success', True) if len(courses) != 1: result.result = False import_test.append(result) results.append(import_test) # Course import is dep for all further tests, so just fail out if not result.result: report_results(results) sys.exit(1) course = modulestore.courses.get(modulestore.courses.keys()[0]) results.append(check_image(directory, course)) results.append(check_alt_tags(course)) results.append(check_captions(course)) results.append(check_links(course)) if report_results(results): sys.exit(1) render_report_results(course, output.getvalue())
def test_word_cloud_import(self): modulestore = XMLModuleStore(DATA_DIR, course_dirs=["word_cloud"]) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) location = course.location location = Location(location.tag, location.org, location.course, "word_cloud", "cloud1") module = modulestore.get_instance(course.id, location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.num_inputs, 5) self.assertEqual(module.num_top_words, 250)
def test_branch_setting(self): """ Test the branch setting context manager """ store = XMLModuleStore(DATA_DIR, source_dirs=['toy']) course = store.get_courses()[0] # XML store allows published_only branch setting with store.branch_setting(ModuleStoreEnum.Branch.published_only, course.id): store.get_item(course.location) # XML store does NOT allow draft_preferred branch setting with self.assertRaises(ValueError): with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id): # verify that the above context manager raises a ValueError pass # pragma: no cover
def test_word_cloud_import(self): modulestore = XMLModuleStore(DATA_DIR, course_dirs=['word_cloud']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) location = course.location location = Location(location.tag, location.org, location.course, 'word_cloud', 'cloud1') module = modulestore.get_instance(course.id, location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.num_inputs, 5) self.assertEqual(module.num_top_words, 250)
class DummyModulestore(object): """ A mixin that allows test classes to have convenience functions to get a module given a location """ get_test_system = get_test_system() def setup_modulestore(self, name): self.modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name]) def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" courses = self.modulestore.get_courses() return courses[0] def get_module_from_location(self, location, course): course = self.get_course(course) if not isinstance(location, Location): location = Location(location) descriptor = self.modulestore.get_instance(course.id, location, depth=None) return descriptor.xmodule(self.test_system)
def test_poll_and_conditional_import(self): modulestore = XMLModuleStore(DATA_DIR, source_dirs=['conditional_and_poll']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() assert len(sections) == 1 conditional_location = course.id.make_usage_key('conditional', 'condone') module = modulestore.get_item(conditional_location) assert len(module.children) == 1 poll_location = course.id.make_usage_key('poll_question', 'first_poll') module = modulestore.get_item(poll_location) assert len(module.get_children()) == 0 assert module.voted is False assert module.poll_answer == '' assert module.poll_answers == {} assert module.answers ==\ [{'text': u'Yes', 'id': 'Yes'}, {'text': u'No', 'id': 'No'}, {'text': u"Don't know", 'id': 'Dont_know'}]
class DummyModulestore(object): """ A mixin that allows test classes to have convenience functions to get a module given a location """ def get_module_system(self, descriptor): raise NotImplementedError("Sub-tests must specify how to generate a module-system") def setup_modulestore(self, name): self.modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name]) def get_course(self, _): """Get a test course by directory name. If there's more than one, error.""" courses = self.modulestore.get_courses() return courses[0] def get_module_from_location(self, location, course): course = self.get_course(course) if not isinstance(location, Location): location = Location(location) descriptor = self.modulestore.get_instance(course.id, location, depth=None) descriptor.xmodule_runtime = self.get_module_system(descriptor) return descriptor
def test_get_courses_for_wiki(self): """ Test the get_courses_for_wiki method """ store = XMLModuleStore(DATA_DIR, source_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_key, 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(CourseKey.from_string('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(CourseKey.from_string('/'.join(['edX', course_number, '2012_Fall'])), course_locations)
def test_poll_and_conditional_import(self): modulestore = XMLModuleStore(DATA_DIR, course_dirs=['conditional_and_poll']) course = modulestore.get_courses()[0] chapters = course.get_children() ch1 = chapters[0] sections = ch1.get_children() self.assertEqual(len(sections), 1) location = course.location conditional_location = Location(location.tag, location.org, location.course, 'conditional', 'condone') module = modulestore.get_instance(course.id, conditional_location) self.assertEqual(len(module.children), 1) poll_location = Location(location.tag, location.org, location.course, 'poll_question', 'first_poll') module = modulestore.get_instance(course.id, poll_location) self.assertEqual(len(module.get_children()), 0) self.assertEqual(module.voted, False) self.assertEqual(module.poll_answer, '') self.assertEqual(module.poll_answers, {}) self.assertEqual(module.answers, [{ 'text': u'Yes', 'id': 'Yes' }, { 'text': u'No', 'id': 'No' }, { 'text': u"Don't know", 'id': 'Dont_know' }])
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)
class ConditionalBlockXmlTest(unittest.TestCase): """ Make sure ConditionalBlock works, by loading data in from an XML-defined course. """ def setUp(self): super().setUp() self.test_system = get_test_system() self.modulestore = XMLModuleStore(DATA_DIR, source_dirs=['conditional_and_poll']) courses = self.modulestore.get_courses() assert len(courses) == 1 self.course = courses[0] def get_module_for_location(self, location): descriptor = self.modulestore.get_item(location, depth=None) return self.test_system.get_module(descriptor) @patch('xmodule.x_module.descriptor_global_local_resource_url') @patch.dict(settings.FEATURES, {'ENABLE_EDXNOTES': False}) def test_conditional_module(self, _): """Make sure that conditional module works""" # edx - HarvardX # cond_test - ER22x location = BlockUsageLocator(CourseLocator("HarvardX", "ER22x", "2013_Spring", deprecated=True), "conditional", "condone", deprecated=True) module = self.get_module_for_location(location) html = module.render(STUDENT_VIEW).content mako_service = module.xmodule_runtime.service(module, 'mako') html_expect = mako_service.render_template( 'conditional_ajax.html', { # Test ajax url is just usage-id / handler_name 'ajax_url': f'{str(location)}/xmodule_handler', 'element_id': 'i4x-HarvardX-ER22x-conditional-condone', 'depends': 'i4x-HarvardX-ER22x-problem-choiceprob' }) assert html == html_expect ajax = json.loads(module.handle_ajax('', '')) fragments = ajax['fragments'] assert not any( ('This is a secret' in item['content']) for item in fragments) # Now change state of the capa problem to make it completed inner_module = self.get_module_for_location( location.replace(category="problem", name='choiceprob')) inner_module.attempts = 1 # Save our modifications to the underlying KeyValueStore so they can be persisted inner_module.save() ajax = json.loads(module.handle_ajax('', '')) fragments = ajax['fragments'] assert any( ('This is a secret' in item['content']) for item in fragments) 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 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_parse_attr_values(self): root = '<conditional attempted="false"></conditional>' xml_object = etree.XML(root) definition = ConditionalBlock.definition_from_xml(xml_object, Mock())[0] expected_definition = { 'show_tag_list': [], 'conditional_attr': 'attempted', 'conditional_value': 'false', 'conditional_message': '' } assert definition == expected_definition def test_presence_attributes_in_xml_attributes(self): modules = ConditionalFactory.create(self.test_system) modules['cond_module'].save() modules['cond_module'].definition_to_xml(Mock()) expected_xml_attributes = { 'attempted': 'true', 'message': 'You must complete {link} before you can access this unit.', 'sources': '' } self.assertDictEqual(modules['cond_module'].xml_attributes, expected_xml_attributes)
def test_export_roundtrip(self, course_dir, mock_get): # Patch network calls to retrieve the textbook TOC mock_get.return_value.text = dedent(""" <?xml version="1.0"?><table_of_contents> <entry page="5" page_label="ii" name="Table of Contents"/> </table_of_contents> """).strip() root_dir = path(self.temp_dir) print "Copying test course to temp dir {0}".format(root_dir) data_dir = path(DATA_DIR) shutil.copytree(data_dir / course_dir, root_dir / course_dir) print "Starting import" initial_import = XMLModuleStore(root_dir, source_dirs=[course_dir], xblock_mixins=(XModuleMixin, )) courses = initial_import.get_courses() self.assertEquals(len(courses), 1) initial_course = courses[0] # export to the same directory--that way things like the custom_tags/ folder # will still be there. print "Starting export" file_system = OSFS(root_dir) initial_course.runtime.export_fs = file_system.makedir(course_dir, recreate=True) root = lxml.etree.Element('root') initial_course.add_xml_to_node(root) with initial_course.runtime.export_fs.open('course.xml', 'wb') as course_xml: lxml.etree.ElementTree(root).write(course_xml, encoding='utf-8') print "Starting second import" second_import = XMLModuleStore(root_dir, source_dirs=[course_dir], xblock_mixins=(XModuleMixin, )) courses2 = second_import.get_courses() self.assertEquals(len(courses2), 1) exported_course = courses2[0] print "Checking course equality" # HACK: filenames change when changing file formats # during imports from old-style courses. Ignore them. strip_filenames(initial_course) strip_filenames(exported_course) self.assertTrue(blocks_are_equivalent(initial_course, exported_course)) self.assertEquals(initial_course.id, exported_course.id) course_id = initial_course.id print "Checking key equality" self.assertItemsEqual(initial_import.modules[course_id].keys(), second_import.modules[course_id].keys()) print "Checking module equality" for location in initial_import.modules[course_id].keys(): print("Checking", location) self.assertTrue( blocks_are_equivalent( initial_import.modules[course_id][location], second_import.modules[course_id][location]))
def test_export_roundtrip(self, course_dir, mock_get): # Patch network calls to retrieve the textbook TOC mock_get.return_value.text = dedent(""" <?xml version="1.0"?><table_of_contents> <entry page="5" page_label="ii" name="Table of Contents"/> </table_of_contents> """).strip() root_dir = path(self.temp_dir) print "Copying test course to temp dir {0}".format(root_dir) data_dir = path(DATA_DIR) shutil.copytree(data_dir / course_dir, root_dir / course_dir) print "Starting import" initial_import = XMLModuleStore(root_dir, source_dirs=[course_dir], xblock_mixins=(XModuleMixin,)) courses = initial_import.get_courses() self.assertEquals(len(courses), 1) initial_course = courses[0] # export to the same directory--that way things like the custom_tags/ folder # will still be there. print "Starting export" file_system = OSFS(root_dir) initial_course.runtime.export_fs = file_system.makeopendir(course_dir) root = lxml.etree.Element('root') initial_course.add_xml_to_node(root) with initial_course.runtime.export_fs.open('course.xml', 'w') as course_xml: lxml.etree.ElementTree(root).write(course_xml) print "Starting second import" second_import = XMLModuleStore(root_dir, source_dirs=[course_dir], xblock_mixins=(XModuleMixin,)) courses2 = second_import.get_courses() self.assertEquals(len(courses2), 1) exported_course = courses2[0] print "Checking course equality" # HACK: filenames change when changing file formats # during imports from old-style courses. Ignore them. strip_filenames(initial_course) strip_filenames(exported_course) self.assertTrue(blocks_are_equivalent(initial_course, exported_course)) self.assertEquals(initial_course.id, exported_course.id) course_id = initial_course.id print "Checking key equality" self.assertItemsEqual( initial_import.modules[course_id].keys(), second_import.modules[course_id].keys() ) print "Checking module equality" for location in initial_import.modules[course_id].keys(): print("Checking", location) self.assertTrue(blocks_are_equivalent( initial_import.modules[course_id][location], second_import.modules[course_id][location] ))