diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index 6d314684f9..91c7c04b06 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -9,10 +9,10 @@ from django.contrib.auth.models import User from xmodule.contentstore.django import _CONTENTSTORE from xmodule.modulestore.django import modulestore, clear_existing_modulestores from xmodule.modulestore import ModuleStoreEnum -from collections import namedtuple import datetime import pytz from xmodule.tabs import CoursewareTab, CourseInfoTab, StaticTab, DiscussionTab, ProgressTab, WikiTab +from xmodule.modulestore.tests.sample_courses import default_block_info_tree, TOY_BLOCK_INFO_TREE def mixed_store_config(data_dir, mappings): @@ -86,7 +86,6 @@ def split_mongo_store_config(data_dir): 'default_class': 'xmodule.raw_module.RawDescriptor', 'fs_root': data_dir, 'render_template': 'edxmako.shortcuts.render_to_string', - # ??? does this & draft need xblock_mixins? } store = { @@ -123,188 +122,7 @@ def xml_store_config(data_dir): return store -# used to create course subtrees in ModuleStoreTestCase.create_test_course -# adds to self properties w/ the given block_id which hold the UsageKey for easy retrieval. -# fields is a dictionary of keys and values. sub_tree is a collection of BlockInfo -BlockInfo = namedtuple('BlockInfo', 'block_id, category, fields, sub_tree') -default_block_info_tree = [ - BlockInfo( - 'chapter_x', 'chapter', {}, [ - BlockInfo( - 'sequential_x1', 'sequential', {}, [ - BlockInfo( - 'vertical_x1a', 'vertical', {}, [ - BlockInfo('problem_x1a_1', 'problem', {}, []), - BlockInfo('problem_x1a_2', 'problem', {}, []), - BlockInfo('problem_x1a_3', 'problem', {}, []), - BlockInfo('html_x1a_1', 'html', {}, []), - ] - ) - ] - ) - ] - ), - BlockInfo( - 'chapter_y', 'chapter', {}, [ - BlockInfo( - 'sequential_y1', 'sequential', {}, [ - BlockInfo( - 'vertical_y1a', 'vertical', {}, [ - BlockInfo('problem_y1a_1', 'problem', {}, []), - BlockInfo('problem_y1a_2', 'problem', {}, []), - BlockInfo('problem_y1a_3', 'problem', {}, []), - ] - ) - ] - ) - ] - ) -] -# equivalent to toy course in xml -TOY_BLOCK_INFO_TREE = [ - BlockInfo( - 'Overview', "chapter", {"display_name" : "Overview"}, [ - BlockInfo( - "Toy_Videos", "videosequence", { - "xml_attributes": {"filename": ["", None]}, "display_name": "Toy Videos", "format": "Lecture Sequence" - }, [ - BlockInfo( - "secret:toylab", "html", { - "data": "Lab 2A: Superposition Experiment\n\n<<<<<<< Updated upstream\n

Isn't the toy course great?

\n\n

Let's add some markup that uses non-ascii characters.\nFor example, we should be able to write words like encyclopædia, or foreign words like français.\nLooking beyond latin-1, we should handle math symbols: πr² ≤ ∞.\nAnd it shouldn't matter if we use entities or numeric codes — Ω ≠ π ≡ Ω ≠ π.\n

\n=======\n

Isn't the toy course great? — ≤

\n>>>>>>> Stashed changes\n", - "xml_attributes": { "filename" : [ "html/secret/toylab.xml", "html/secret/toylab.xml" ] }, - "display_name" : "Toy lab" - }, [] - ), - BlockInfo( - "toyjumpto", "html", { - "data" : "This is a link to another page and some Chinese 四節比分和七年前

Some more Chinese 四節比分和七年前

\n", - "xml_attributes": { "filename" : [ "html/toyjumpto.xml", "html/toyjumpto.xml" ] } - }, []), - BlockInfo( - "toyhtml", "html", { - "data" : "Sample", - "xml_attributes" : { "filename" : [ "html/toyhtml.xml", "html/toyhtml.xml" ] } - }, []), - BlockInfo( - "nonportable", "html", { - "data": "link\n", - "xml_attributes" : { "filename" : [ "html/nonportable.xml", "html/nonportable.xml" ] } - }, []), - BlockInfo( - "nonportable_link", "html", { - "data": "link\n\n", - "xml_attributes": {"filename": ["html/nonportable_link.xml", "html/nonportable_link.xml"]} - }, []), - BlockInfo( - "badlink", "html", { - "data": "\n", - "xml_attributes" : { "filename" : [ "html/badlink.xml", "html/badlink.xml" ] } - }, []), - BlockInfo( - "with_styling", "html", { - "data": "

Red text here

", - "xml_attributes": {"filename": ["html/with_styling.xml", "html/with_styling.xml"]} - }, []), - BlockInfo( - "just_img", "html", { - "data": "", - "xml_attributes": {"filename": [ "html/just_img.xml", "html/just_img.xml" ] } - }, []), - BlockInfo( - "Video_Resources", "video", { - "youtube_id_1_0" : "1bK-WdDi6Qw", "display_name" : "Video Resources" - }, []), - ]), - BlockInfo( - "Welcome", "video", {"data": "", "youtube_id_1_0": "p2Q6BrNhdh8", "display_name": "Welcome"}, [] - ), - BlockInfo( - "video_123456789012", "video", {"data": "", "youtube_id_1_0": "p2Q6BrNhdh8", "display_name": "Test Video"}, [] - ), - BlockInfo( - "video_4f66f493ac8f", "video", {"youtube_id_1_0": "p2Q6BrNhdh8"}, [] - ) - ] - ), - BlockInfo( - "secret:magic", "chapter", { - "xml_attributes": {"filename": [ "chapter/secret/magic.xml", "chapter/secret/magic.xml"]} - }, [ - BlockInfo( - "toyvideo", "video", {"youtube_id_1_0": "OEoXaMPEzfMA", "display_name": "toyvideo"}, [] - ) - ] - ), - BlockInfo( - "poll_test", "chapter", {}, [ - BlockInfo( - "T1_changemind_poll_foo", "poll_question", { - "question": "

Have you changed your mind? ’

", - "answers": [{"text": "Yes", "id": "yes"}, {"text": "No", "id": "no"}], - "xml_attributes": {"reset": "false", "filename": ["", None]}, - "display_name": "Change your answer" - }, []) ] - ), - BlockInfo( - "vertical_container", "chapter", { - "xml_attributes": {"filename": ["chapter/vertical_container.xml", "chapter/vertical_container.xml"]} - }, [ - BlockInfo("vertical_sequential", "sequential", {}, [ - BlockInfo("vertical_test", "vertical", { - "xml_attributes": {"filename": ["vertical/vertical_test.xml", "vertical_test"]} - }, [ - BlockInfo( - "sample_video", "video", { - "youtube_id_1_25": "AKqURZnYqpk", - "youtube_id_0_75": "JMD_ifUUfsU", - "youtube_id_1_0": "OEoXaMPEzfM", - "display_name": "default", - "youtube_id_1_5": "DYpADpL7jAY" - }, []), - BlockInfo( - "separate_file_video", "video", { - "youtube_id_1_25": "AKqURZnYqpk", - "youtube_id_0_75": "JMD_ifUUfsU", - "youtube_id_1_0": "OEoXaMPEzfM", - "display_name": "default", - "youtube_id_1_5": "DYpADpL7jAY" - }, []), - BlockInfo( - "video_with_end_time", "video", { - "youtube_id_1_25": "AKqURZnYqpk", - "display_name": "default", - "youtube_id_1_0": "OEoXaMPEzfM", - "end_time": datetime.timedelta(seconds=10), - "youtube_id_1_5": "DYpADpL7jAY", - "youtube_id_0_75": "JMD_ifUUfsU" - }, []), - BlockInfo( - "T1_changemind_poll_foo_2", "poll_question", { - "question": "

Have you changed your mind?

", - "answers": [{"text": "Yes", "id": "yes"}, {"text": "No", "id": "no"}], - "xml_attributes": {"reset": "false", "filename": [ "", None]}, - "display_name": "Change your answer" - }, []), - ]), - BlockInfo("unicode", "html", { - "data": "…", "xml_attributes": {"filename": ["", None]} - }, []) - ]), - ] - ), - BlockInfo( - "handout_container", "chapter", { - "xml_attributes" : {"filename" : ["chapter/handout_container.xml", "chapter/handout_container.xml"]} - }, [ - BlockInfo( - "html_7e5578f25f79", "html", { - "data": " handouts", - "xml_attributes": {"filename": ["", None]} - }, [] - ), - ] - ) -] + class ModuleStoreTestCase(TestCase): """ @@ -456,32 +274,34 @@ class ModuleStoreTestCase(TestCase): course_loc: the CourseKey for the created course """ with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, None): - # TODO use a single transaction (version, inheritance cache, etc) for this whole thing - course = self.store.create_course(org, course, run, self.user.id, fields=course_fields) - self.course_loc = course.location +# with self.store.bulk_write_operations(self.store.make_course_key(org, course, run)): + course = self.store.create_course(org, course, run, self.user.id, fields=course_fields) + self.course_loc = course.location - def create_sub_tree(parent_loc, block_info): - block = self.store.create_child( - self.user.id, - # TODO remove version_agnostic() when we impl the single transaction - parent_loc.version_agnostic(), - block_info.category, block_id=block_info.block_id, - fields=block_info.fields, - ) - for tree in block_info.sub_tree: - create_sub_tree(block.location, tree) - setattr(self, block_info.block_id, block.location.version_agnostic()) + def create_sub_tree(parent_loc, block_info): + block = self.store.create_child( + self.user.id, + # TODO remove version_agnostic() when we impl the single transaction + parent_loc.version_agnostic(), + block_info.category, block_id=block_info.block_id, + fields=block_info.fields, + ) + for tree in block_info.sub_tree: + create_sub_tree(block.location, tree) + setattr(self, block_info.block_id, block.location.version_agnostic()) - for tree in block_info_tree: - create_sub_tree(self.course_loc, tree) + for tree in block_info_tree: + create_sub_tree(self.course_loc, tree) - self.store.publish(self.course_loc, self.user.id) + # remove version_agnostic when bulk write works + self.store.publish(self.course_loc.version_agnostic(), self.user.id) return self.course_loc.course_key.version_agnostic() def create_toy_course(self, org='edX', course='toy', run='2012_Fall'): """ - Create an equiavlent to the toy xml course + Create an equivalent to the toy xml course """ +# with self.store.bulk_write_operations(self.store.make_course_key(org, course, run)): self.toy_loc = self.create_sample_course( org, course, run, TOY_BLOCK_INFO_TREE, { @@ -490,8 +310,8 @@ class ModuleStoreTestCase(TestCase): "display_name" : "Toy Course", "graded" : True, "tabs" : [ - CoursewareTab(), # {"type" : "courseware", "name" : "Courseware"}, - CourseInfoTab(), # {"type" : "course_info", "name" : "Course Info"}, + CoursewareTab(), + CourseInfoTab(), StaticTab(name="Syllabus", url_slug="syllabus"), StaticTab(name="Resources", url_slug="resources"), DiscussionTab(), diff --git a/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py b/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py new file mode 100644 index 0000000000..aa634cc09b --- /dev/null +++ b/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py @@ -0,0 +1,188 @@ +# encoding: utf-8 +""" +The data type and use of it for declaratively creating test courses. +""" +# used to create course subtrees in ModuleStoreTestCase.create_test_course +# adds to self properties w/ the given block_id which hold the UsageKey for easy retrieval. +# fields is a dictionary of keys and values. sub_tree is a collection of BlockInfo +from collections import namedtuple +import datetime +BlockInfo = namedtuple('BlockInfo', 'block_id, category, fields, sub_tree') +default_block_info_tree = [ + BlockInfo( + 'chapter_x', 'chapter', {}, [ + BlockInfo( + 'sequential_x1', 'sequential', {}, [ + BlockInfo( + 'vertical_x1a', 'vertical', {}, [ + BlockInfo('problem_x1a_1', 'problem', {}, []), + BlockInfo('problem_x1a_2', 'problem', {}, []), + BlockInfo('problem_x1a_3', 'problem', {}, []), + BlockInfo('html_x1a_1', 'html', {}, []), + ] + ) + ] + ) + ] + ), + BlockInfo( + 'chapter_y', 'chapter', {}, [ + BlockInfo( + 'sequential_y1', 'sequential', {}, [ + BlockInfo( + 'vertical_y1a', 'vertical', {}, [ + BlockInfo('problem_y1a_1', 'problem', {}, []), + BlockInfo('problem_y1a_2', 'problem', {}, []), + BlockInfo('problem_y1a_3', 'problem', {}, []), + ] + ) + ] + ) + ] + ) +] +# equivalent to toy course in xml +TOY_BLOCK_INFO_TREE = [ + BlockInfo( + 'Overview', "chapter", {"display_name" : "Overview"}, [ + BlockInfo( + "Toy_Videos", "videosequence", { + "xml_attributes": {"filename": ["", None]}, "display_name": "Toy Videos", "format": "Lecture Sequence" + }, [ + BlockInfo( + "secret:toylab", "html", { + "data": "Lab 2A: Superposition Experiment\n\n<<<<<<< Updated upstream\n

Isn't the toy course great?

\n\n

Let's add some markup that uses non-ascii characters.\nFor example, we should be able to write words like encyclopædia, or foreign words like français.\nLooking beyond latin-1, we should handle math symbols: πr² ≤ ∞.\nAnd it shouldn't matter if we use entities or numeric codes — Ω ≠ π ≡ Ω ≠ π.\n

\n=======\n

Isn't the toy course great? — ≤

\n>>>>>>> Stashed changes\n", + "xml_attributes": { "filename" : [ "html/secret/toylab.xml", "html/secret/toylab.xml" ] }, + "display_name" : "Toy lab" + }, [] + ), + BlockInfo( + "toyjumpto", "html", { + "data" : "This is a link to another page and some Chinese 四節比分和七年前

Some more Chinese 四節比分和七年前

\n", + "xml_attributes": { "filename" : [ "html/toyjumpto.xml", "html/toyjumpto.xml" ] } + }, []), + BlockInfo( + "toyhtml", "html", { + "data" : "Sample", + "xml_attributes" : { "filename" : [ "html/toyhtml.xml", "html/toyhtml.xml" ] } + }, []), + BlockInfo( + "nonportable", "html", { + "data": "link\n", + "xml_attributes" : { "filename" : [ "html/nonportable.xml", "html/nonportable.xml" ] } + }, []), + BlockInfo( + "nonportable_link", "html", { + "data": "link\n\n", + "xml_attributes": {"filename": ["html/nonportable_link.xml", "html/nonportable_link.xml"]} + }, []), + BlockInfo( + "badlink", "html", { + "data": "\n", + "xml_attributes" : { "filename" : [ "html/badlink.xml", "html/badlink.xml" ] } + }, []), + BlockInfo( + "with_styling", "html", { + "data": "

Red text here

", + "xml_attributes": {"filename": ["html/with_styling.xml", "html/with_styling.xml"]} + }, []), + BlockInfo( + "just_img", "html", { + "data": "", + "xml_attributes": {"filename": [ "html/just_img.xml", "html/just_img.xml" ] } + }, []), + BlockInfo( + "Video_Resources", "video", { + "youtube_id_1_0" : "1bK-WdDi6Qw", "display_name" : "Video Resources" + }, []), + ]), + BlockInfo( + "Welcome", "video", {"data": "", "youtube_id_1_0": "p2Q6BrNhdh8", "display_name": "Welcome"}, [] + ), + BlockInfo( + "video_123456789012", "video", {"data": "", "youtube_id_1_0": "p2Q6BrNhdh8", "display_name": "Test Video"}, [] + ), + BlockInfo( + "video_4f66f493ac8f", "video", {"youtube_id_1_0": "p2Q6BrNhdh8"}, [] + ) + ] + ), + BlockInfo( + "secret:magic", "chapter", { + "xml_attributes": {"filename": [ "chapter/secret/magic.xml", "chapter/secret/magic.xml"]} + }, [ + BlockInfo( + "toyvideo", "video", {"youtube_id_1_0": "OEoXaMPEzfMA", "display_name": "toyvideo"}, [] + ) + ] + ), + BlockInfo( + "poll_test", "chapter", {}, [ + BlockInfo( + "T1_changemind_poll_foo", "poll_question", { + "question": "

Have you changed your mind? ’

", + "answers": [{"text": "Yes", "id": "yes"}, {"text": "No", "id": "no"}], + "xml_attributes": {"reset": "false", "filename": ["", None]}, + "display_name": "Change your answer" + }, []) ] + ), + BlockInfo( + "vertical_container", "chapter", { + "xml_attributes": {"filename": ["chapter/vertical_container.xml", "chapter/vertical_container.xml"]} + }, [ + BlockInfo("vertical_sequential", "sequential", {}, [ + BlockInfo("vertical_test", "vertical", { + "xml_attributes": {"filename": ["vertical/vertical_test.xml", "vertical_test"]} + }, [ + BlockInfo( + "sample_video", "video", { + "youtube_id_1_25": "AKqURZnYqpk", + "youtube_id_0_75": "JMD_ifUUfsU", + "youtube_id_1_0": "OEoXaMPEzfM", + "display_name": "default", + "youtube_id_1_5": "DYpADpL7jAY" + }, []), + BlockInfo( + "separate_file_video", "video", { + "youtube_id_1_25": "AKqURZnYqpk", + "youtube_id_0_75": "JMD_ifUUfsU", + "youtube_id_1_0": "OEoXaMPEzfM", + "display_name": "default", + "youtube_id_1_5": "DYpADpL7jAY" + }, []), + BlockInfo( + "video_with_end_time", "video", { + "youtube_id_1_25": "AKqURZnYqpk", + "display_name": "default", + "youtube_id_1_0": "OEoXaMPEzfM", + "end_time": datetime.timedelta(seconds=10), + "youtube_id_1_5": "DYpADpL7jAY", + "youtube_id_0_75": "JMD_ifUUfsU" + }, []), + BlockInfo( + "T1_changemind_poll_foo_2", "poll_question", { + "question": "

Have you changed your mind?

", + "answers": [{"text": "Yes", "id": "yes"}, {"text": "No", "id": "no"}], + "xml_attributes": {"reset": "false", "filename": [ "", None]}, + "display_name": "Change your answer" + }, []), + ]), + BlockInfo("unicode", "html", { + "data": "…", "xml_attributes": {"filename": ["", None]} + }, []) + ]), + ] + ), + BlockInfo( + "handout_container", "chapter", { + "xml_attributes" : {"filename" : ["chapter/handout_container.xml", "chapter/handout_container.xml"]} + }, [ + BlockInfo( + "html_7e5578f25f79", "html", { + "data": " handouts", + "xml_attributes": {"filename": ["", None]} + }, [] + ), + ] + ) +]