Commit 701f5fc1 by David Ormsbee

Optimize test course creation with bulk_operations.

Use bulk operations to both minimize the number of writes
to MongoDB, as well as to suppress signals which could
trigger things like search indexing or course structure
caching.
parent cb217563
...@@ -371,54 +371,54 @@ class ModuleStoreTestCase(TestCase): ...@@ -371,54 +371,54 @@ class ModuleStoreTestCase(TestCase):
""" """
Create an equivalent to the toy xml course Create an equivalent to the toy xml course
""" """
# with self.store.bulk_operations(self.store.make_course_key(org, course, run)): with self.store.bulk_operations(self.store.make_course_key(org, course, run), emit_signals=False):
self.toy_loc = self.create_sample_course( # pylint: disable=attribute-defined-outside-init self.toy_loc = self.create_sample_course( # pylint: disable=attribute-defined-outside-init
org, course, run, TOY_BLOCK_INFO_TREE, org, course, run, TOY_BLOCK_INFO_TREE,
{ {
"textbooks": [["Textbook", "https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"]], "textbooks": [["Textbook", "https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"]],
"wiki_slug": "toy", "wiki_slug": "toy",
"display_name": "Toy Course", "display_name": "Toy Course",
"graded": True, "graded": True,
"discussion_topics": {"General": {"id": "i4x-edX-toy-course-2012_Fall"}}, "discussion_topics": {"General": {"id": "i4x-edX-toy-course-2012_Fall"}},
"graceperiod": datetime.timedelta(days=2, seconds=21599), "graceperiod": datetime.timedelta(days=2, seconds=21599),
"start": datetime.datetime(2015, 07, 17, 12, tzinfo=pytz.utc), "start": datetime.datetime(2015, 07, 17, 12, tzinfo=pytz.utc),
"xml_attributes": {"filename": ["course/2012_Fall.xml", "course/2012_Fall.xml"]}, "xml_attributes": {"filename": ["course/2012_Fall.xml", "course/2012_Fall.xml"]},
"pdf_textbooks": [ "pdf_textbooks": [
{ {
"tab_title": "Sample Multi Chapter Textbook", "tab_title": "Sample Multi Chapter Textbook",
"id": "MyTextbook", "id": "MyTextbook",
"chapters": [ "chapters": [
{"url": "/static/Chapter1.pdf", "title": "Chapter 1"}, {"url": "/static/Chapter1.pdf", "title": "Chapter 1"},
{"url": "/static/Chapter2.pdf", "title": "Chapter 2"} {"url": "/static/Chapter2.pdf", "title": "Chapter 2"}
] ]
} }
], ],
"course_image": "just_a_test.jpg", "course_image": "just_a_test.jpg",
} }
)
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.toy_loc):
self.store.create_item(
self.user.id, self.toy_loc, "about", block_id="short_description",
fields={"data": "A course about toys."}
)
self.store.create_item(
self.user.id, self.toy_loc, "about", block_id="effort",
fields={"data": "6 hours"}
)
self.store.create_item(
self.user.id, self.toy_loc, "about", block_id="end_date",
fields={"data": "TBD"}
)
self.store.create_item(
self.user.id, self.toy_loc, "course_info", "handouts",
fields={"data": "<a href='/static/handouts/sample_handout.txt'>Sample</a>"}
)
self.store.create_item(
self.user.id, self.toy_loc, "static_tab", "resources",
fields={"display_name": "Resources"},
)
self.store.create_item(
self.user.id, self.toy_loc, "static_tab", "syllabus",
fields={"display_name": "Syllabus"},
) )
return self.toy_loc with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.toy_loc):
self.store.create_item(
self.user.id, self.toy_loc, "about", block_id="short_description",
fields={"data": "A course about toys."}
)
self.store.create_item(
self.user.id, self.toy_loc, "about", block_id="effort",
fields={"data": "6 hours"}
)
self.store.create_item(
self.user.id, self.toy_loc, "about", block_id="end_date",
fields={"data": "TBD"}
)
self.store.create_item(
self.user.id, self.toy_loc, "course_info", "handouts",
fields={"data": "<a href='/static/handouts/sample_handout.txt'>Sample</a>"}
)
self.store.create_item(
self.user.id, self.toy_loc, "static_tab", "resources",
fields={"display_name": "Resources"},
)
self.store.create_item(
self.user.id, self.toy_loc, "static_tab", "syllabus",
fields={"display_name": "Syllabus"},
)
return self.toy_loc
...@@ -99,7 +99,11 @@ class CourseFactory(XModuleFactory): ...@@ -99,7 +99,11 @@ class CourseFactory(XModuleFactory):
# pylint: disable=unused-argument # pylint: disable=unused-argument
@classmethod @classmethod
def _create(cls, target_class, **kwargs): def _create(cls, target_class, **kwargs):
"""
Create and return a new course. For performance reasons, we do not emit
signals during this process, but if you need signals to run, you can
pass `emit_signals=True` to this method.
"""
# All class attributes (from this class and base classes) are # All class attributes (from this class and base classes) are
# passed in via **kwargs. However, some of those aren't actual field values, # passed in via **kwargs. However, some of those aren't actual field values,
# so pop those off for use separately # so pop those off for use separately
...@@ -110,20 +114,23 @@ class CourseFactory(XModuleFactory): ...@@ -110,20 +114,23 @@ class CourseFactory(XModuleFactory):
name = kwargs.get('name', kwargs.get('run', Location.clean(kwargs.get('display_name')))) name = kwargs.get('name', kwargs.get('run', Location.clean(kwargs.get('display_name'))))
run = kwargs.pop('run', name) run = kwargs.pop('run', name)
user_id = kwargs.pop('user_id', ModuleStoreEnum.UserID.test) user_id = kwargs.pop('user_id', ModuleStoreEnum.UserID.test)
emit_signals = kwargs.get('emit_signals', False)
# Pass the metadata just as field=value pairs # Pass the metadata just as field=value pairs
kwargs.update(kwargs.pop('metadata', {})) kwargs.update(kwargs.pop('metadata', {}))
default_store_override = kwargs.pop('default_store', None) default_store_override = kwargs.pop('default_store', None)
with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred): with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
if default_store_override is not None: course_key = store.make_course_key(org, number, run)
with store.default_store(default_store_override): with store.bulk_operations(course_key, emit_signals=emit_signals):
if default_store_override is not None:
with store.default_store(default_store_override):
new_course = store.create_course(org, number, run, user_id, fields=kwargs)
else:
new_course = store.create_course(org, number, run, user_id, fields=kwargs) new_course = store.create_course(org, number, run, user_id, fields=kwargs)
else:
new_course = store.create_course(org, number, run, user_id, fields=kwargs)
last_course.loc = new_course.location last_course.loc = new_course.location
return new_course return new_course
class LibraryFactory(XModuleFactory): class LibraryFactory(XModuleFactory):
......
...@@ -149,7 +149,7 @@ class ProceduralCourseTestMixin(object): ...@@ -149,7 +149,7 @@ class ProceduralCourseTestMixin(object):
""" """
Contains methods for testing courses generated procedurally Contains methods for testing courses generated procedurally
""" """
def populate_course(self, branching=2): def populate_course(self, branching=2, emit_signals=False):
""" """
Add k chapters, k^2 sections, k^3 verticals, k^4 problems to self.course (where k = branching) Add k chapters, k^2 sections, k^3 verticals, k^4 problems to self.course (where k = branching)
""" """
...@@ -172,4 +172,5 @@ class ProceduralCourseTestMixin(object): ...@@ -172,4 +172,5 @@ class ProceduralCourseTestMixin(object):
) )
descend(child, stack[1:]) descend(child, stack[1:])
descend(self.course, ['chapter', 'sequential', 'vertical', 'problem']) with self.store.bulk_operations(self.course.id, emit_signals=emit_signals):
descend(self.course, ['chapter', 'sequential', 'vertical', 'problem'])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment