From b905de757bd308e02a9593a0daef0cd054a12b5c Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Mon, 31 Jan 2022 14:00:57 -0500 Subject: [PATCH] test: more Old Mongo removal from tests Convert more tests from MONGO_AMNESTY to SPLIT modulestores. This is in preparation for just wholesale denying access to Old Mongo, so I either converted tests to split or just deleted some test variants that were Old Mongo specific. (e.g. ddt lines) --- .../tests/test_backfill_course_outlines.py | 8 +- .../contentstore/tests/test_outlines.py | 68 ++++---- .../student/tests/test_enrollment.py | 25 ++- .../xmodule/modulestore/tests/factories.py | 5 + .../tests/test_field_override_performance.py | 34 +--- lms/djangoapps/course_api/tests/test_views.py | 20 +-- .../transformers/tests/helpers.py | 20 ++- .../tests/test_library_content.py | 2 - .../transformers/tests/test_split_test.py | 3 - .../transformers/tests/test_start_date.py | 2 +- lms/djangoapps/courseware/tests/test_about.py | 79 +++------ .../courseware/tests/test_course_info.py | 18 +- .../courseware/tests/test_course_survey.py | 6 +- .../courseware/tests/test_courses.py | 9 +- .../courseware/tests/test_entrance_exam.py | 161 ++++++++---------- .../courseware/tests/test_module_render.py | 69 +++----- .../courseware/tests/test_split_module.py | 29 ++-- lms/djangoapps/courseware/tests/test_tabs.py | 13 +- lms/djangoapps/courseware/tests/test_views.py | 47 ++--- lms/djangoapps/courseware/testutils.py | 56 ++---- .../django_comment_client/base/tests.py | 2 - .../discussion/rest_api/tests/test_api.py | 107 +++++------- .../rest_api/tests/test_serializers.py | 41 +++-- .../discussion/rest_api/tests/test_views.py | 64 +++---- .../discussion/rest_api/tests/utils.py | 23 ++- lms/djangoapps/discussion/tests/test_views.py | 24 +-- lms/djangoapps/grades/tests/base.py | 6 +- .../grades/tests/test_course_grade_factory.py | 6 +- .../grades/tests/test_transformer.py | 17 +- .../lti_provider/tests/test_views.py | 18 -- .../mobile_api/course_info/tests.py | 154 ++++++----------- lms/djangoapps/mobile_api/testutils.py | 4 +- .../djangoapps/bookmarks/tests/test_models.py | 157 ++++++++--------- .../djangoapps/bookmarks/tests/test_tasks.py | 23 +-- ...ourse-enrollments-api-list-valid-data.json | 40 ++--- .../enrollments/tests/test_views.py | 5 +- .../user_api/accounts/tests/test_utils.py | 15 +- .../content_type_gating/tests/test_access.py | 27 +-- .../tests/views/test_course_outline.py | 31 ++-- .../test_crowdsource_hinter.py | 3 +- .../xblock_integration/test_recommender.py | 6 +- .../xblock_integration/xblock_testcase.py | 8 +- 42 files changed, 577 insertions(+), 878 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_outlines.py b/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_outlines.py index 6d9d423718..1aaa4de9fa 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_outlines.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_outlines.py @@ -62,22 +62,22 @@ class BackfillCourseOutlinesTest(SharedModuleStoreTestCase): ) with cls.store.bulk_operations(course_key): section = ItemFactory.create( - parent_location=course.location, + parent=course, category="chapter", display_name="A Section" ) sequence = ItemFactory.create( - parent_location=section.location, + parent=section, category="sequential", display_name="A Sequence" ) unit = ItemFactory.create( - parent_location=sequence.location, + parent=sequence, category="vertical", display_name="A Unit" ) ItemFactory.create( - parent_location=unit.location, + parent=unit, category="html", display_name="An HTML Module" ) diff --git a/cms/djangoapps/contentstore/tests/test_outlines.py b/cms/djangoapps/contentstore/tests/test_outlines.py index b712d85871..9a0da6e9d5 100644 --- a/cms/djangoapps/contentstore/tests/test_outlines.py +++ b/cms/djangoapps/contentstore/tests/test_outlines.py @@ -136,18 +136,18 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """Make sure sequences go into the right places.""" with self.store.bulk_operations(self.course_key): section_1 = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section 1 - Three Sequences", ) ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section 2 - Empty", ) for i in range(3): ItemFactory.create( - parent_location=section_1.location, + parent=section_1, category='sequential', display_name=f"Seq_1_{i}", ) @@ -164,23 +164,23 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): def test_duplicate_children(self): with self.store.bulk_operations(self.course_key): section_1 = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section", ) seq = ItemFactory.create( - parent_location=section_1.location, + parent=section_1, category='sequential', display_name="standard_seq" ) section_2 = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section 2", children=[seq.location] ) section_3 = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section 3", children=[seq.location] @@ -215,42 +215,42 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): # Course -> Section -> Unit (No Sequence) with self.store.bulk_operations(self.course_key): section_1 = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section", ) # This Unit should be skipped ItemFactory.create( - parent_location=section_1.location, + parent=section_1, category='vertical', display_name="u1" ) ItemFactory.create( - parent_location=section_1.location, + parent=section_1, category='sequential', display_name="standard_seq" ) ItemFactory.create( - parent_location=section_1.location, + parent=section_1, category='problemset', display_name="pset_seq" ) ItemFactory.create( - parent_location=section_1.location, + parent=section_1, category='videosequence', display_name="video_seq" ) # This should work fine section_2 = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Section 2", ) # Second error message here ItemFactory.create( - parent_location=section_2.location, + parent=section_2, category='vertical', display_name="u2" ) @@ -278,12 +278,12 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): # Course -> Sequence (No Section) with self.store.bulk_operations(self.course_key): seq = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='sequential', display_name="Sequence", ) ItemFactory.create( - parent_location=seq.location, + parent=seq, category='vertical', display_name="Unit", ) @@ -302,12 +302,12 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """ with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name=None, ) sequence = ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', display_name=None, ) @@ -325,7 +325,7 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """ with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name='Ch 1', group_access={ @@ -335,7 +335,7 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): } ) ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', display_name='Seq 1', group_access={ @@ -354,14 +354,14 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """Testing empty case to make sure bubble-up code doesn't break.""" with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name='Ch 0', ) # Bubble up with no children (nothing happens) ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', display_name='Seq 0', group_access={} @@ -375,20 +375,20 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """Group settings should bubble up from Unit to Seq. if only one unit""" with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name='Ch 0', ) # Bubble up with 1 child (grabs the setting from child) seq_1 = ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', display_name='Seq 1', group_access={} ) ItemFactory.create( - parent_location=seq_1.location, + parent=seq_1, category='vertical', display_name='Single Vertical', group_access={ @@ -406,27 +406,27 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """If all Units have the same group_access, bubble up to Sequence.""" with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name='Ch 0', ) # Bubble up with n children, all matching for one group seq_n = ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', display_name='Seq N', group_access={} ) for i in range(4): ItemFactory.create( - parent_location=seq_n.location, + parent=seq_n, category='vertical', display_name=f'vertical {i}', group_access={50: [3, 4], 51: [i]} # Only 50 should get bubbled up ) ItemFactory.create( - parent_location=seq_n.location, + parent=seq_n, category='vertical', display_name='vertical 5', group_access={50: [4, 3], 51: [5]} # Ordering should be normalized @@ -441,20 +441,20 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """Don't bubble up from Unit if Seq has a conflicting group_access.""" with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name='Ch 0', ) # Bubble up with 1 child (grabs the setting from child) seq_1 = ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', display_name='Seq 1', group_access={50: [3, 4]} ) ItemFactory.create( - parent_location=seq_1.location, + parent=seq_1, category='vertical', display_name='Single Vertical', group_access={50: [1, 2]}, @@ -494,12 +494,12 @@ class OutlineFromModuleStoreTestCase(ModuleStoreTestCase): """ with self.store.bulk_operations(self.course_key): section = ItemFactory.create( - parent_location=self.draft_course.location, + parent=self.draft_course, category='chapter', display_name="Generated Section", ) sequence = ItemFactory.create( - parent_location=section.location, + parent=section, category='sequential', **kwargs, ) diff --git a/common/djangoapps/student/tests/test_enrollment.py b/common/djangoapps/student/tests/test_enrollment.py index 2073c099ea..bc0264322a 100644 --- a/common/djangoapps/student/tests/test_enrollment.py +++ b/common/djangoapps/student/tests/test_enrollment.py @@ -11,7 +11,7 @@ import pytest from django.conf import settings from django.urls import reverse from openedx_events.tests.utils import OpenEdxEventsTestMixin -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from common.djangoapps.course_modes.models import CourseMode @@ -31,12 +31,11 @@ from openedx.core.djangoapps.embargo.test_utils import restrict_course @ddt.ddt @patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True}) @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') -class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase, OpenEdxEventsTestMixin): +class EnrollmentTest(UrlResetMixin, ModuleStoreTestCase, OpenEdxEventsTestMixin): """ Test student enrollment, especially with different course modes. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE ENABLED_OPENEDX_EVENTS = [] USERNAME = "Bob" @@ -54,23 +53,21 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase, OpenEdxEventsTest """ super().setUpClass() cls.start_events_isolation() - cls.course = CourseFactory.create() - cls.course_limited = CourseFactory.create() - cls.proctored_course = CourseFactory( - enable_proctored_exams=True, enable_timed_exams=True - ) - cls.proctored_course_no_exam = CourseFactory( - enable_proctored_exams=True, enable_timed_exams=True - ) @patch.dict(settings.FEATURES, {'EMBARGO': True}) def setUp(self): """ Create a course and user, then log in. """ super().setUp() + self.course = CourseFactory.create() + self.course_limited = CourseFactory.create(max_student_enrollments_allowed=1) + self.proctored_course = CourseFactory( + enable_proctored_exams=True, enable_timed_exams=True + ) + self.proctored_course_no_exam = CourseFactory( + enable_proctored_exams=True, enable_timed_exams=True + ) self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) self.client.login(username=self.USERNAME, password=self.PASSWORD) - self.course_limited.max_student_enrollments_allowed = 1 - self.store.update_item(self.course_limited, self.user.id) self.urls = [ reverse('course_modes_choose', kwargs={'course_id': str(self.course.id)}) ] @@ -87,7 +84,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase, OpenEdxEventsTest ItemFactory.create( parent=chapter, category='sequential', display_name='Test Proctored Exam', graded=True, is_time_limited=True, default_time_limit_minutes=10, - is_proctored_exam=True, publish_item=True + is_proctored_enabled=True, publish_item=True ) @ddt.data( diff --git a/common/lib/xmodule/xmodule/modulestore/tests/factories.py b/common/lib/xmodule/xmodule/modulestore/tests/factories.py index ae3f5c2a12..a7c03b799d 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/factories.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/factories.py @@ -23,6 +23,7 @@ from xblock.core import XBlock from xmodule.course_module import Textbook from xmodule.modulestore import ModuleStoreEnum, prefer_xmodules +from xmodule.modulestore.mixed import strip_key from xmodule.modulestore.tests.sample_courses import TOY_BLOCK_INFO_TREE, default_block_info_tree from xmodule.tabs import CourseTab @@ -324,6 +325,7 @@ class ItemFactory(XModuleFactory): return parent.location @classmethod + @strip_key def _create(cls, target_class, **kwargs): # lint-amnesty, pylint: disable=arguments-differ, too-many-statements, unused-argument """ Uses ``**kwargs``: @@ -365,6 +367,9 @@ class ItemFactory(XModuleFactory): submission_start = kwargs.pop('submission_start', None) submission_end = kwargs.pop('submission_end', None) + # Remove this variable passed in by `strip_key` + kwargs.pop('field_decorator') + # Remove the descriptive_tag, it's just for generating display_name, # and doesn't need to be passed into the object constructor kwargs.pop('descriptive_tag') diff --git a/lms/djangoapps/ccx/tests/test_field_override_performance.py b/lms/djangoapps/ccx/tests/test_field_override_performance.py index 99f14c44ab..8e251952ed 100644 --- a/lms/djangoapps/ccx/tests/test_field_override_performance.py +++ b/lms/djangoapps/ccx/tests/test_field_override_performance.py @@ -20,7 +20,7 @@ from edx_django_utils.cache import RequestCache from opaque_keys.edx.keys import CourseKey from pytz import UTC from xblock.core import XBlock -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls, check_sum_of_calls from xmodule.modulestore.tests.utils import ProceduralCourseTestMixin @@ -215,9 +215,6 @@ class FieldOverridePerformanceTestCase(FieldOverrideTestMixin, ProceduralCourseT if not enable_ccx and view_as_ccx: pytest.skip("Can't view a ccx course if ccx is disabled on the course") - if self.MODULESTORE == TEST_DATA_MONGO_MODULESTORE and view_as_ccx: - pytest.skip("Can't use a MongoModulestore test as a CCX course") - with self.settings( XBLOCK_FIELD_DATA_WRAPPERS=['lms.djangoapps.courseware.field_overrides:OverrideModulestoreFieldData.wrap'], MODULESTORE_FIELD_OVERRIDE_PROVIDERS=providers[overrides], @@ -230,35 +227,6 @@ class FieldOverridePerformanceTestCase(FieldOverrideTestMixin, ProceduralCourseT ) -class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase): - """ - Test cases for instrumenting field overrides against the Mongo modulestore. - """ - MODULESTORE = TEST_DATA_MONGO_MODULESTORE - __test__ = True - - # TODO: decrease query count as part of REVO-28 - QUERY_COUNT = 31 - TEST_DATA = { - # (providers, course_width, enable_ccx, view_as_ccx): ( - # # of sql queries to default, - # # of mongo queries, - # ) - ('no_overrides', 1, True, False): (QUERY_COUNT, 1), - ('no_overrides', 2, True, False): (QUERY_COUNT, 1), - ('no_overrides', 3, True, False): (QUERY_COUNT, 1), - ('ccx', 1, True, False): (QUERY_COUNT, 1), - ('ccx', 2, True, False): (QUERY_COUNT, 1), - ('ccx', 3, True, False): (QUERY_COUNT, 1), - ('no_overrides', 1, False, False): (QUERY_COUNT, 1), - ('no_overrides', 2, False, False): (QUERY_COUNT, 1), - ('no_overrides', 3, False, False): (QUERY_COUNT, 1), - ('ccx', 1, False, False): (QUERY_COUNT, 1), - ('ccx', 2, False, False): (QUERY_COUNT, 1), - ('ccx', 3, False, False): (QUERY_COUNT, 1), - } - - class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase): """ Test cases for instrumenting field overrides against the Split modulestore. diff --git a/lms/djangoapps/course_api/tests/test_views.py b/lms/djangoapps/course_api/tests/test_views.py index e2633d085c..984472eaba 100644 --- a/lms/djangoapps/course_api/tests/test_views.py +++ b/lms/djangoapps/course_api/tests/test_views.py @@ -12,16 +12,13 @@ from django.test import RequestFactory from django.test.utils import override_settings from django.urls import reverse from edx_django_utils.cache import RequestCache +from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocator from search.tests.test_course_discovery import DemoCourse from search.tests.tests import TEST_INDEX_NAME from search.tests.utils import SearcherMixin from waffle.testutils import override_switch -from xmodule.modulestore.tests.django_utils import ( - TEST_DATA_MONGO_MODULESTORE, - ModuleStoreTestCase, - SharedModuleStoreTestCase, -) +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from common.djangoapps.course_modes.models import CourseMode @@ -317,7 +314,6 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear Similar to search.tests.test_course_discovery_views but with the course API integration. """ - MODULESTORE = TEST_DATA_MONGO_MODULESTORE ENABLED_SIGNALS = ['course_published'] ENABLED_CACHES = ModuleStoreTestCase.ENABLED_CACHES + ['configuration'] @@ -348,8 +344,7 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear 'org': org_code, 'run': '2010', 'number': 'DemoZ', - # Using the slash separated course ID bcuz `DemoCourse` isn't updated yet to new locator. - 'id': f'{org_code}/DemoZ/2010', + 'id': f'course-v1:{org_code}+DemoZ+2010', 'content': { 'short_description': short_description, }, @@ -357,14 +352,13 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear DemoCourse.index(self.searcher, [search_course]) - org, course, run = search_course['id'].split('/') + key = CourseKey.from_string(search_course['id']) db_course = self.create_course( mobile_available=False, - org=org, - course=course, - run=run, - short_description=short_description, + org=key.org, + course=key.course, + run=key.run, ) return db_course diff --git a/lms/djangoapps/course_blocks/transformers/tests/helpers.py b/lms/djangoapps/course_blocks/transformers/tests/helpers.py index c83924ad54..f55aa9ccab 100644 --- a/lms/djangoapps/course_blocks/transformers/tests/helpers.py +++ b/lms/djangoapps/course_blocks/transformers/tests/helpers.py @@ -7,7 +7,7 @@ from unittest.mock import patch from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from common.djangoapps.course_modes.models import CourseMode @@ -43,7 +43,6 @@ class CourseStructureTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase) """ Helper for test cases that need to build course structures. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE def setUp(self): """ @@ -116,6 +115,7 @@ class CourseStructureTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase) Mapping from '#ref' values to their XBlocks. """ + store = modulestore() parents = block_hierarchy.get('#parents', []) if parents: block_key = block_map[block_hierarchy['#ref']].location @@ -123,14 +123,16 @@ class CourseStructureTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase) # First remove the block from the course. # It would be re-added to the course if the course was # explicitly listed in parents. - course = modulestore().get_item(block_map['course'].location) + with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, block_map['course'].id): + course = store.get_item(block_map['course'].location) if block_key in course.children: course.children.remove(block_key) block_map['course'] = update_block(course) # Add this to block to each listed parent. for parent_ref in parents: - parent_block = modulestore().get_item(block_map[parent_ref].location) + with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id): + parent_block = store.get_item(block_map[parent_ref].location) parent_block.children.append(block_key) block_map[parent_ref] = update_block(parent_block) @@ -209,8 +211,6 @@ class BlockParentsMapTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase) a graph of vertical blocks based on a parents_map. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - # Tree formed by parent_map: # 0 # / \ @@ -310,7 +310,9 @@ class BlockParentsMapTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase) Helper method to retrieve the requested block (index) from the modulestore """ - return modulestore().get_item(self.xblock_keys[block_index]) + store = modulestore() + with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): + return store.get_item(self.xblock_keys[block_index]) def _check_results(self, user, expected_accessible_blocks, blocks_with_differing_access, transformers): """ @@ -350,7 +352,9 @@ def update_block(block): """ Helper method to update the block in the modulestore """ - return modulestore().update_item(block, ModuleStoreEnum.UserID.test) + store = modulestore() + with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, block.course_id): + return store.update_item(block, ModuleStoreEnum.UserID.test) def publish_course(course): diff --git a/lms/djangoapps/course_blocks/transformers/tests/test_library_content.py b/lms/djangoapps/course_blocks/transformers/tests/test_library_content.py index 20505290af..7fdb58f7f6 100644 --- a/lms/djangoapps/course_blocks/transformers/tests/test_library_content.py +++ b/lms/djangoapps/course_blocks/transformers/tests/test_library_content.py @@ -70,7 +70,6 @@ class ContentLibraryTransformerTestCase(CourseStructureTestCase): '#ref': 'vertical1', '#children': [ { - 'metadata': {'category': 'library_content'}, '#type': 'library_content', '#ref': 'library_content1', '#children': [ @@ -205,7 +204,6 @@ class ContentLibraryOrderTransformerTestCase(CourseStructureTestCase): '#ref': 'vertical1', '#children': [ { - 'metadata': {'category': 'library_content'}, '#type': 'library_content', '#ref': 'library_content1', '#children': [ diff --git a/lms/djangoapps/course_blocks/transformers/tests/test_split_test.py b/lms/djangoapps/course_blocks/transformers/tests/test_split_test.py index f7aafc1316..468cc30c8f 100644 --- a/lms/djangoapps/course_blocks/transformers/tests/test_split_test.py +++ b/lms/djangoapps/course_blocks/transformers/tests/test_split_test.py @@ -103,7 +103,6 @@ class SplitTestTransformerTestCase(CourseStructureTestCase): { '#type': 'split_test', '#ref': 'BSplit', - 'metadata': {'category': 'split_test'}, 'user_partition_id': self.TEST_PARTITION_ID, 'group_id_to_child': { '0': location('E'), @@ -128,7 +127,6 @@ class SplitTestTransformerTestCase(CourseStructureTestCase): { '#type': 'split_test', '#ref': 'KSplit', - 'metadata': {'category': 'split_test'}, 'user_partition_id': self.TEST_PARTITION_ID, 'group_id_to_child': { '1': location('M'), @@ -143,7 +141,6 @@ class SplitTestTransformerTestCase(CourseStructureTestCase): { '#type': 'split_test', '#ref': 'CSplit', - 'metadata': {'category': 'split_test'}, 'user_partition_id': self.TEST_PARTITION_ID, 'group_id_to_child': { '0': location('H'), diff --git a/lms/djangoapps/course_blocks/transformers/tests/test_start_date.py b/lms/djangoapps/course_blocks/transformers/tests/test_start_date.py index bb4b6cb6aa..adac44c95d 100644 --- a/lms/djangoapps/course_blocks/transformers/tests/test_start_date.py +++ b/lms/djangoapps/course_blocks/transformers/tests/test_start_date.py @@ -72,7 +72,7 @@ class StartDateTransformerTestCase(BlockParentsMapTestCase): # has_access checks on block directly and doesn't follow negative access set on parent/ancestor (i.e., 0) (STUDENT, {1: StartDateType.released}, {}, {1, 3, 4, 6}), - (STUDENT, {2: StartDateType.released}, {}, {2, 5, 6}), + (STUDENT, {2: StartDateType.released}, {}, {2, 5}), (STUDENT, {1: StartDateType.released, 2: StartDateType.released}, {}, {1, 2, 3, 4, 5, 6}), # DAG conflicts: has_access relies on field inheritance so it takes only the value from the first parent-chain diff --git a/lms/djangoapps/courseware/tests/test_about.py b/lms/djangoapps/courseware/tests/test_about.py index ce6cbce18a..4b863fbc8e 100644 --- a/lms/djangoapps/courseware/tests/test_about.py +++ b/lms/djangoapps/courseware/tests/test_about.py @@ -13,12 +13,24 @@ from ccx_keys.locator import CCXLocator from django.conf import settings from django.test.utils import override_settings from django.urls import reverse +from edx_toggles.toggles.testutils import override_waffle_flag from milestones.tests.utils import MilestonesTestCaseMixin from waffle.testutils import override_switch +from xmodule.course_module import ( + CATALOG_VISIBILITY_ABOUT, + CATALOG_VISIBILITY_NONE, + COURSE_VISIBILITY_PRIVATE, + COURSE_VISIBILITY_PUBLIC, + COURSE_VISIBILITY_PUBLIC_OUTLINE +) +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory +from xmodule.modulestore.tests.utils import TEST_DATA_DIR +from xmodule.modulestore.xml_importer import import_course_from_xml from common.djangoapps.course_modes.models import CourseMode -from edx_toggles.toggles.testutils import override_waffle_flag # lint-amnesty, pylint: disable=wrong-import-order from lms.djangoapps.ccx.tests.factories import CcxFactory +from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.features.course_experience import COURSE_ENABLE_UNENROLLED_ACCESS_FLAG from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML from openedx.features.course_experience.waffle import WAFFLE_NAMESPACE as COURSE_EXPERIENCE_WAFFLE_NAMESPACE @@ -26,22 +38,6 @@ from lms.djangoapps.course_home_api.toggles import COURSE_HOME_USE_LEGACY_FRONTE from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentAllowedFactory, UserFactory from common.djangoapps.track.tests import EventTrackingTestCase from common.djangoapps.util.milestones_helpers import get_prerequisite_courses_display, set_prerequisite_courses -from xmodule.course_module import ( # lint-amnesty, pylint: disable=wrong-import-order - CATALOG_VISIBILITY_ABOUT, - CATALOG_VISIBILITY_NONE, - COURSE_VISIBILITY_PRIVATE, - COURSE_VISIBILITY_PUBLIC, - COURSE_VISIBILITY_PUBLIC_OUTLINE -) -from xmodule.modulestore.tests.django_utils import ( # lint-amnesty, pylint: disable=wrong-import-order - TEST_DATA_MIXED_MODULESTORE, - TEST_DATA_MONGO_AMNESTY_MODULESTORE, - ModuleStoreTestCase, - SharedModuleStoreTestCase -) -from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.tests.utils import TEST_DATA_DIR # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.xml_importer import import_course_from_xml # lint-amnesty, pylint: disable=wrong-import-order from .helpers import LoginEnrollmentTestCase @@ -51,12 +47,11 @@ SHIB_ERROR_STR = "The currently logged-in user account does not have permission @ddt.ddt +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class AboutTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase, EventTrackingTestCase, MilestonesTestCaseMixin): """ Tests about xblock. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -64,18 +59,9 @@ class AboutTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase, EventTra cls.course_without_about = CourseFactory.create(catalog_visibility=CATALOG_VISIBILITY_NONE) cls.course_with_about = CourseFactory.create(catalog_visibility=CATALOG_VISIBILITY_ABOUT) cls.purchase_course = CourseFactory.create(org='MITx', number='buyme', display_name='Course To Buy') - cls.about = ItemFactory.create( - category="about", parent_location=cls.course.location, - data="OOGIE BLOOGIE", display_name="overview" - ) - cls.about = ItemFactory.create( - category="about", parent_location=cls.course_without_about.location, - data="WITHOUT ABOUT", display_name="overview" - ) - cls.about = ItemFactory.create( - category="about", parent_location=cls.course_with_about.location, - data="WITH ABOUT", display_name="overview" - ) + CourseDetails.update_about_item(cls.course, 'overview', 'OOGIE BLOOGIE', None) + CourseDetails.update_about_item(cls.course_without_about, 'overview', 'WITHOUT ABOUT', None) + CourseDetails.update_about_item(cls.course_with_about, 'overview', 'WITH ABOUT', None) def setUp(self): super().setUp() @@ -243,12 +229,11 @@ class AboutTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase, EventTra self.assertContains(resp, "Enroll Now") +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class AboutTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): """ Tests for the course about page """ - MODULESTORE = TEST_DATA_MIXED_MODULESTORE - def setUp(self): """ Set up the tests @@ -261,7 +246,7 @@ class AboutTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): self.xml_course_id = self.store.make_course_key('edX', 'detached_pages', '2014') import_course_from_xml( self.store, - 'test_user', + self.user.id, TEST_DATA_DIR, source_dirs=['2014'], static_content_store=None, @@ -288,20 +273,16 @@ class AboutTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): self.assertContains(resp, self.xml_data) +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class AboutWithCappedEnrollmentsTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase): """ This test case will check the About page when a course has a capped enrollment """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create(metadata={"max_student_enrollments_allowed": 1}) - cls.about = ItemFactory.create( - category="about", parent_location=cls.course.location, - data="OOGIE BLOOGIE", display_name="overview" - ) + CourseDetails.update_about_item(cls.course, 'overview', 'OOGIE BLOOGIE', None) def test_enrollment_cap(self): """ @@ -335,20 +316,15 @@ class AboutWithCappedEnrollmentsTestCase(LoginEnrollmentTestCase, SharedModuleSt self.assertNotContains(resp, REG_STR) +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class AboutWithInvitationOnly(SharedModuleStoreTestCase): """ This test case will check the About page when a course is invitation only. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create(metadata={"invitation_only": True}) - cls.about = ItemFactory.create( - category="about", parent_location=cls.course.location, - display_name="overview" - ) def test_invitation_only(self): """ @@ -380,13 +356,12 @@ class AboutWithInvitationOnly(SharedModuleStoreTestCase): self.assertContains(resp, REG_STR) +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class AboutWithClosedEnrollment(ModuleStoreTestCase): """ This test case will check the About page for a course that has enrollment start/end set but it is currently outside of that period. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() @@ -401,11 +376,6 @@ class AboutWithClosedEnrollment(ModuleStoreTestCase): self.course.enrollment_end = nextday self.course = self.update_course(self.course, self.user.id) - self.about = ItemFactory.create( - category="about", parent_location=self.course.location, - display_name="overview" - ) - def test_closed_enrollmement(self): url = reverse('about_course', args=[str(self.course.id)]) resp = self.client.get(url) @@ -414,7 +384,7 @@ class AboutWithClosedEnrollment(ModuleStoreTestCase): # Check that registration button is not present self.assertNotContains(resp, REG_STR) - def test_course_price_is_not_visble_in_sidebar(self): + def test_course_price_is_not_visible_in_sidebar(self): url = reverse('about_course', args=[str(self.course.id)]) resp = self.client.get(url) # course price is not visible ihe course_about page when the course @@ -423,6 +393,7 @@ class AboutWithClosedEnrollment(ModuleStoreTestCase): @ddt.ddt +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class AboutSidebarHTMLTestCase(SharedModuleStoreTestCase): """ This test case will check the About page for the content in the HTML sidebar. diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py index 90df8c68ca..5cb98b3a22 100644 --- a/lms/djangoapps/courseware/tests/test_course_info.py +++ b/lms/djangoapps/courseware/tests/test_course_info.py @@ -13,6 +13,11 @@ from django.http import QueryDict from django.test.utils import override_settings from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag +from pyquery import PyQuery as pq +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls +from xmodule.modulestore.tests.utils import TEST_DATA_DIR +from xmodule.modulestore.xml_importer import import_course_from_xml from lms.djangoapps.ccx.tests.factories import CcxFactory from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration @@ -21,18 +26,9 @@ from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired -from pyquery import PyQuery as pq # lint-amnesty, pylint: disable=wrong-import-order from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import AdminFactory from common.djangoapps.util.date_utils import strftime_localized -from xmodule.modulestore.tests.django_utils import ( # lint-amnesty, pylint: disable=wrong-import-order - TEST_DATA_MIXED_MODULESTORE, - ModuleStoreTestCase, - SharedModuleStoreTestCase -) -from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.tests.utils import TEST_DATA_DIR # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.xml_importer import import_course_from_xml # lint-amnesty, pylint: disable=wrong-import-order from .helpers import LoginEnrollmentTestCase @@ -341,8 +337,6 @@ class CourseInfoTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): """ Tests for the Course Info page for an XML course """ - MODULESTORE = TEST_DATA_MIXED_MODULESTORE - def setUp(self): """ Set up the tests @@ -355,7 +349,7 @@ class CourseInfoTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): self.xml_course_key = self.store.make_course_key('edX', 'detached_pages', '2014') import_course_from_xml( self.store, - 'test_user', + self.user.id, TEST_DATA_DIR, source_dirs=['2014'], static_content_store=None, diff --git a/lms/djangoapps/courseware/tests/test_course_survey.py b/lms/djangoapps/courseware/tests/test_course_survey.py index 77240e44ba..5cfae9047c 100644 --- a/lms/djangoapps/courseware/tests/test_course_survey.py +++ b/lms/djangoapps/courseware/tests/test_course_survey.py @@ -8,19 +8,21 @@ from copy import deepcopy from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.urls import reverse -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from edx_toggles.toggles.testutils import override_waffle_flag +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from common.test.utils import XssTestMixin +from lms.djangoapps.course_home_api.toggles import COURSE_HOME_USE_LEGACY_FRONTEND from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase from lms.djangoapps.survey.models import SurveyAnswer, SurveyForm +@override_waffle_flag(COURSE_HOME_USE_LEGACY_FRONTEND, active=True) class SurveyViewsTests(LoginEnrollmentTestCase, SharedModuleStoreTestCase, XssTestMixin): """ All tests for the views.py file """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE STUDENT_INFO = [('view@test.com', 'foo')] @classmethod diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index 77293624d4..365dc0aaf7 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -54,7 +54,6 @@ TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT @ddt.ddt class CoursesTest(ModuleStoreTestCase): """Test methods related to fetching courses.""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE ENABLED_SIGNALS = ['course_published'] GET_COURSE_WITH_ACCESS = 'get_course_with_access' GET_COURSE_OVERVIEW_WITH_ACCESS = 'get_course_overview_with_access' @@ -90,7 +89,7 @@ class CoursesTest(ModuleStoreTestCase): assert not error.value.access_response.has_access @ddt.data( - (GET_COURSE_WITH_ACCESS, 1), + (GET_COURSE_WITH_ACCESS, 3), (GET_COURSE_OVERVIEW_WITH_ACCESS, 0), ) @ddt.unpack @@ -370,11 +369,11 @@ class CourseInstantiationTests(ModuleStoreTestCase): self.factory = RequestFactory() - @ddt.data(*itertools.product(range(5), [ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split], [None, 0, 5])) + @ddt.data(*itertools.product(range(5), [None, 0, 5])) @ddt.unpack - def test_repeated_course_module_instantiation(self, loops, default_store, course_depth): + def test_repeated_course_module_instantiation(self, loops, course_depth): - with modulestore().default_store(default_store): + with modulestore().default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() chapter = ItemFactory(parent=course, category='chapter', graded=True) section = ItemFactory(parent=chapter, category='sequential') diff --git a/lms/djangoapps/courseware/tests/test_entrance_exam.py b/lms/djangoapps/courseware/tests/test_entrance_exam.py index dbea9ce190..0dd7976c11 100644 --- a/lms/djangoapps/courseware/tests/test_entrance_exam.py +++ b/lms/djangoapps/courseware/tests/test_entrance_exam.py @@ -8,8 +8,7 @@ from crum import set_current_request from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag from milestones.tests.utils import MilestonesTestCaseMixin -from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory @@ -22,6 +21,7 @@ from lms.djangoapps.courseware.entrance_exams import ( from lms.djangoapps.courseware.model_data import FieldDataCache from lms.djangoapps.courseware.module_render import get_module, handle_xblock_callback, toc_for_course from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase +from lms.djangoapps.courseware.toggles import COURSEWARE_USE_LEGACY_FRONTEND from openedx.core.djangolib.testing.utils import get_mock_request from openedx.features.course_experience import DISABLE_COURSE_OUTLINE_PAGE_FLAG, DISABLE_UNIFIED_COURSE_TAB_FLAG from common.djangoapps.student.models import CourseEnrollment @@ -40,6 +40,7 @@ from common.djangoapps.util.milestones_helpers import ( ) +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTestCaseMixin): """ @@ -48,8 +49,6 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest Creates a test course from scratch. The tests below are designed to execute workflows regardless of the feature flag settings. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) def setUp(self): """ @@ -61,82 +60,75 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest 'entrance_exam_enabled': True, } ) - with self.store.bulk_operations(self.course.id): - self.chapter = ItemFactory.create( - parent=self.course, - display_name='Overview' - ) - self.welcome = ItemFactory.create( - parent=self.chapter, - display_name='Welcome' - ) - ItemFactory.create( - parent=self.course, - category='chapter', - display_name="Week 1" - ) - self.chapter_subsection = ItemFactory.create( - parent=self.chapter, - category='sequential', - display_name="Lesson 1" - ) - chapter_vertical = ItemFactory.create( - parent=self.chapter_subsection, - category='vertical', - display_name='Lesson 1 Vertical - Unit 1' - ) - ItemFactory.create( - parent=chapter_vertical, - category="problem", - display_name="Problem - Unit 1 Problem 1" - ) - ItemFactory.create( - parent=chapter_vertical, - category="problem", - display_name="Problem - Unit 1 Problem 2" - ) + self.chapter = ItemFactory.create( + parent=self.course, + display_name='Overview' + ) + self.welcome = ItemFactory.create( + parent=self.chapter, + display_name='Welcome' + ) + ItemFactory.create( + parent=self.course, + category='chapter', + display_name="Week 1" + ) + self.chapter_subsection = ItemFactory.create( + parent=self.chapter, + category='sequential', + display_name="Lesson 1" + ) + chapter_vertical = ItemFactory.create( + parent=self.chapter_subsection, + category='vertical', + display_name='Lesson 1 Vertical - Unit 1' + ) + ItemFactory.create( + parent=chapter_vertical, + category="problem", + display_name="Problem - Unit 1 Problem 1" + ) + ItemFactory.create( + parent=chapter_vertical, + category="problem", + display_name="Problem - Unit 1 Problem 2" + ) - ItemFactory.create( - category="instructor", - parent=self.course, - data="Instructor Tab", - display_name="Instructor" - ) - self.entrance_exam = ItemFactory.create( - parent=self.course, - category="chapter", - display_name="Entrance Exam Section - Chapter 1", - is_entrance_exam=True, - in_entrance_exam=True - ) - self.exam_1 = ItemFactory.create( - parent=self.entrance_exam, - category='sequential', - display_name="Exam Sequential - Subsection 1", - graded=True, - in_entrance_exam=True - ) - subsection = ItemFactory.create( - parent=self.exam_1, - category='vertical', - display_name='Exam Vertical - Unit 1' - ) - problem_xml = MultipleChoiceResponseXMLFactory().build_xml( - question_text='The correct answer is Choice 3', - choices=[False, False, True, False], - choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3'] - ) - self.problem_1 = ItemFactory.create( - parent=subsection, - category="problem", - display_name="Exam Problem - Problem 1", - data=problem_xml - ) - self.problem_2 = ItemFactory.create( - parent=subsection, - category="problem", - display_name="Exam Problem - Problem 2" - ) + self.entrance_exam = ItemFactory.create( + parent=self.course, + category="chapter", + display_name="Entrance Exam Section - Chapter 1", + is_entrance_exam=True, + in_entrance_exam=True + ) + self.exam_1 = ItemFactory.create( + parent=self.entrance_exam, + category='sequential', + display_name="Exam Sequential - Subsection 1", + graded=True, + in_entrance_exam=True + ) + subsection = ItemFactory.create( + parent=self.exam_1, + category='vertical', + display_name='Exam Vertical - Unit 1' + ) + problem_xml = MultipleChoiceResponseXMLFactory().build_xml( + question_text='The correct answer is Choice 3', + choices=[False, False, True, False], + choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3'] + ) + self.problem_1 = ItemFactory.create( + parent=subsection, + category="problem", + display_name="Exam Problem - Problem 1", + data=problem_xml + ) + self.problem_2 = ItemFactory.create( + parent=subsection, + category="problem", + display_name="Exam Problem - Problem 2" + ) add_entrance_exam_milestone(self.course, self.entrance_exam) @@ -147,7 +139,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest self.anonymous_user = AnonymousUserFactory() self.addCleanup(set_current_request, None) self.request = get_mock_request(UserFactory()) - modulestore().update_item(self.course, self.request.user.id) + self.course = self.update_course(self.course, self.request.user.id) self.client.login(username=self.request.user.username, password="test") CourseEnrollment.enroll(self.request.user, self.course.id) @@ -205,13 +197,6 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest 'display_name': 'Week 1', 'display_id': 'week-1' }, - { - 'active': False, - 'sections': [], - 'url_name': 'Instructor', - 'display_name': 'Instructor', - 'display_id': 'instructor' - }, { 'active': True, 'sections': [ @@ -316,7 +301,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest """ minimum_score_pct = 29 self.course.entrance_exam_minimum_score_pct = float(minimum_score_pct) / 100 - modulestore().update_item(self.course, self.request.user.id) + self.update_course(self.course, self.request.user.id) # answer the problem so it results in only 20% correct. answer_entrance_exam_problem(self.course, self.request, self.problem_1, value=1, max_value=5) diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index 07d5d7fa80..eeee3e7bfa 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -1012,20 +1012,14 @@ class TestTOC(ModuleStoreTestCase): self.course_key, self.request.user, self.toy_course, depth=2 ) - # Mongo makes 3 queries to load the course to depth 2: - # - 1 for the course - # - 1 for its children - # - 1 for its grandchildren # Split makes 2 queries to load the course to depth 2: # - 1 for the structure # - 1 for 5 definitions # Split makes 1 MySQL query to render the toc: # - 1 MySQL for the active version at the start of the bulk operation (no mongo calls) - @ddt.data((ModuleStoreEnum.Type.mongo, 3, 0, 0), (ModuleStoreEnum.Type.split, 2, 0, 0)) - @ddt.unpack - def test_toc_toy_from_chapter(self, default_ms, setup_finds, setup_sends, toc_finds): - with self.store.default_store(default_ms): - self.setup_request_and_course(setup_finds, setup_sends) + def test_toc_toy_from_chapter(self): + with self.store.default_store(ModuleStoreEnum.Type.split): + self.setup_request_and_course(2, 0) expected = ([{'active': True, 'sections': [{'url_name': 'Toy_Videos', 'display_name': 'Toy Videos', 'graded': True, @@ -1043,7 +1037,7 @@ class TestTOC(ModuleStoreTestCase): 'url_name': 'secret:magic', 'display_name': 'secret:magic', 'display_id': 'secretmagic'}]) course = self.store.get_course(self.toy_course.id, depth=2) - with check_mongo_calls(toc_finds): + with check_mongo_calls(0): actual = render.toc_for_course( self.request.user, self.request, course, self.chapter, None, self.field_data_cache ) @@ -1052,20 +1046,14 @@ class TestTOC(ModuleStoreTestCase): assert actual['previous_of_active_section'] is None assert actual['next_of_active_section'] is None - # Mongo makes 3 queries to load the course to depth 2: - # - 1 for the course - # - 1 for its children - # - 1 for its grandchildren # Split makes 2 queries to load the course to depth 2: # - 1 for the structure # - 1 for 5 definitions # Split makes 1 MySQL query to render the toc: # - 1 MySQL for the active version at the start of the bulk operation (no mongo calls) - @ddt.data((ModuleStoreEnum.Type.mongo, 3, 0, 0), (ModuleStoreEnum.Type.split, 2, 0, 0)) - @ddt.unpack - def test_toc_toy_from_section(self, default_ms, setup_finds, setup_sends, toc_finds): - with self.store.default_store(default_ms): - self.setup_request_and_course(setup_finds, setup_sends) + def test_toc_toy_from_section(self): + with self.store.default_store(ModuleStoreEnum.Type.split): + self.setup_request_and_course(2, 0) section = 'Welcome' expected = ([{'active': True, 'sections': [{'url_name': 'Toy_Videos', 'display_name': 'Toy Videos', 'graded': True, @@ -1082,7 +1070,7 @@ class TestTOC(ModuleStoreTestCase): 'format': '', 'due': None, 'active': False}], 'url_name': 'secret:magic', 'display_name': 'secret:magic', 'display_id': 'secretmagic'}]) - with check_mongo_calls(toc_finds): + with check_mongo_calls(0): actual = render.toc_for_course( self.request.user, self.request, self.toy_course, self.chapter, section, self.field_data_cache ) @@ -1094,20 +1082,14 @@ class TestTOC(ModuleStoreTestCase): @ddt.ddt @patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True}) -class TestProctoringRendering(SharedModuleStoreTestCase): +class TestProctoringRendering(ModuleStoreTestCase): """Check the Table of Contents for a course""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.course_key = ToyCourseFactory.create(enable_proctored_exams=True).id - def setUp(self): """ Set up the initial mongo datastores """ super().setUp() + self.course_key = ToyCourseFactory.create(enable_proctored_exams=True).id self.chapter = 'Overview' chapter_url = '{}/{}/{}'.format('/courses', self.course_key, self.chapter) factory = RequestFactoryNoCsrf() @@ -1342,15 +1324,15 @@ class TestProctoringRendering(SharedModuleStoreTestCase): test harness data """ usage_key = self.course_key.make_usage_key('videosequence', 'Toy_Videos') - sequence = self.modulestore.get_item(usage_key) - sequence.is_time_limited = True - sequence.is_proctored_exam = True - sequence.is_practice_exam = is_practice_exam + with self.modulestore.bulk_operations(self.toy_course.id): + sequence = self.modulestore.get_item(usage_key) + sequence.is_time_limited = True + sequence.is_proctored_exam = True + sequence.is_practice_exam = is_practice_exam + self.modulestore.update_item(sequence, self.user.id) - self.modulestore.update_item(sequence, self.user.id) - - self.toy_course = self.modulestore.get_course(self.course_key) + self.toy_course = self.update_course(self.toy_course, self.user.id) # refresh cache after update self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( @@ -1375,7 +1357,7 @@ class TestProctoringRendering(SharedModuleStoreTestCase): exam_id = create_exam( course_id=str(self.course_key), - content_id=str(sequence.location), + content_id=str(sequence.location.replace(branch=None, version=None)), exam_name='foo', time_limit_mins=10, is_proctored=True, @@ -1415,26 +1397,17 @@ class TestProctoringRendering(SharedModuleStoreTestCase): return None -class TestGatedSubsectionRendering(SharedModuleStoreTestCase, MilestonesTestCaseMixin): +class TestGatedSubsectionRendering(ModuleStoreTestCase, MilestonesTestCaseMixin): """ Test the toc for a course is rendered correctly when there is gated content """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.course = CourseFactory.create() - cls.course.enable_subsection_gating = True - cls.course.save() - cls.store.update_item(cls.course, 0) - def setUp(self): """ Set up the initial test data """ super().setUp() + self.course = CourseFactory.create(enable_subsection_gating=True) self.chapter = ItemFactory.create( parent=self.course, category="chapter", @@ -1450,6 +1423,8 @@ class TestGatedSubsectionRendering(SharedModuleStoreTestCase, MilestonesTestCase category='sequential', display_name="Gated Sequential" ) + self.course = self.update_course(self.course, 0) + self.request = RequestFactoryNoCsrf().get(f'/courses/{self.course.id}/{self.chapter.display_name}') self.request.user = UserFactory() self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( diff --git a/lms/djangoapps/courseware/tests/test_split_module.py b/lms/djangoapps/courseware/tests/test_split_module.py index 0aecb0fbb0..fb447dcca1 100644 --- a/lms/djangoapps/courseware/tests/test_split_module.py +++ b/lms/djangoapps/courseware/tests/test_split_module.py @@ -5,23 +5,25 @@ Test for split test XModule from unittest.mock import MagicMock from django.urls import reverse -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from edx_toggles.toggles.testutils import override_waffle_flag +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.partitions.partitions import Group, UserPartition from lms.djangoapps.courseware.model_data import FieldDataCache from lms.djangoapps.courseware.module_render import get_module_for_descriptor +from lms.djangoapps.courseware.toggles import COURSEWARE_USE_LEGACY_FRONTEND from openedx.core.djangoapps.user_api.tests.factories import UserCourseTagFactory from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -class SplitTestBase(SharedModuleStoreTestCase): +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) +class SplitTestBase(ModuleStoreTestCase): """ Sets up a basic course and user for split test testing. Also provides tests of rendered HTML for two user_tag conditions, 0 and 1. """ __test__ = False - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE COURSE_NUMBER = 'split-test-base' ICON_CLASSES = None TOOLTIPS = None @@ -40,25 +42,24 @@ class SplitTestBase(SharedModuleStoreTestCase): ] ) - cls.course = CourseFactory.create( - number=cls.COURSE_NUMBER, - user_partitions=[cls.partition] - ) + def setUp(self): + super().setUp() - cls.chapter = ItemFactory.create( - parent_location=cls.course.location, + self.course = CourseFactory.create( + number=self.COURSE_NUMBER, + user_partitions=[self.partition] + ) + self.chapter = ItemFactory.create( + parent_location=self.course.location, category="chapter", display_name="test chapter", ) - cls.sequential = ItemFactory.create( - parent_location=cls.chapter.location, + self.sequential = ItemFactory.create( + parent_location=self.chapter.location, category="sequential", display_name="Split Test Tests", ) - def setUp(self): - super().setUp() - self.student = UserFactory.create() CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) self.client.login(username=self.student.username, password='test') diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 92ff935aa7..82b1c672ba 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -237,8 +237,6 @@ class TextbooksTestCase(TabTestCase): class StaticTabDateTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase): """Test cases for Static Tab Dates.""" - MODULESTORE = TEST_DATA_MIXED_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -294,8 +292,6 @@ class StaticTabDateTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): Tests for the static tab dates of an XML course """ - MODULESTORE = TEST_DATA_MIXED_MODULESTORE - def setUp(self): """ Set up the tests @@ -308,7 +304,7 @@ class StaticTabDateTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): self.xml_course_key = self.store.make_course_key('edX', 'detached_pages', '2014') import_course_from_xml( self.store, - 'test_user', + self.user.id, TEST_DATA_DIR, source_dirs=['2014'], static_content_store=None, @@ -341,8 +337,6 @@ class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, Mi """ Validate tab behavior when dealing with Entrance Exams """ - MODULESTORE = TEST_DATA_MIXED_MODULESTORE - @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) def setUp(self): """ @@ -351,10 +345,6 @@ class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, Mi super().setUp() self.course = CourseFactory.create() - self.instructor_tab = ItemFactory.create( - category="instructor", parent_location=self.course.location, - data="Instructor Tab", display_name="Instructor" - ) self.extra_tab_2 = ItemFactory.create( category="static_tab", parent_location=self.course.location, data="Extra Tab", display_name="Extra Tab 2" @@ -376,7 +366,6 @@ class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, Mi entrance_exam = ItemFactory.create( category="chapter", parent_location=self.course.location, - data="Exam Data", display_name="Entrance Exam", is_entrance_exam=True ) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index d79b77a33f..8124d8e3ac 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -43,12 +43,7 @@ from xmodule.data import CertificatesDisplayBehaviors from xmodule.graders import ShowCorrectness from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import ( - TEST_DATA_MONGO_AMNESTY_MODULESTORE, - CourseUserType, - ModuleStoreTestCase, - SharedModuleStoreTestCase -) +from xmodule.modulestore.tests.django_utils import CourseUserType, ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import ( CourseFactory, ItemFactory, @@ -402,15 +397,10 @@ class IndexQueryTestCase(ModuleStoreTestCase): CREATE_USER = False NUM_PROBLEMS = 20 - @ddt.data( - (ModuleStoreEnum.Type.mongo, 10, 220), - (ModuleStoreEnum.Type.split, 4, 205), - ) - @ddt.unpack - def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count): + def test_index_query_counts(self): # TODO: decrease query count as part of REVO-28 ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1)) - with self.store.default_store(store_type): + with self.store.default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() with self.store.bulk_operations(course.id): chapter = ItemFactory.create(category='chapter', parent_location=course.location) @@ -423,8 +413,8 @@ class IndexQueryTestCase(ModuleStoreTestCase): self.client.login(username=self.user.username, password=TEST_PASSWORD) CourseEnrollment.enroll(self.user, course.id) - with self.assertNumQueries(expected_mysql_query_count, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): - with check_mongo_calls(expected_mongo_query_count): + with self.assertNumQueries(205, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with check_mongo_calls(4): url = reverse( 'courseware_section', kwargs={ @@ -1396,16 +1386,14 @@ class ProgressPageTests(ProgressPageBaseTests): ItemFactory.create(category='acid', parent_location=self.vertical.location) self._get_progress_page() - @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) - def test_student_progress_with_valid_and_invalid_id(self, default_store): + def test_student_progress_with_valid_and_invalid_id(self): """ - Check that invalid 'student_id' raises Http404 for both old mongo and - split mongo courses. + Check that invalid 'student_id' raises Http404. """ - # Create new course with respect to 'default_store' + # Create new course # Enroll student into course - self.course = CourseFactory.create(default_store=default_store) # lint-amnesty, pylint: disable=attribute-defined-outside-init + self.course = CourseFactory.create() # lint-amnesty, pylint: disable=attribute-defined-outside-init CourseEnrollmentFactory(user=self.user, course_id=self.course.id, mode=CourseMode.HONOR) # Invalid Student Ids (Integer and Non-int) @@ -2537,17 +2525,14 @@ class TestIndexView(ModuleStoreTestCase): """ Tests of the courseware.views.index view. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @XBlock.register_temp_plugin(ViewCheckerBlock, 'view_checker') - @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) - def test_student_state(self, default_store): + def test_student_state(self): """ Verify that saved student state is loaded for xblocks rendered in the index view. """ user = UserFactory() - with modulestore().default_store(default_store): + with modulestore().default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() chapter = ItemFactory.create(parent_location=course.location, category='chapter') section = ItemFactory.create(parent_location=chapter.location, category='view_checker', @@ -2843,10 +2828,9 @@ class TestIndexViewCompleteOnView(ModuleStoreTestCase, CompletionWaffleTestMixin CourseOverview.load_from_module_store(self.course.id) CourseEnrollmentFactory(user=self.user, course_id=self.course.id) - @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) - def test_completion_service_disabled(self, default_store): + def test_completion_service_disabled(self): - self.setup_course(default_store) + self.setup_course(ModuleStoreEnum.Type.split) assert self.client.login(username=self.user.username, password='test') response = self.client.get(self.section_1_url) @@ -2855,12 +2839,11 @@ class TestIndexViewCompleteOnView(ModuleStoreTestCase, CompletionWaffleTestMixin response = self.client.get(self.section_2_url) self.assertNotContains(response, 'data-mark-completed-on-view-after-delay') - @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) - def test_completion_service_enabled(self, default_store): + def test_completion_service_enabled(self): self.override_waffle_switch(True) - self.setup_course(default_store) + self.setup_course(ModuleStoreEnum.Type.split) assert self.client.login(username=self.user.username, password='test') response = self.client.get(self.section_1_url) diff --git a/lms/djangoapps/courseware/testutils.py b/lms/djangoapps/courseware/testutils.py index 8b9efd3177..2beca75913 100644 --- a/lms/djangoapps/courseware/testutils.py +++ b/lms/djangoapps/courseware/testutils.py @@ -161,13 +161,11 @@ class RenderXBlockTestMixin(MasqueradeMixin, metaclass=ABCMeta): return response @ddt.data( - ('vertical_block', ModuleStoreEnum.Type.mongo, 13), - ('vertical_block', ModuleStoreEnum.Type.split, 5), - ('html_block', ModuleStoreEnum.Type.mongo, 14), - ('html_block', ModuleStoreEnum.Type.split, 5), + ('vertical_block', 5), + ('html_block', 5), ) @ddt.unpack - def test_courseware_html(self, block_name, default_store, mongo_calls): + def test_courseware_html(self, block_name, mongo_calls): """ To verify that the removal of courseware chrome elements is working, we include this test here to make sure the chrome elements that should @@ -175,9 +173,9 @@ class RenderXBlockTestMixin(MasqueradeMixin, metaclass=ABCMeta): If this test fails, it's probably because the HTML template for courseware has changed and COURSEWARE_CHROME_HTML_ELEMENTS needs to be updated. """ - with self.store.default_store(default_store): + with self.store.default_store(ModuleStoreEnum.Type.split): self.block_name_to_be_tested = block_name - self.setup_course(default_store) + self.setup_course(ModuleStoreEnum.Type.split) self.setup_user(admin=True, enroll=True, login=True) with check_mongo_calls(mongo_calls): @@ -190,40 +188,18 @@ class RenderXBlockTestMixin(MasqueradeMixin, metaclass=ABCMeta): for chrome_element in expected_elements: self.assertContains(response, chrome_element) - @ddt.data( - (ModuleStoreEnum.Type.mongo, 5), - (ModuleStoreEnum.Type.split, 5), - ) - @ddt.unpack - def test_success_enrolled_staff(self, default_store, mongo_calls): - with self.store.default_store(default_store): - if default_store is ModuleStoreEnum.Type.mongo: - mongo_calls = self.get_success_enrolled_staff_mongo_count() - self.setup_course(default_store) - self.setup_user(admin=True, enroll=True, login=True) + def test_success_enrolled_staff(self): + self.setup_course() + self.setup_user(admin=True, enroll=True, login=True) - # The 5 mongoDB calls include calls for - # Old Mongo: - # (1) fill_in_run - # (2) get_course in get_course_with_access - # (3) get_item for HTML block in get_module_by_usage_id - # (4) get_parent when loading HTML block - # (5) edx_notes descriptor call to get_course - # Split: - # (1) course_index - bulk_operation call - # (2) structure - get_course_with_access - # (3) definition - get_course_with_access - # (4) definition - HTML block - # (5) definition - edx_notes decorator (original_get_html) - with check_mongo_calls(mongo_calls): - self.verify_response() - - def get_success_enrolled_staff_mongo_count(self): - """ - Helper method used by test_success_enrolled_staff because one test - class using this mixin has an increased number of mongo (only) queries. - """ - return 9 + # The 5 mongoDB calls include calls for + # (1) course_index - bulk_operation call + # (2) structure - get_course_with_access + # (3) definition - get_course_with_access + # (4) definition - HTML block + # (5) definition - edx_notes decorator (original_get_html) + with check_mongo_calls(5): + self.verify_response() def test_success_unenrolled_staff(self): self.setup_course() diff --git a/lms/djangoapps/discussion/django_comment_client/base/tests.py b/lms/djangoapps/discussion/django_comment_client/base/tests.py index 1c313342d2..dd9ee9d796 100644 --- a/lms/djangoapps/discussion/django_comment_client/base/tests.py +++ b/lms/djangoapps/discussion/django_comment_client/base/tests.py @@ -403,7 +403,6 @@ class ViewsQueryCountTestCase( return inner @ddt.data( - (ModuleStoreEnum.Type.mongo, 3, 4, 39), (ModuleStoreEnum.Type.split, 3, 11, 39), ) @ddt.unpack @@ -412,7 +411,6 @@ class ViewsQueryCountTestCase( self.create_thread_helper(mock_request) @ddt.data( - (ModuleStoreEnum.Type.mongo, 3, 3, 35), (ModuleStoreEnum.Type.split, 3, 9, 35), ) @ddt.unpack diff --git a/lms/djangoapps/discussion/rest_api/tests/test_api.py b/lms/djangoapps/discussion/rest_api/tests/test_api.py index 1ed30aa2d0..413d217489 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_api.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_api.py @@ -21,9 +21,7 @@ from pytz import UTC from rest_framework.exceptions import PermissionDenied from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import ( - TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase, SharedModuleStoreTestCase, -) +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.partitions.partitions import Group, UserPartition @@ -64,7 +62,8 @@ from lms.djangoapps.discussion.rest_api.tests.utils import ( CommentsServiceMockMixin, make_minimal_cs_comment, make_minimal_cs_thread, - make_paginated_api_response + make_paginated_api_response, + parsed_body, ) from openedx.core.djangoapps.course_groups.models import CourseUserGroupPartitionGroup from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory @@ -155,8 +154,6 @@ def _set_course_discussion_blackout(course, user_id): @ddt.ddt class GetCourseTest(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase): """Test for get_course""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -172,7 +169,7 @@ class GetCourseTest(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase) def test_nonexistent_course(self): with pytest.raises(CourseNotFoundError): - get_course(self.request, CourseLocator.from_string("non/existent/course")) + get_course(self.request, CourseLocator.from_string("course-v1:non+existent+course")) def test_not_enrolled(self): unenrolled_user = UserFactory.create() @@ -188,10 +185,10 @@ class GetCourseTest(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase) assert get_course(self.request, self.course.id) == { 'id': str(self.course.id), 'blackouts': [], - 'thread_list_url': 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz', + 'thread_list_url': 'http://testserver/api/discussion/v1/threads/?course_id=course-v1%3Ax%2By%2Bz', 'following_thread_list_url': - 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&following=True', - 'topics_url': 'http://testserver/api/discussion/v1/course_topics/x/y/z', + 'http://testserver/api/discussion/v1/threads/?course_id=course-v1%3Ax%2By%2Bz&following=True', + 'topics_url': 'http://testserver/api/discussion/v1/course_topics/course-v1:x+y+z', 'allow_anonymous': True, 'allow_anonymous_to_peers': False, 'user_is_privileged': False, @@ -219,8 +216,6 @@ class GetCourseTestBlackouts(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCa """ Tests of get_course for courses that have blackout dates. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -234,9 +229,9 @@ class GetCourseTestBlackouts(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCa # A variety of formats is accepted self.course.discussion_blackouts = [ ["2015-06-09T00:00:00Z", "6-10-15"], - [1433980800000, datetime(2015, 6, 12)], + [1433980800000, datetime(2015, 6, 12, tzinfo=UTC)], ] - modulestore().update_item(self.course, self.user.id) + self.update_course(self.course, self.user.id) result = get_course(self.request, self.course.id) assert result['blackouts'] == [ {'start': '2015-06-09T00:00:00Z', 'end': '2015-06-10T00:00:00Z'}, @@ -258,8 +253,6 @@ class GetCourseTestBlackouts(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCa @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class GetCourseTopicsTest(CommentsServiceMockMixin, ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase): """Test for get_course_topics""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): httpretty.reset() @@ -345,7 +338,7 @@ class GetCourseTopicsTest(CommentsServiceMockMixin, ForumsEnableMixin, UrlResetM def test_nonexistent_course(self): with pytest.raises(CourseNotFoundError): - get_course_topics(self.request, CourseLocator.from_string("non/existent/course")) + get_course_topics(self.request, CourseLocator.from_string("course-v1:non+existent+course")) def test_not_enrolled(self): unenrolled_user = UserFactory.create() @@ -506,6 +499,7 @@ class GetCourseTopicsTest(CommentsServiceMockMixin, ForumsEnableMixin, UrlResetM ) with self.store.bulk_operations(self.course.id, emit_signals=False): + self.store.update_item(self.course, self.user.id) self.make_discussion_xblock("courseware-1", "First", "Everybody") self.make_discussion_xblock( "courseware-2", @@ -613,15 +607,15 @@ class GetCourseTopicsTest(CommentsServiceMockMixin, ForumsEnableMixin, UrlResetM { 'children': [], 'id': 'topic_id_1', - 'thread_list_url': - 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&topic_id=topic_id_1', + 'thread_list_url': 'http://testserver/api/discussion/v1/threads/' + '?course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_1', 'name': 'test_target_1', 'thread_counts': {'discussion': 0, 'question': 0}, }, ], 'id': None, - 'thread_list_url': - 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&topic_id=topic_id_1', + 'thread_list_url': 'http://testserver/api/discussion/v1/threads/' + '?course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_1', 'name': 'test_category_1', 'thread_counts': None, }, @@ -630,15 +624,15 @@ class GetCourseTopicsTest(CommentsServiceMockMixin, ForumsEnableMixin, UrlResetM { 'children': [], 'id': 'topic_id_2', - 'thread_list_url': - 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&topic_id=topic_id_2', + 'thread_list_url': 'http://testserver/api/discussion/v1/threads/' + '?course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_2', 'name': 'test_target_2', 'thread_counts': {'discussion': 0, 'question': 0}, } ], 'id': None, - 'thread_list_url': - 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&topic_id=topic_id_2', + 'thread_list_url': 'http://testserver/api/discussion/v1/threads/' + '?course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_2', 'name': 'test_category_2', 'thread_counts': None, } @@ -650,8 +644,6 @@ class GetCourseTopicsTest(CommentsServiceMockMixin, ForumsEnableMixin, UrlResetM @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase): """Test for get_thread_list""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -695,7 +687,7 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix def test_nonexistent_course(self): with pytest.raises(CourseNotFoundError): - get_thread_list(self.request, CourseLocator.from_string("non/existent/course"), 1, 1) + get_thread_list(self.request, CourseLocator.from_string("course-v1:non+existent+course"), 1, 1) def test_not_enrolled(self): self.request.user = UserFactory.create() @@ -1232,7 +1224,7 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu def test_nonexistent_course(self): with pytest.raises(CourseNotFoundError): - self.get_comment_list(self.make_minimal_cs_thread({"course_id": "non/existent/course"})) + self.get_comment_list(self.make_minimal_cs_thread({"course_id": "course-v1:non+existent+course"})) def test_not_enrolled(self): self.request.user = UserFactory.create() @@ -1713,7 +1705,7 @@ class GetUserCommentsTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedMod get_user_comments( request=self.request, author=self.user, - course_key=CourseKey.from_string("x/y/z"), + course_key=CourseKey.from_string("course-v1:x+y+z"), page=2, ) @@ -1730,7 +1722,6 @@ class CreateThreadTest( MockSignalHandlerMixin ): """Tests for create_thread""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE LONG_TITLE = ( 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ' 'Aenean commodo ligula eget dolor. Aenean massa. Cum sociis ' @@ -1808,7 +1799,7 @@ class CreateThreadTest( "read": True, }) assert actual == expected - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], @@ -1879,7 +1870,7 @@ class CreateThreadTest( }) assert actual == expected self.assertEqual( - httpretty.last_request().parsed_body, # lint-amnesty, pylint: disable=no-member + parsed_body(httpretty.last_request()), { "course_id": [str(self.course.id)], "commentable_id": ["test_topic"], @@ -1997,7 +1988,7 @@ class CreateThreadTest( try: create_thread(self.request, data) assert not expected_error - actual_post_data = httpretty.last_request().parsed_body # lint-amnesty, pylint: disable=no-member + actual_post_data = parsed_body(httpretty.last_request()) if data_group_state == "group_is_set": assert actual_post_data['group_id'] == [str(data['group_id'])] elif data_group_state == "no_group_set" and course_is_cohorted and topic_is_cohorted: @@ -2018,7 +2009,7 @@ class CreateThreadTest( cs_request = httpretty.last_request() assert urlparse(cs_request.path).path == f"/api/v1/users/{self.user.id}/subscriptions" # lint-amnesty, pylint: disable=no-member assert cs_request.method == 'POST' - assert cs_request.parsed_body == {'source_type': ['thread'], 'source_id': ['test_id']} # lint-amnesty, pylint: disable=no-member + assert parsed_body(cs_request) == {'source_type': ['thread'], 'source_id': ['test_id']} def test_voted(self): self.register_post_thread_response({"id": "test_id", "username": self.user.username}) @@ -2031,7 +2022,7 @@ class CreateThreadTest( cs_request = httpretty.last_request() assert urlparse(cs_request.path).path == '/api/v1/threads/test_id/votes' # lint-amnesty, pylint: disable=no-member assert cs_request.method == 'PUT' - assert cs_request.parsed_body == {'user_id': [str(self.user.id)], 'value': ['up']} # lint-amnesty, pylint: disable=no-member + assert parsed_body(cs_request) == {'user_id': [str(self.user.id)], 'value': ['up']} def test_abuse_flagged(self): self.register_post_thread_response({"id": "test_id", "username": self.user.username}) @@ -2043,7 +2034,7 @@ class CreateThreadTest( cs_request = httpretty.last_request() assert urlparse(cs_request.path).path == '/api/v1/threads/test_id/abuse_flag' # lint-amnesty, pylint: disable=no-member assert cs_request.method == 'PUT' - assert cs_request.parsed_body == {'user_id': [str(self.user.id)]} # lint-amnesty, pylint: disable=no-member + assert parsed_body(cs_request) == {'user_id': [str(self.user.id)]} def test_course_id_missing(self): with pytest.raises(ValidationError) as assertion: @@ -2057,7 +2048,7 @@ class CreateThreadTest( def test_nonexistent_course(self): with pytest.raises(CourseNotFoundError): - create_thread(self.request, {"course_id": "non/existent/course"}) + create_thread(self.request, {"course_id": "course-v1:non+existent+course"}) def test_not_enrolled(self): self.request.user = UserFactory.create() @@ -2089,8 +2080,6 @@ class CreateCommentTest( MockSignalHandlerMixin ): """Tests for create_comment""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -2172,7 +2161,7 @@ class CreateCommentTest( "/api/v1/threads/test_thread/comments" ) assert urlparse(httpretty.last_request().path).path == expected_url # lint-amnesty, pylint: disable=no-member - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], @@ -2258,7 +2247,7 @@ class CreateCommentTest( "/api/v1/threads/test_thread/comments" ) assert urlparse(httpretty.last_request().path).path == expected_url # pylint: disable=no-member - assert httpretty.last_request().parsed_body == { # pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { "course_id": [str(self.course.id)], "body": ["Test body"], "user_id": [str(self.user.id)], @@ -2330,7 +2319,7 @@ class CreateCommentTest( ) try: create_comment(self.request, data) - assert httpretty.last_request().parsed_body['endorsed'] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())['endorsed'] == ['True'] assert not expected_error except ValidationError: assert expected_error @@ -2346,7 +2335,7 @@ class CreateCommentTest( cs_request = httpretty.last_request() assert urlparse(cs_request.path).path == '/api/v1/comments/test_comment/votes' # lint-amnesty, pylint: disable=no-member assert cs_request.method == 'PUT' - assert cs_request.parsed_body == {'user_id': [str(self.user.id)], 'value': ['up']} # lint-amnesty, pylint: disable=no-member + assert parsed_body(cs_request) == {'user_id': [str(self.user.id)], 'value': ['up']} def test_abuse_flagged(self): self.register_post_comment_response({"id": "test_comment", "username": self.user.username}, "test_thread") @@ -2358,7 +2347,7 @@ class CreateCommentTest( cs_request = httpretty.last_request() assert urlparse(cs_request.path).path == '/api/v1/comments/test_comment/abuse_flag' # lint-amnesty, pylint: disable=no-member assert cs_request.method == 'PUT' - assert cs_request.parsed_body == {'user_id': [str(self.user.id)]} # lint-amnesty, pylint: disable=no-member + assert parsed_body(cs_request) == {'user_id': [str(self.user.id)]} def test_thread_id_missing(self): with pytest.raises(ValidationError) as assertion: @@ -2372,7 +2361,7 @@ class CreateCommentTest( def test_nonexistent_course(self): self.register_get_thread_response( - make_minimal_cs_thread({"id": "test_thread", "course_id": "non/existent/course"}) + make_minimal_cs_thread({"id": "test_thread", "course_id": "course-v1:non+existent+course"}) ) with pytest.raises(CourseNotFoundError): create_comment(self.request, self.minimal_data) @@ -2451,8 +2440,6 @@ class UpdateThreadTest( MockSignalHandlerMixin ): """Tests for update_thread""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -2514,7 +2501,7 @@ class UpdateThreadTest( 'read': True, 'title': 'Original Title' }) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['original_topic'], 'thread_type': ['discussion'], @@ -2534,7 +2521,7 @@ class UpdateThreadTest( update_thread(self.request, "test_thread", {}) def test_nonexistent_course(self): - self.register_thread({"course_id": "non/existent/course"}) + self.register_thread({"course_id": "course-v1:non+existent+course"}) with pytest.raises(CourseNotFoundError): update_thread(self.request, "test_thread", {}) @@ -2630,7 +2617,7 @@ class UpdateThreadTest( assert last_request_path == subscription_url assert httpretty.last_request().method == ('POST' if new_following else 'DELETE') request_data = ( - httpretty.last_request().parsed_body if new_following else # lint-amnesty, pylint: disable=no-member + parsed_body(httpretty.last_request()) if new_following else parse_qs(urlparse(httpretty.last_request().path).query) # lint-amnesty, pylint: disable=no-member ) request_data.pop("request_id", None) @@ -2664,7 +2651,7 @@ class UpdateThreadTest( assert last_request_path == votes_url assert httpretty.last_request().method == ('PUT' if new_vote_status else 'DELETE') actual_request_data = ( - httpretty.last_request().parsed_body if new_vote_status else # lint-amnesty, pylint: disable=no-member + parsed_body(httpretty.last_request()) if new_vote_status else parse_qs(urlparse(httpretty.last_request().path).query) # lint-amnesty, pylint: disable=no-member ) actual_request_data.pop("request_id", None) @@ -2785,7 +2772,7 @@ class UpdateThreadTest( else: assert last_request_path == (flag_url if new_flagged else unflag_url) assert httpretty.last_request().method == 'PUT' - assert httpretty.last_request().parsed_body == {'user_id': [str(self.user.id)]} # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == {'user_id': [str(self.user.id)]} def test_invalid_field(self): self.register_thread() @@ -2806,8 +2793,6 @@ class UpdateCommentTest( MockSignalHandlerMixin ): """Tests for update_comment""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -2895,7 +2880,7 @@ class UpdateCommentTest( "can_delete": True, } assert actual == expected - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'body': ['Edited body'], 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], @@ -2910,7 +2895,7 @@ class UpdateCommentTest( update_comment(self.request, "test_comment", {}) def test_nonexistent_course(self): - self.register_comment(thread_overrides={"course_id": "non/existent/course"}) + self.register_comment(thread_overrides={"course_id": "course-v1:non+existent+course"}) with pytest.raises(CourseNotFoundError): update_comment(self.request, "test_comment", {}) @@ -3054,7 +3039,7 @@ class UpdateCommentTest( assert last_request_path == votes_url assert httpretty.last_request().method == ('PUT' if new_vote_status else 'DELETE') actual_request_data = ( - httpretty.last_request().parsed_body if new_vote_status else # lint-amnesty, pylint: disable=no-member + parsed_body(httpretty.last_request()) if new_vote_status else parse_qs(urlparse(httpretty.last_request().path).query) # lint-amnesty, pylint: disable=no-member ) actual_request_data.pop("request_id", None) @@ -3175,7 +3160,7 @@ class UpdateCommentTest( else: assert last_request_path == (flag_url if new_flagged else unflag_url) assert httpretty.last_request().method == 'PUT' - assert httpretty.last_request().parsed_body == {'user_id': [str(self.user.id)]} # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == {'user_id': [str(self.user.id)]} @ddt.ddt @@ -3236,7 +3221,7 @@ class DeleteThreadTest( delete_thread(self.request, "missing_thread") def test_nonexistent_course(self): - self.register_thread({"course_id": "non/existent/course"}) + self.register_thread({"course_id": "course-v1:non+existent+course"}) with pytest.raises(CourseNotFoundError): delete_thread(self.request, self.thread_id) @@ -3379,7 +3364,7 @@ class DeleteCommentTest( def test_nonexistent_course(self): self.register_comment_and_thread( - thread_overrides={"course_id": "non/existent/course"} + thread_overrides={"course_id": "course-v1:non+existent+course"} ) with pytest.raises(CourseNotFoundError): delete_comment(self.request, self.comment_id) diff --git a/lms/djangoapps/discussion/rest_api/tests/test_serializers.py b/lms/djangoapps/discussion/rest_api/tests/test_serializers.py index 2f5afadb34..9b92573c62 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_serializers.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_serializers.py @@ -11,7 +11,7 @@ import httpretty from django.test.client import RequestFactory from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from common.djangoapps.student.tests.factories import UserFactory @@ -22,6 +22,7 @@ from lms.djangoapps.discussion.rest_api.tests.utils import ( CommentsServiceMockMixin, make_minimal_cs_comment, make_minimal_cs_thread, + parsed_body, ) from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory from openedx.core.djangoapps.django_comment_common.comment_client.comment import Comment @@ -414,8 +415,6 @@ class ThreadSerializerDeserializationTest( SharedModuleStoreTestCase ): """Tests for ThreadSerializer deserialization.""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUpClass(cls): @@ -474,7 +473,7 @@ class ThreadSerializerDeserializationTest( saved = self.save_and_reserialize(self.minimal_data) assert urlparse(httpretty.last_request().path).path ==\ '/api/v1/test_topic/threads' # lint-amnesty, pylint: disable=no-member - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], @@ -491,7 +490,7 @@ class ThreadSerializerDeserializationTest( data = self.minimal_data.copy() data["group_id"] = 42 self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], @@ -540,7 +539,7 @@ class ThreadSerializerDeserializationTest( data = self.minimal_data.copy() data["anonymous"] = True self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body["anonymous"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous"] == ['True'] def test_create_anonymous_to_peers(self): """ @@ -551,12 +550,12 @@ class ThreadSerializerDeserializationTest( data = self.minimal_data.copy() data["anonymous_to_peers"] = True self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body["anonymous_to_peers"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous_to_peers"] == ['True'] def test_update_empty(self): self.register_put_thread_response(self.existing_thread.attributes) self.save_and_reserialize({}, self.existing_thread) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['original_topic'], 'thread_type': ['discussion'], @@ -581,7 +580,7 @@ class ThreadSerializerDeserializationTest( "read": read, } saved = self.save_and_reserialize(data, self.existing_thread) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['edited_topic'], 'thread_type': ['question'], @@ -607,7 +606,7 @@ class ThreadSerializerDeserializationTest( "anonymous": True, } self.save_and_reserialize(data, self.existing_thread) - assert httpretty.last_request().parsed_body["anonymous"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous"] == ['True'] def test_update_anonymous_to_peers(self): """ @@ -619,7 +618,7 @@ class ThreadSerializerDeserializationTest( "anonymous_to_peers": True, } self.save_and_reserialize(data, self.existing_thread) - assert httpretty.last_request().parsed_body["anonymous_to_peers"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous_to_peers"] == ['True'] @ddt.data("", " ") def test_update_empty_string(self, value): @@ -648,8 +647,6 @@ class ThreadSerializerDeserializationTest( @ddt.ddt class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModuleStoreTestCase): """Tests for ThreadSerializer deserialization.""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -715,7 +712,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc "/api/v1/threads/test_thread/comments" ) assert urlparse(httpretty.last_request().path).path == expected_url # lint-amnesty, pylint: disable=no-member - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], @@ -736,7 +733,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc parent_id="test_parent" ) self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], @@ -816,7 +813,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc data = self.minimal_data.copy() data["endorsed"] = True saved = self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], @@ -838,7 +835,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc data = self.minimal_data.copy() data["anonymous"] = True self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body["anonymous"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous"] == ['True'] def test_create_anonymous_to_peers(self): """ @@ -849,12 +846,12 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc data = self.minimal_data.copy() data["anonymous_to_peers"] = True self.save_and_reserialize(data) - assert httpretty.last_request().parsed_body["anonymous_to_peers"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous_to_peers"] == ['True'] def test_update_empty(self): self.register_put_comment_response(self.existing_comment.attributes) self.save_and_reserialize({}, instance=self.existing_comment) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'body': ['Original body'], 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], @@ -872,7 +869,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc self.register_put_comment_response(cs_response_data) data = {"raw_body": "Edited body", "endorsed": True} saved = self.save_and_reserialize(data, instance=self.existing_comment) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'body': ['Edited body'], 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], @@ -907,7 +904,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc "anonymous": True, } self.save_and_reserialize(data, self.existing_comment) - assert httpretty.last_request().parsed_body["anonymous"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous"] == ['True'] def test_update_anonymous_to_peers(self): """ @@ -919,7 +916,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc "anonymous_to_peers": True, } self.save_and_reserialize(data, self.existing_comment) - assert httpretty.last_request().parsed_body["anonymous_to_peers"] == ['True'] # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request())["anonymous_to_peers"] == ['True'] @ddt.data("thread_id", "parent_id") def test_update_non_updatable(self, field): diff --git a/lms/djangoapps/discussion/rest_api/tests/test_views.py b/lms/djangoapps/discussion/rest_api/tests/test_views.py index 36ba3a0c1c..ce7aac8671 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_views.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_views.py @@ -20,7 +20,7 @@ from rest_framework.test import APIClient, APITestCase from rest_framework import status from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls from common.djangoapps.course_modes.models import CourseMode @@ -46,6 +46,7 @@ from lms.djangoapps.discussion.rest_api.tests.utils import ( make_minimal_cs_comment, make_minimal_cs_thread, make_paginated_api_response, + parsed_body, ) from openedx.core.djangoapps.course_groups.tests.helpers import config_course_cohorts from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings, Role @@ -448,7 +449,7 @@ class CommentViewSetListByUserTest( self.register_mock_endpoints() self.client.login(username=self.other_user.username, password="password") GlobalStaff().add_users(self.other_user) - url = self.build_url(self.user.username, "x/y/z") + url = self.build_url(self.user.username, "course-v1:x+y+z") response = self.client.get(url) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -484,8 +485,6 @@ class CommentViewSetListByUserTest( @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for CourseView""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() self.url = reverse("discussion_course", kwargs={"course_id": str(self.course.id)}) @@ -508,11 +507,11 @@ class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): { "id": str(self.course.id), "blackouts": [], - "thread_list_url": "http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz", + "thread_list_url": "http://testserver/api/discussion/v1/threads/?course_id=course-v1%3Ax%2By%2Bz", "following_thread_list_url": ( - "http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&following=True" + "http://testserver/api/discussion/v1/threads/?course_id=course-v1%3Ax%2By%2Bz&following=True" ), - "topics_url": "http://testserver/api/discussion/v1/course_topics/x/y/z", + "topics_url": "http://testserver/api/discussion/v1/course_topics/course-v1:x+y+z", "allow_anonymous": True, "allow_anonymous_to_peers": False, 'user_is_privileged': False, @@ -695,8 +694,6 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin, """ Tests for CourseTopicsView """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): httpretty.reset() httpretty.enable() @@ -771,17 +768,14 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin, "id": "test_topic", "name": "Test Topic", "children": [], - "thread_list_url": - "http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&topic_id=test_topic", + "thread_list_url": 'http://testserver/api/discussion/v1/threads/' + '?course_id=course-v1%3Ax%2By%2Bz&topic_id=test_topic', "thread_counts": {"discussion": 0, "question": 0}, }], } ) @ddt.data( - (2, ModuleStoreEnum.Type.mongo, 2, {"Test Topic 1": {"id": "test_topic_1"}}), - (2, ModuleStoreEnum.Type.mongo, 2, - {"Test Topic 1": {"id": "test_topic_1"}, "Test Topic 2": {"id": "test_topic_2"}}), (2, ModuleStoreEnum.Type.split, 3, {"Test Topic 1": {"id": "test_topic_1"}}), (2, ModuleStoreEnum.Type.split, 3, {"Test Topic 1": {"id": "test_topic_1"}, "Test Topic 2": {"id": "test_topic_2"}}), @@ -830,13 +824,13 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin, "children": [], "id": "topic_id_1", "thread_list_url": "http://testserver/api/discussion/v1/threads/?" - "course_id=x%2Fy%2Fz&topic_id=topic_id_1", + "course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_1", "name": "test_target_1", "thread_counts": {"discussion": 0, "question": 0}, }], "id": None, "thread_list_url": "http://testserver/api/discussion/v1/threads/?" - "course_id=x%2Fy%2Fz&topic_id=topic_id_1", + "course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_1", "name": "test_category_1", "thread_counts": None, }, @@ -846,13 +840,13 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin, "children": [], "id": "topic_id_2", "thread_list_url": "http://testserver/api/discussion/v1/threads/?" - "course_id=x%2Fy%2Fz&topic_id=topic_id_2", + "course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_2", "name": "test_target_2", "thread_counts": {"discussion": 0, "question": 0}, }], "id": None, "thread_list_url": "http://testserver/api/discussion/v1/threads/?" - "course_id=x%2Fy%2Fz&topic_id=topic_id_2", + "course_id=course-v1%3Ax%2By%2Bz&topic_id=topic_id_2", "name": "test_category_2", "thread_counts": None, } @@ -866,8 +860,6 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin, @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, ProfileImageTestMixin): """Tests for ThreadViewSet list""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() self.author = UserFactory.create() @@ -934,7 +926,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro results=expected_threads, count=1, num_pages=2, - next_link="http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz&following=&page=2", + next_link="http://testserver/api/discussion/v1/threads/?course_id=course-v1%3Ax%2By%2Bz&following=&page=2", previous_link=None ) expected_response.update({"text_search_rewrite": None}) @@ -1209,8 +1201,6 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for ThreadViewSet create""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() self.url = reverse("thread-list") @@ -1243,7 +1233,7 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): "preview_body": "Test This is a very long body that will be…", "rendered_body": "

Test

\n

This is a very long body that will be truncated for the preview.

", }) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], @@ -1280,8 +1270,6 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, PatchMediaTypeMixin): """Tests for ThreadViewSet partial_update""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): self.unsupported_media_type = JSONParser.media_type super().setUp() @@ -1313,7 +1301,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest 'read': True, 'response_count': 2 }) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], @@ -1874,8 +1862,6 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for CommentViewSet create""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() self.url = reverse("comment-list") @@ -1922,7 +1908,7 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): response_data = json.loads(response.content.decode('utf-8')) assert response_data == expected_response_data assert urlparse(httpretty.last_request().path).path == '/api/v1/threads/test_thread/comments' # lint-amnesty, pylint: disable=no-member - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], @@ -1964,8 +1950,6 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, PatchMediaTypeMixin): """Tests for CommentViewSet partial_update""" - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): self.unsupported_media_type = JSONParser.media_type super().setUp() @@ -2022,7 +2006,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes 'created_at': 'Test Created Date', 'updated_at': 'Test Updated Date' }) - assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member + assert parsed_body(httpretty.last_request()) == { 'body': ['Edited body'], 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], @@ -2259,8 +2243,6 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor """ Test the course discussion settings handler API endpoint. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -2294,7 +2276,7 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor divided_discussions = divided_inline_discussions + divided_course_wide_discussions ItemFactory.create( - parent_location=self.course.location, + parent=self.course, category='discussion', discussion_id=topic_name_to_id(self.course, 'Topic A'), discussion_category='Chapter', @@ -2371,7 +2353,7 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor self._login_as_staff() response = self.client.get( reverse('discussion_course_settings', kwargs={ - 'course_id': 'a/b/c' + 'course_id': 'course-v1:a+b+c' }) ) assert response.status_code == 404 @@ -2504,8 +2486,6 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe """ Test the course discussion roles management endpoint. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -2517,7 +2497,7 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe ) self.password = 'edx' self.user = UserFactory(username='staff', password=self.password, is_staff=True) - course_key = CourseKey.from_string('x/y/z') + course_key = CourseKey.from_string('course-v1:x+y+z') seed_permissions_roles(course_key) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @@ -2597,7 +2577,7 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe def test_non_existent_course_id(self): """Test the response when the endpoint URL contains a non-existent course id.""" self._login_as_staff() - path = self.path(course_id='a/b/c') + path = self.path(course_id='course-v1:a+b+c') response = self.client.get(path) assert response.status_code == 404 @@ -2635,7 +2615,7 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe assert response.status_code == 200 content = json.loads(response.content.decode('utf-8')) - assert content['course_id'] == 'x/y/z' + assert content['course_id'] == 'course-v1:x+y+z' assert len(content['results']) == count expected_fields = ('username', 'email', 'first_name', 'last_name', 'group_name') for item in content['results']: diff --git a/lms/djangoapps/discussion/rest_api/tests/utils.py b/lms/djangoapps/discussion/rest_api/tests/utils.py index 1e117cb4c1..fc7c917a66 100644 --- a/lms/djangoapps/discussion/rest_api/tests/utils.py +++ b/lms/djangoapps/discussion/rest_api/tests/utils.py @@ -8,6 +8,7 @@ import json import re from contextlib import closing from datetime import datetime +from urllib.parse import parse_qs import httpretty from PIL import Image @@ -30,7 +31,7 @@ def _get_thread_callback(thread_data): additional required fields. """ response_data = make_minimal_cs_thread(thread_data) - for key, val_list in request.parsed_body.items(): + for key, val_list in parsed_body(request).items(): val = val_list[0] if key in ["anonymous", "anonymous_to_peers", "closed", "pinned"]: response_data[key] = val == "True" @@ -56,7 +57,7 @@ def _get_comment_callback(comment_data, thread_id, parent_id): # are returned by the comments service response_data["thread_id"] = thread_id response_data["parent_id"] = parent_id - for key, val_list in request.parsed_body.items(): + for key, val_list in parsed_body(request).items(): val = val_list[0] if key in ["anonymous", "anonymous_to_peers", "endorsed"]: response_data[key] = val == "True" @@ -398,7 +399,7 @@ class CommentsServiceMockMixin: """ Assert that the given mock request had the expected query parameters """ - actual_params = dict(httpretty_request.querystring) + actual_params = dict(querystring(httpretty_request)) actual_params.pop("request_id") # request_id is random assert actual_params == expected_params @@ -472,7 +473,7 @@ def make_minimal_cs_thread(overrides=None): ret = { "type": "thread", "id": "dummy", - "course_id": "dummy/dummy/dummy", + "course_id": "course-v1:dummy+dummy+dummy", "commentable_id": "dummy", "group_id": None, "user_id": "0", @@ -595,3 +596,17 @@ class ProfileImageTestMixin: } } } + + +def parsed_body(request): + """Returns a parsed dictionary version of a request body""" + # This could just be HTTPrettyRequest.parsed_body, but that method double-decodes '%2B' -> '+' -> ' '. + # You can just remove this method when this issue is fixed: https://github.com/gabrielfalcao/HTTPretty/issues/240 + return parse_qs(request.body.decode('utf8')) + + +def querystring(request): + """Returns a parsed dictionary version of a query string""" + # This could just be HTTPrettyRequest.querystring, but that method double-decodes '%2B' -> '+' -> ' '. + # You can just remove this method when this issue is fixed: https://github.com/gabrielfalcao/HTTPretty/issues/240 + return parse_qs(request.path.split('?', 1)[-1]) diff --git a/lms/djangoapps/discussion/tests/test_views.py b/lms/djangoapps/discussion/tests/test_views.py index 4b4df1f810..929dfd1483 100644 --- a/lms/djangoapps/discussion/tests/test_views.py +++ b/lms/djangoapps/discussion/tests/test_views.py @@ -19,7 +19,6 @@ from edx_toggles.toggles.testutils import override_waffle_flag from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ( - TEST_DATA_MONGO_MODULESTORE, TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase, SharedModuleStoreTestCase @@ -477,32 +476,19 @@ class SingleThreadQueryCountTestCase(ForumsEnableMixin, ModuleStoreTestCase): Ensures the number of modulestore queries and number of sql queries are independent of the number of responses retrieved for a given discussion thread. """ - MODULESTORE = TEST_DATA_MONGO_MODULESTORE - @ddt.data( - # Old mongo with cache. There is an additional SQL query for old mongo - # because the first time that disabled_xblocks is queried is in call_single_thread, - # vs. the creation of the course (CourseFactory.create). The creation of the - # course is outside the context manager that is verifying the number of queries, - # and with split mongo, that method ends up querying disabled_xblocks (which is then - # cached and hence not queried as part of call_single_thread). - (ModuleStoreEnum.Type.mongo, False, 1, 5, 2, 21, 7), - (ModuleStoreEnum.Type.mongo, False, 50, 5, 2, 21, 7), # split mongo: 3 queries, regardless of thread response size. - (ModuleStoreEnum.Type.split, False, 1, 2, 2, 21, 8), - (ModuleStoreEnum.Type.split, False, 50, 2, 2, 21, 8), + (False, 1, 2, 2, 21, 8), + (False, 50, 2, 2, 21, 8), # Enabling Enterprise integration should have no effect on the number of mongo queries made. - (ModuleStoreEnum.Type.mongo, True, 1, 5, 2, 21, 7), - (ModuleStoreEnum.Type.mongo, True, 50, 5, 2, 21, 7), # split mongo: 3 queries, regardless of thread response size. - (ModuleStoreEnum.Type.split, True, 1, 2, 2, 21, 8), - (ModuleStoreEnum.Type.split, True, 50, 2, 2, 21, 8), + (True, 1, 2, 2, 21, 8), + (True, 50, 2, 2, 21, 8), ) @ddt.unpack def test_number_of_mongo_queries( self, - default_store, enterprise_enabled, num_thread_responses, num_uncached_mongo_calls, @@ -512,7 +498,7 @@ class SingleThreadQueryCountTestCase(ForumsEnableMixin, ModuleStoreTestCase): mock_request ): ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1)) - with modulestore().default_store(default_store): + with modulestore().default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}}) student = UserFactory.create() diff --git a/lms/djangoapps/grades/tests/base.py b/lms/djangoapps/grades/tests/base.py index 5fe1618fba..d50d77b643 100644 --- a/lms/djangoapps/grades/tests/base.py +++ b/lms/djangoapps/grades/tests/base.py @@ -4,7 +4,7 @@ Base file for Grades tests from crum import set_current_request -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory @@ -21,8 +21,6 @@ class GradeTestBase(SharedModuleStoreTestCase): """ Base class for some Grades tests. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -66,7 +64,7 @@ class GradeTestBase(SharedModuleStoreTestCase): cls.problem2 = ItemFactory.create( parent=cls.sequence2, category="problem", - display_name="Test Problem", + display_name="Test Problem 2", data=problem_xml ) # AED 2017-06-19: make cls.sequence belong to multiple parents, diff --git a/lms/djangoapps/grades/tests/test_course_grade_factory.py b/lms/djangoapps/grades/tests/test_course_grade_factory.py index 222a487b37..085e758d51 100644 --- a/lms/djangoapps/grades/tests/test_course_grade_factory.py +++ b/lms/djangoapps/grades/tests/test_course_grade_factory.py @@ -98,7 +98,7 @@ class TestCourseGradeFactory(GradeTestBase): with self.assertNumQueries(4), mock_get_score(1, 2): _assert_read(expected_pass=False, expected_percent=0) # start off with grade of 0 - num_queries = 42 + num_queries = 41 with self.assertNumQueries(num_queries), mock_get_score(1, 2): grade_factory.update(self.request.user, self.course, force_update_subsections=True) @@ -112,14 +112,14 @@ class TestCourseGradeFactory(GradeTestBase): with self.assertNumQueries(3): _assert_read(expected_pass=True, expected_percent=0.5) # NOT updated to grade of .25 - num_queries = 23 + num_queries = 18 with self.assertNumQueries(num_queries), mock_get_score(2, 2): grade_factory.update(self.request.user, self.course, force_update_subsections=True) with self.assertNumQueries(3): _assert_read(expected_pass=True, expected_percent=1.0) # updated to grade of 1.0 - num_queries = 29 + num_queries = 28 with self.assertNumQueries(num_queries), mock_get_score(0, 0): # the subsection now is worth zero grade_factory.update(self.request.user, self.course, force_update_subsections=True) diff --git a/lms/djangoapps/grades/tests/test_transformer.py b/lms/djangoapps/grades/tests/test_transformer.py index ada0ac8c5b..ff73566015 100644 --- a/lms/djangoapps/grades/tests/test_transformer.py +++ b/lms/djangoapps/grades/tests/test_transformer.py @@ -9,15 +9,14 @@ from copy import deepcopy import ddt import pytz +from xmodule.modulestore import ModuleStoreEnum +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import check_mongo_calls from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.course_blocks.api import get_course_blocks from lms.djangoapps.course_blocks.transformers.tests.helpers import CourseStructureTestCase from openedx.core.djangoapps.content.block_structure.api import clear_course_from_cache -from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order -from xmodule.modulestore.tests.factories import check_mongo_calls # lint-amnesty, pylint: disable=wrong-import-order from ..transformer import GradesTransformer @@ -49,7 +48,7 @@ class GradesTransformerTestCase(CourseStructureTestCase): Helper to update a course's grading policy in the modulestore. """ course.set_grading_policy(grading_policy) - modulestore().update_item(course, self.user.id) + self.update_course(course, self.user.id) def _validate_grading_policy_hash(self, course_location, grading_policy_hash): """ @@ -115,10 +114,10 @@ class GradesTransformerTestCase(CourseStructureTestCase): '#ref': 'course', '#children': [ { - 'metadata': metadata, '#type': 'problem', '#ref': 'problem', 'data': data, + **metadata, } ] } @@ -369,13 +368,13 @@ class GradesTransformerTestCase(CourseStructureTestCase): ) def test_course_version_not_collected_in_old_mongo(self): - blocks = self.build_course_with_problems() + with self.store.default_store(ModuleStoreEnum.Type.mongo): + blocks = self.build_course_with_problems() block_structure = get_course_blocks(self.student, blocks['course'].location, self.transformers) assert block_structure.get_xblock_field(blocks['course'].location, 'course_version') is None def test_course_version_collected_in_split(self): - with self.store.default_store(ModuleStoreEnum.Type.split): - blocks = self.build_course_with_problems() + blocks = self.build_course_with_problems() block_structure = get_course_blocks(self.student, blocks['course'].location, self.transformers) assert block_structure.get_xblock_field(blocks['course'].location, 'course_version') is not None assert block_structure.get_xblock_field( diff --git a/lms/djangoapps/lti_provider/tests/test_views.py b/lms/djangoapps/lti_provider/tests/test_views.py index f4c93395e0..ff1f742462 100644 --- a/lms/djangoapps/lti_provider/tests/test_views.py +++ b/lms/djangoapps/lti_provider/tests/test_views.py @@ -221,21 +221,3 @@ class LtiLaunchTestRender(LtiTestMixin, RenderXBlockTestMixin, ModuleStoreTestCa self.setup_course() self.setup_user(admin=False, enroll=True, login=False) self.verify_response() - - def get_success_enrolled_staff_mongo_count(self): - """ - Override because mongo queries are higher for this - particular test. This has not been investigated exhaustively - as mongo is no longer used much, and removing user_partitions - from inheritance fixes the problem. - - # The 9 mongoDB calls include calls for - # Old Mongo: - # (1) fill_in_run - # (2) get_course in get_course_with_access - # (3) get_item for HTML block in get_module_by_usage_id - # (4) get_parent when loading HTML block - # (5)-(8) calls related to the inherited user_partitions field. - # (9) edx_notes descriptor call to get_course - """ - return 9 diff --git a/lms/djangoapps/mobile_api/course_info/tests.py b/lms/djangoapps/mobile_api/course_info/tests.py index 1a02d93dbf..0d6156b5a0 100644 --- a/lms/djangoapps/mobile_api/course_info/tests.py +++ b/lms/djangoapps/mobile_api/course_info/tests.py @@ -104,118 +104,76 @@ class TestHandouts(MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTes """ REVERSE_INFO = {'name': 'course-handouts-list', 'params': ['course_id', 'api_version']} - @ddt.data( - (ModuleStoreEnum.Type.mongo, API_V05), - (ModuleStoreEnum.Type.mongo, API_V1), - (ModuleStoreEnum.Type.split, API_V05), - (ModuleStoreEnum.Type.split, API_V1), - ) - @ddt.unpack - def test_handouts(self, default_ms, api_version): - with self.store.default_store(default_ms): - self.add_mobile_available_toy_course() - response = self.api_response(expected_response_code=200, api_version=api_version) - assert 'Sample' in response.data['handouts_html'] + @ddt.data(API_V05, API_V1) + def test_handouts(self, api_version): + self.add_mobile_available_toy_course() + response = self.api_response(expected_response_code=200, api_version=api_version) + assert 'Sample' in response.data['handouts_html'] - @ddt.data( - (ModuleStoreEnum.Type.mongo, API_V05), - (ModuleStoreEnum.Type.mongo, API_V1), - (ModuleStoreEnum.Type.split, API_V05), - (ModuleStoreEnum.Type.split, API_V1), - ) - @ddt.unpack - def test_no_handouts(self, default_ms, api_version): - with self.store.default_store(default_ms): - self.add_mobile_available_toy_course() + @ddt.data(API_V05, API_V1) + def test_no_handouts(self, api_version): + self.add_mobile_available_toy_course() - # delete handouts in course - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): - self.store.delete_item(handouts_usage_key, self.user.id) + # delete handouts in course + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): + self.store.delete_item(handouts_usage_key, self.user.id) - response = self.api_response(expected_response_code=200, api_version=api_version) - assert response.data['handouts_html'] is None + response = self.api_response(expected_response_code=200, api_version=api_version) + assert response.data['handouts_html'] is None - @ddt.data( - (ModuleStoreEnum.Type.mongo, API_V05), - (ModuleStoreEnum.Type.mongo, API_V1), - (ModuleStoreEnum.Type.split, API_V05), - (ModuleStoreEnum.Type.split, API_V1), - ) - @ddt.unpack - def test_empty_handouts(self, default_ms, api_version): - with self.store.default_store(default_ms): - self.add_mobile_available_toy_course() + @ddt.data(API_V05, API_V1) + def test_empty_handouts(self, api_version): + self.add_mobile_available_toy_course() - # set handouts to empty tags - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - underlying_handouts = self.store.get_item(handouts_usage_key) - underlying_handouts.data = "
    " - self.store.update_item(underlying_handouts, self.user.id) - response = self.api_response(expected_response_code=200, api_version=api_version) - assert response.data['handouts_html'] is None + # set handouts to empty tags + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + underlying_handouts.data = "
      " + self.store.update_item(underlying_handouts, self.user.id) + response = self.api_response(expected_response_code=200, api_version=api_version) + assert response.data['handouts_html'] is None - @ddt.data( - (ModuleStoreEnum.Type.mongo, API_V05), - (ModuleStoreEnum.Type.mongo, API_V1), - (ModuleStoreEnum.Type.split, API_V05), - (ModuleStoreEnum.Type.split, API_V1), - ) - @ddt.unpack - def test_handouts_static_rewrites(self, default_ms, api_version): - with self.store.default_store(default_ms): - self.add_mobile_available_toy_course() + @ddt.data(API_V05, API_V1) + def test_handouts_static_rewrites(self, api_version): + self.add_mobile_available_toy_course() - # check that we start with relative static assets - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - underlying_handouts = self.store.get_item(handouts_usage_key) - assert "'/static/" in underlying_handouts.data + # check that we start with relative static assets + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + assert "'/static/" in underlying_handouts.data - # but shouldn't finish with any - response = self.api_response(api_version=api_version) - assert "'/static/" not in response.data['handouts_html'] + # but shouldn't finish with any + response = self.api_response(api_version=api_version) + assert "'/static/" not in response.data['handouts_html'] - @ddt.data( - (ModuleStoreEnum.Type.mongo, API_V05), - (ModuleStoreEnum.Type.mongo, API_V1), - (ModuleStoreEnum.Type.split, API_V05), - (ModuleStoreEnum.Type.split, API_V1), - ) - @ddt.unpack - def test_jump_to_id_handout_href(self, default_ms, api_version): - with self.store.default_store(default_ms): - self.add_mobile_available_toy_course() + @ddt.data(API_V05, API_V1) + def test_jump_to_id_handout_href(self, api_version): + self.add_mobile_available_toy_course() - # check that we start with relative static assets - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - underlying_handouts = self.store.get_item(handouts_usage_key) - underlying_handouts.data = "Intracourse Link" - self.store.update_item(underlying_handouts, self.user.id) + # check that we start with relative static assets + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + underlying_handouts.data = "Intracourse Link" + self.store.update_item(underlying_handouts, self.user.id) - # but shouldn't finish with any - response = self.api_response(api_version=api_version) - assert f'/courses/{self.course.id}/jump_to_id/' in response.data['handouts_html'] + # but shouldn't finish with any + response = self.api_response(api_version=api_version) + assert f'/courses/{self.course.id}/jump_to_id/' in response.data['handouts_html'] - @ddt.data( - (ModuleStoreEnum.Type.mongo, API_V05), - (ModuleStoreEnum.Type.mongo, API_V1), - (ModuleStoreEnum.Type.split, API_V05), - (ModuleStoreEnum.Type.split, API_V1), - ) - @ddt.unpack - def test_course_url_handout_href(self, default_ms, api_version): - with self.store.default_store(default_ms): - self.add_mobile_available_toy_course() + @ddt.data(API_V05, API_V1) + def test_course_url_handout_href(self, api_version): + self.add_mobile_available_toy_course() - # check that we start with relative static assets - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - underlying_handouts = self.store.get_item(handouts_usage_key) - underlying_handouts.data = "Linked Content" - self.store.update_item(underlying_handouts, self.user.id) + # check that we start with relative static assets + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + underlying_handouts.data = "Linked Content" + self.store.update_item(underlying_handouts, self.user.id) - # but shouldn't finish with any - response = self.api_response(api_version=api_version) - assert f'/courses/{self.course.id}/' in response.data['handouts_html'] + # but shouldn't finish with any + response = self.api_response(api_version=api_version) + assert f'/courses/{self.course.id}/' in response.data['handouts_html'] def add_mobile_available_toy_course(self): """ use toy course with handouts, and make it mobile_available """ diff --git a/lms/djangoapps/mobile_api/testutils.py b/lms/djangoapps/mobile_api/testutils.py index e81afc24e5..fe2804782a 100644 --- a/lms/djangoapps/mobile_api/testutils.py +++ b/lms/djangoapps/mobile_api/testutils.py @@ -22,7 +22,7 @@ from django.urls import reverse from django.utils import timezone from opaque_keys.edx.keys import CourseKey from rest_framework.test import APITestCase -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from common.djangoapps.student import auth @@ -41,8 +41,6 @@ class MobileAPITestCase(ModuleStoreTestCase, APITestCase): REVERSE_INFO = {'name': , 'params': []} They may also override any of the methods defined in this class to control the behavior of the TestMixins. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() self.course = CourseFactory.create( diff --git a/openedx/core/djangoapps/bookmarks/tests/test_models.py b/openedx/core/djangoapps/bookmarks/tests/test_models.py index 8fc067449b..d4daccc237 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_models.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_models.py @@ -14,7 +14,7 @@ from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls from openedx.core.djangolib.testing.utils import skip_unless_lms @@ -35,9 +35,8 @@ class BookmarksTestsBase(ModuleStoreTestCase): """ Test the Bookmark model. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE ALL_FIELDS = DEFAULT_FIELDS + OPTIONAL_FIELDS - STORE_TYPE = ModuleStoreEnum.Type.mongo + STORE_TYPE = ModuleStoreEnum.Type.split TEST_PASSWORD = 'test' ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache'] @@ -50,7 +49,7 @@ class BookmarksTestsBase(ModuleStoreTestCase): self.other_user = UserFactory.create(password=self.TEST_PASSWORD) self.setup_data(self.STORE_TYPE) - def setup_data(self, store_type=ModuleStoreEnum.Type.mongo): + def setup_data(self, store_type=ModuleStoreEnum.Type.split): """ Create courses and add some test blocks. """ with self.store.default_store(store_type): @@ -58,35 +57,33 @@ class BookmarksTestsBase(ModuleStoreTestCase): self.course = CourseFactory.create(display_name='An Introduction to API Testing') self.course_id = str(self.course.id) - with self.store.bulk_operations(self.course.id): + self.chapter_1 = ItemFactory.create( + parent=self.course, category='chapter', display_name='Week 1' + ) + self.chapter_2 = ItemFactory.create( + parent=self.course, category='chapter', display_name='Week 2' + ) - self.chapter_1 = ItemFactory.create( - parent_location=self.course.location, category='chapter', display_name='Week 1' - ) - self.chapter_2 = ItemFactory.create( - parent_location=self.course.location, category='chapter', display_name='Week 2' - ) + self.sequential_1 = ItemFactory.create( + parent=self.chapter_1, category='sequential', display_name='Lesson 1' + ) + self.sequential_2 = ItemFactory.create( + parent=self.chapter_1, category='sequential', display_name='Lesson 2' + ) - self.sequential_1 = ItemFactory.create( - parent_location=self.chapter_1.location, category='sequential', display_name='Lesson 1' - ) - self.sequential_2 = ItemFactory.create( - parent_location=self.chapter_1.location, category='sequential', display_name='Lesson 2' - ) + self.vertical_1 = ItemFactory.create( + parent=self.sequential_1, category='vertical', display_name='Subsection 1' + ) + self.vertical_2 = ItemFactory.create( + parent=self.sequential_2, category='vertical', display_name='Subsection 2' + ) + self.vertical_3 = ItemFactory.create( + parent=self.sequential_2, category='vertical', display_name='Subsection 3' + ) - self.vertical_1 = ItemFactory.create( - parent_location=self.sequential_1.location, category='vertical', display_name='Subsection 1' - ) - self.vertical_2 = ItemFactory.create( - parent_location=self.sequential_2.location, category='vertical', display_name='Subsection 2' - ) - self.vertical_3 = ItemFactory.create( - parent_location=self.sequential_2.location, category='vertical', display_name='Subsection 3' - ) - - self.html_1 = ItemFactory.create( - parent_location=self.vertical_2.location, category='html', display_name='Details 1' - ) + self.html_1 = ItemFactory.create( + parent=self.vertical_2, category='html', display_name='Details 1' + ) self.path = [ PathItem(self.chapter_1.location, self.chapter_1.display_name), @@ -135,24 +132,25 @@ class BookmarksTestsBase(ModuleStoreTestCase): with self.store.bulk_operations(self.other_course.id): self.other_chapter_1 = ItemFactory.create( - parent_location=self.other_course.location, category='chapter', display_name='Other Week 1' + parent=self.other_course, category='chapter', display_name='Other Week 1' ) self.other_sequential_1 = ItemFactory.create( - parent_location=self.other_chapter_1.location, category='sequential', display_name='Other Lesson 1' + parent=self.other_chapter_1, category='sequential', display_name='Other Lesson 1' ) self.other_sequential_2 = ItemFactory.create( - parent_location=self.other_chapter_1.location, category='sequential', display_name='Other Lesson 2' + parent=self.other_chapter_1, category='sequential', display_name='Other Lesson 2' ) self.other_vertical_1 = ItemFactory.create( - parent_location=self.other_sequential_1.location, category='vertical', display_name='Other Subsection 1' + parent=self.other_sequential_1, category='vertical', display_name='Other Subsection 1' ) self.other_vertical_2 = ItemFactory.create( - parent_location=self.other_sequential_1.location, category='vertical', display_name='Other Subsection 2' + parent=self.other_sequential_1, category='vertical', display_name='Other Subsection 2' ) # self.other_vertical_1 has two parents self.other_sequential_2.children.append(self.other_vertical_1.location) - modulestore().update_item(self.other_sequential_2, self.admin.id) + with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): + self.store.update_item(self.other_sequential_2, self.admin.id) self.other_bookmark_1 = BookmarkFactory.create( user=self.user, @@ -164,7 +162,7 @@ class BookmarksTestsBase(ModuleStoreTestCase): }), ) - def create_course_with_blocks(self, children_per_block=1, depth=1, store_type=ModuleStoreEnum.Type.mongo): + def create_course_with_blocks(self, children_per_block=1, depth=1, store_type=ModuleStoreEnum.Type.split): """ Create a course and add blocks. """ @@ -173,23 +171,23 @@ class BookmarksTestsBase(ModuleStoreTestCase): course = CourseFactory.create() display_name = 0 - with self.store.bulk_operations(course.id): - blocks_at_next_level = [course] + blocks_at_next_level = [course] - for __ in range(depth): - blocks_at_current_level = blocks_at_next_level - blocks_at_next_level = [] + for __ in range(depth): + blocks_at_current_level = blocks_at_next_level + blocks_at_next_level = [] - for block in blocks_at_current_level: - for __ in range(children_per_block): - blocks_at_next_level += [ItemFactory.create( - parent_location=block.scope_ids.usage_id, display_name=str(display_name) - )] - display_name += 1 + for block in blocks_at_current_level: + for __ in range(children_per_block): + blocks_at_next_level += [ItemFactory.create( + parent_location=block.location, display_name=str(display_name) + )] + display_name += 1 - return course + with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id): + return self.store.get_course(course.id, depth=None) - def create_course_with_bookmarks_count(self, count, store_type=ModuleStoreEnum.Type.mongo): + def create_course_with_bookmarks_count(self, count, store_type=ModuleStoreEnum.Type.split): """ Create a course, add some content and add bookmarks. """ @@ -197,10 +195,9 @@ class BookmarksTestsBase(ModuleStoreTestCase): course = CourseFactory.create() - with self.store.bulk_operations(course.id): - blocks = [ItemFactory.create( - parent_location=course.location, category='chapter', display_name=str(index) - ) for index in range(count)] + blocks = [ItemFactory.create( + parent=course, category='chapter', display_name=str(index) + ) for index in range(count)] bookmarks = [BookmarkFactory.create( user=self.user, @@ -255,7 +252,7 @@ class BookmarkModelTests(BookmarksTestsBase): super().setUp() self.vertical_4 = ItemFactory.create( - parent_location=self.sequential_2.location, + parent=self.sequential_2, category='vertical', display_name=None ) @@ -272,26 +269,21 @@ class BookmarkModelTests(BookmarksTestsBase): } @ddt.data( - (ModuleStoreEnum.Type.mongo, 'course', [], 3), - (ModuleStoreEnum.Type.mongo, 'chapter_1', [], 3), - (ModuleStoreEnum.Type.mongo, 'sequential_1', ['chapter_1'], 4), - (ModuleStoreEnum.Type.mongo, 'vertical_1', ['chapter_1', 'sequential_1'], 6), - (ModuleStoreEnum.Type.mongo, 'html_1', ['chapter_1', 'sequential_2', 'vertical_2'], 7), - (ModuleStoreEnum.Type.split, 'course', [], 3), - (ModuleStoreEnum.Type.split, 'chapter_1', [], 2), - (ModuleStoreEnum.Type.split, 'sequential_1', ['chapter_1'], 2), - (ModuleStoreEnum.Type.split, 'vertical_1', ['chapter_1', 'sequential_1'], 2), - (ModuleStoreEnum.Type.split, 'html_1', ['chapter_1', 'sequential_2', 'vertical_2'], 2), + ('course', [], 3), + ('chapter_1', [], 2), + ('sequential_1', ['chapter_1'], 2), + ('vertical_1', ['chapter_1', 'sequential_1'], 2), + ('html_1', ['chapter_1', 'sequential_2', 'vertical_2'], 2), ) @ddt.unpack - def test_path_and_queries_on_create(self, store_type, block_to_bookmark, ancestors_attrs, expected_mongo_calls): + def test_path_and_queries_on_create(self, block_to_bookmark, ancestors_attrs, expected_mongo_calls): """ In case of mongo, 1 query is used to fetch the block, and 2 by path_to_location(), and then 1 query per parent in path is needed to fetch the parent blocks. """ - self.setup_data(store_type) + self.setup_data() user = UserFactory.create() expected_path = [PathItem( @@ -353,7 +345,7 @@ class BookmarkModelTests(BookmarksTestsBase): mock_get_path.return_value = block_path html = ItemFactory.create( - parent_location=self.other_chapter_1.location, category='html', display_name='Other Lesson 1' + parent=self.other_chapter_1, category='html', display_name='Other Lesson 1' ) bookmark_data = self.get_bookmark_data(html) @@ -369,32 +361,23 @@ class BookmarkModelTests(BookmarksTestsBase): assert mock_get_path.call_count == get_path_call_count @ddt.data( - (ModuleStoreEnum.Type.mongo, 2, 2, 2), - (ModuleStoreEnum.Type.mongo, 4, 2, 2), - (ModuleStoreEnum.Type.mongo, 6, 2, 2), - (ModuleStoreEnum.Type.mongo, 2, 3, 3), - (ModuleStoreEnum.Type.mongo, 4, 3, 3), - # (ModuleStoreEnum.Type.mongo, 6, 3, 3), Too slow. - (ModuleStoreEnum.Type.mongo, 2, 4, 4), - # (ModuleStoreEnum.Type.mongo, 4, 4, 4), - (ModuleStoreEnum.Type.split, 2, 2, 1), - (ModuleStoreEnum.Type.split, 4, 2, 1), - (ModuleStoreEnum.Type.split, 2, 3, 1), - # (ModuleStoreEnum.Type.split, 4, 3, 1), - (ModuleStoreEnum.Type.split, 2, 4, 1), - + (2, 2, 1), + (4, 2, 1), + (2, 3, 1), + # (4, 3, 1), + (2, 4, 1), ) @ddt.unpack - def test_get_path_queries(self, store_type, children_per_block, depth, expected_mongo_calls): + def test_get_path_queries(self, children_per_block, depth, expected_mongo_calls): """ In case of mongo, 2 queries are used by path_to_location(), and then 1 query per parent in path is needed to fetch the parent blocks. """ - course = self.create_course_with_blocks(children_per_block, depth, store_type) + course = self.create_course_with_blocks(children_per_block, depth) # Find a leaf block. - block = modulestore().get_course(course.id, depth=None) + block = course for __ in range(depth - 1): children = block.get_children() block = children[-1] @@ -408,8 +391,8 @@ class BookmarkModelTests(BookmarksTestsBase): user = UserFactory.create() # Block does not exist - usage_key = UsageKey.from_string('i4x://edX/apis/html/interactive') - usage_key.replace(course_key=self.course.id) + key = self.course.id + usage_key = UsageKey.from_string(f'block-v1:{key.org}+{key.course}+{key.run}+type@vertical+block@interactive') assert not Bookmark.get_path(usage_key) # Block is an orphan diff --git a/openedx/core/djangoapps/bookmarks/tests/test_tasks.py b/openedx/core/djangoapps/bookmarks/tests/test_tasks.py index 075a263f01..028bcbad6d 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_tasks.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_tasks.py @@ -6,7 +6,6 @@ Tests for tasks. import ddt from xmodule.modulestore import ModuleStoreEnum -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE from xmodule.modulestore.tests.factories import ItemFactory, check_mongo_calls from ..models import XBlockCache @@ -19,8 +18,6 @@ class XBlockCacheTaskTests(BookmarksTestsBase): """ Test the XBlockCache model. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - def setUp(self): super().setUp() @@ -104,21 +101,15 @@ class XBlockCacheTaskTests(BookmarksTestsBase): } @ddt.data( - (ModuleStoreEnum.Type.mongo, 2, 2, 4), - (ModuleStoreEnum.Type.mongo, 4, 2, 4), - (ModuleStoreEnum.Type.mongo, 2, 3, 5), - (ModuleStoreEnum.Type.mongo, 4, 3, 5), - (ModuleStoreEnum.Type.mongo, 2, 4, 6), - # (ModuleStoreEnum.Type.mongo, 4, 4, 6), Too slow. - (ModuleStoreEnum.Type.split, 2, 2, 3), - (ModuleStoreEnum.Type.split, 4, 2, 3), - (ModuleStoreEnum.Type.split, 2, 3, 3), - (ModuleStoreEnum.Type.split, 2, 4, 3), + (2, 2, 3), + (4, 2, 3), + (2, 3, 3), + (2, 4, 3), ) @ddt.unpack - def test_calculate_course_xblocks_data_queries(self, store_type, children_per_block, depth, expected_mongo_calls): + def test_calculate_course_xblocks_data_queries(self, children_per_block, depth, expected_mongo_calls): - course = self.create_course_with_blocks(children_per_block, depth, store_type) + course = self.create_course_with_blocks(children_per_block, depth, ModuleStoreEnum.Type.split) # clear cache to get consistent query counts self.clear_caches() @@ -174,7 +165,7 @@ class XBlockCacheTaskTests(BookmarksTestsBase): Test that the xblocks data is persisted correctly with display_name=None. """ block_with_display_name_none = ItemFactory.create( - parent_location=self.sequential_2.location, + parent=self.sequential_2, category='vertical', display_name=None ) diff --git a/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json b/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json index e9fd2f55ec..7822ad5626 100644 --- a/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json +++ b/openedx/core/djangoapps/enrollments/tests/fixtures/course-enrollments-api-list-valid-data.json @@ -1,18 +1,18 @@ [ [ { - "course_id": "e/d/X" + "course_id": "course-v1:e+d+X" }, [ { - "course_id": "e/d/X", + "course_id": "course-v1:e+d+X", "is_active": true, "mode": "honor", "user": "student1", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "e/d/X", + "course_id": "course-v1:e+d+X", "is_active": true, "mode": "honor", "user": "student2", @@ -22,25 +22,25 @@ ], [ { - "course_id": "x/y/Z" + "course_id": "course-v1:x+y+Z" }, [ { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "verified", "user": "staff", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "honor", "user": "student2", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "verified", "user": "student3", @@ -50,19 +50,19 @@ ], [ { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "username": "student2,student3" }, [ { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "honor", "user": "student2", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "verified", "user": "student3", @@ -72,12 +72,12 @@ ], [ { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "username": "student1,student2" }, [ { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "honor", "user": "student2", @@ -91,21 +91,21 @@ }, [ { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "verified", "user": "staff", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "e/d/X", + "course_id": "course-v1:e+d+X", "is_active": true, "mode": "honor", "user": "student2", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "honor", "user": "student2", @@ -118,35 +118,35 @@ null, [ { - "course_id": "e/d/X", + "course_id": "course-v1:e+d+X", "is_active": true, "mode": "honor", "user": "student1", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "e/d/X", + "course_id": "course-v1:e+d+X", "is_active": true, "mode": "honor", "user": "student2", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "verified", "user": "student3", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "honor", "user": "student2", "created": "2018-01-01T00:00:01Z" }, { - "course_id": "x/y/Z", + "course_id": "course-v1:x+y+Z", "is_active": true, "mode": "verified", "user": "staff", diff --git a/openedx/core/djangoapps/enrollments/tests/test_views.py b/openedx/core/djangoapps/enrollments/tests/test_views.py index 309cce3bc7..c5292aaf10 100644 --- a/openedx/core/djangoapps/enrollments/tests/test_views.py +++ b/openedx/core/djangoapps/enrollments/tests/test_views.py @@ -25,7 +25,7 @@ from django.urls import reverse from freezegun import freeze_time from rest_framework import status from rest_framework.test import APITestCase -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range from common.djangoapps.course_modes.models import CourseMode @@ -1600,7 +1600,6 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase): """ Test the course enrollments list API. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE CREATED_DATA = datetime.datetime(2018, 1, 1, 0, 0, 1, tzinfo=pytz.UTC) def setUp(self): @@ -1613,7 +1612,7 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase): self.rate_limit, __ = throttle.parse_rate(throttle.rate) self.course = CourseFactory.create(org='e', number='d', run='X', emit_signals=True) - self.course2 = CourseFactory.create(org='x', number='y', run='Z', emit_signal=True) + self.course2 = CourseFactory.create(org='x', number='y', run='Z', emit_signals=True) for mode_slug in ('honor', 'verified', 'audit'): CourseModeFactory.create( diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py b/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py index 694b5d5e36..6559948290 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_utils.py @@ -84,13 +84,10 @@ class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMix """ course = CourseFactory.create() with self.store.bulk_operations(course.id): - self.chapter = ItemFactory.create(category='chapter', parent_location=course.location) - self.sequential = ItemFactory.create(category='sequential', parent_location=self.chapter.location) - self.vertical1 = ItemFactory.create(category='vertical', parent_location=self.sequential.location) - self.vertical2 = ItemFactory.create(category='vertical', parent_location=self.sequential.location) - course.children = [self.chapter] - self.chapter.children = [self.sequential] - self.sequential.children = [self.vertical1, self.vertical2] + self.chapter = ItemFactory.create(category='chapter', parent=course) + self.sequential = ItemFactory.create(category='sequential', parent=self.chapter) + self.vertical1 = ItemFactory.create(category='vertical', parent=self.sequential) + self.vertical2 = ItemFactory.create(category='vertical', parent=self.sequential) if hasattr(self, 'user_one'): CourseEnrollment.enroll(self.engaged_user, course.id) @@ -100,9 +97,9 @@ class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMix def submit_faux_completions(self): """ - Submit completions (only for user_one)g + Submit completions (only for user_one) """ - for block in self.course.children[0].children[0].children: + for block in self.sequential.get_children(): models.BlockCompletion.objects.submit_completion( user=self.engaged_user, block_key=block.location, diff --git a/openedx/features/content_type_gating/tests/test_access.py b/openedx/features/content_type_gating/tests/test_access.py index fd1726fe63..e38ab04842 100644 --- a/openedx/features/content_type_gating/tests/test_access.py +++ b/openedx/features/content_type_gating/tests/test_access.py @@ -12,6 +12,7 @@ from django.test.utils import override_settings from django.urls import reverse from django.utils import timezone from django.contrib.auth import get_user_model +from edx_toggles.toggles.testutils import override_waffle_flag from pyquery import PyQuery as pq from xmodule.modulestore.tests.django_utils import ( TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase, SharedModuleStoreTestCase, @@ -29,6 +30,7 @@ from common.djangoapps.student.tests.factories import OrgStaffFactory from common.djangoapps.student.tests.factories import StaffFactory from lms.djangoapps.courseware.module_render import load_single_xblock from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin +from lms.djangoapps.courseware.toggles import COURSEWARE_USE_LEGACY_FRONTEND from lms.djangoapps.discussion.django_comment_client.tests.factories import RoleFactory from openedx.core.djangoapps.django_comment_common.models import ( FORUM_ROLE_ADMINISTRATOR, @@ -163,9 +165,9 @@ def _assert_block_is_empty(block, user_id, course, request_factory): @override_settings(FIELD_OVERRIDE_PROVIDERS=( 'openedx.features.content_type_gating.field_override.ContentTypeGatingFieldOverride', )) +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) class TestProblemTypeAccess(SharedModuleStoreTestCase, MasqueradeMixin): # pylint: disable=missing-class-docstring - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE PROBLEM_TYPES = ['problem', 'openassessment', 'drag-and-drop-v2', 'done', 'edx_sga'] # 'html' is a component that just displays html, in these tests it is used to test that users who do not have access # to graded problems still have access to non-problems @@ -208,16 +210,19 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase, MasqueradeMixin): # pyli cls.graded_score_weight_blocks = {} for graded, has_score, weight, gated in cls.GRADED_SCORE_WEIGHT_TEST_CASES: case_name = ' Graded: ' + str(graded) + ' Has Score: ' + str(has_score) + ' Weight: ' + str(weight) - block = ItemFactory.create( - parent=cls.blocks_dict['vertical'], + block_args = { + 'parent': cls.blocks_dict['vertical'], # has_score is determined by XBlock type. It is not a value set on an instance of an XBlock. # Therefore, we create a problem component when has_score is True # and an html component when has_score is False. - category='problem' if has_score else 'html', - graded=graded, - weight=weight, - metadata=METADATA if (graded and has_score and weight) else {}, - ) + 'category': 'problem' if has_score else 'html', + 'graded': graded, + } + if has_score: + block_args['weight'] = weight + if graded and has_score and weight: + block_args['metadata'] = METADATA + block = ItemFactory.create(**block_args) # Intersperse HTML so that the content-gating renders in all blocks ItemFactory.create( parent=cls.blocks_dict['vertical'], @@ -230,7 +235,6 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase, MasqueradeMixin): # pyli metadata_lti_xblock = { 'lti_id': 'correct_lti_id', 'launch_url': 'http://{}:{}/{}'.format(host, '8765', 'correct_lti_endpoint'), - 'open_in_a_new_page': False } scored_lti_metadata = {} @@ -781,13 +785,12 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase, MasqueradeMixin): # pyli @override_settings(FIELD_OVERRIDE_PROVIDERS=( 'openedx.features.content_type_gating.field_override.ContentTypeGatingFieldOverride', )) +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) class TestConditionalContentAccess(TestConditionalContent): """ Conditional Content allows course authors to run a/b tests on course content. We want to make sure that even if one of these a/b tests are being run, the student still has the correct access to the content. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE - @classmethod def setUpClass(cls): super().setUpClass() @@ -883,6 +886,7 @@ class TestConditionalContentAccess(TestConditionalContent): @override_settings(FIELD_OVERRIDE_PROVIDERS=( 'openedx.features.content_type_gating.field_override.ContentTypeGatingFieldOverride', )) +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) class TestMessageDeduplication(ModuleStoreTestCase): """ Tests to verify that access denied messages isn't shown if multiple items in a row are denied. @@ -895,7 +899,6 @@ class TestMessageDeduplication(ModuleStoreTestCase): how it's currently tested). If that method changes to use something other than the template message, this method's checks will need to be updated. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE def setUp(self): super().setUp() diff --git a/openedx/features/course_experience/tests/views/test_course_outline.py b/openedx/features/course_experience/tests/views/test_course_outline.py index 5e3afdf185..f952ca0b7b 100644 --- a/openedx/features/course_experience/tests/views/test_course_outline.py +++ b/openedx/features/course_experience/tests/views/test_course_outline.py @@ -22,7 +22,7 @@ from pyquery import PyQuery as pq from pytz import UTC from waffle.models import Switch from xmodule.modulestore import ModuleStoreEnum -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from common.djangoapps.course_modes.models import CourseMode @@ -60,7 +60,6 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase, MasqueradeMixin): Test the course outline view. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE ENABLED_SIGNALS = ['course_published'] @classmethod @@ -77,35 +76,28 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase, MasqueradeMixin): course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1)) with cls.store.bulk_operations(course.id): chapter = ItemFactory.create(category='chapter', parent_location=course.location) - sequential = ItemFactory.create(category='sequential', parent_location=chapter.location, graded=True, format="Homework") # lint-amnesty, pylint: disable=line-too-long + sequential = ItemFactory.create(category='sequential', parent_location=chapter.location, graded=True, + format="Homework") vertical = ItemFactory.create(category='vertical', parent_location=sequential.location) - problem = ItemFactory.create(category='problem', parent_location=vertical.location) - course.children = [chapter] - chapter.children = [sequential] - sequential.children = [vertical] - vertical.children = [problem] - cls.courses.append(course) + ItemFactory.create(category='problem', parent_location=vertical.location) + cls.courses.append(cls.store.publish(course.location, ModuleStoreEnum.UserID.test)) course = CourseFactory.create() with cls.store.bulk_operations(course.id): chapter = ItemFactory.create(category='chapter', parent_location=course.location) sequential = ItemFactory.create(category='sequential', parent_location=chapter.location) sequential2 = ItemFactory.create(category='sequential', parent_location=chapter.location) - vertical = ItemFactory.create( + ItemFactory.create( category='vertical', parent_location=sequential.location, display_name="Vertical 1" ) - vertical2 = ItemFactory.create( + ItemFactory.create( category='vertical', parent_location=sequential2.location, display_name="Vertical 2" ) - course.children = [chapter] - chapter.children = [sequential, sequential2] - sequential.children = [vertical] - sequential2.children = [vertical2] - cls.courses.append(course) + cls.courses.append(cls.store.publish(course.location, ModuleStoreEnum.UserID.test)) course = CourseFactory.create() with cls.store.bulk_operations(course.id): @@ -117,11 +109,8 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase, MasqueradeMixin): graded=True, format='Homework', ) - vertical = ItemFactory.create(category='vertical', parent_location=sequential.location) - course.children = [chapter] - chapter.children = [sequential] - sequential.children = [vertical] - cls.courses.append(course) + ItemFactory.create(category='vertical', parent_location=sequential.location) + cls.courses.append(cls.store.publish(course.location, ModuleStoreEnum.UserID.test)) @classmethod def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called diff --git a/openedx/tests/xblock_integration/test_crowdsource_hinter.py b/openedx/tests/xblock_integration/test_crowdsource_hinter.py index f4d566d99b..fedd1e91ca 100644 --- a/openedx/tests/xblock_integration/test_crowdsource_hinter.py +++ b/openedx/tests/xblock_integration/test_crowdsource_hinter.py @@ -8,7 +8,7 @@ import unittest import simplejson as json from django.conf import settings from django.urls import reverse -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from common.djangoapps.student.tests.factories import GlobalStaffFactory @@ -20,7 +20,6 @@ class TestCrowdsourceHinter(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Create the test environment with the crowdsourcehinter xblock. """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE STUDENTS = [ {'email': 'view@test.com', 'password': 'foo'}, {'email': 'view2@test.com', 'password': 'foo'} diff --git a/openedx/tests/xblock_integration/test_recommender.py b/openedx/tests/xblock_integration/test_recommender.py index 9cb263f095..d245a1dfb1 100644 --- a/openedx/tests/xblock_integration/test_recommender.py +++ b/openedx/tests/xblock_integration/test_recommender.py @@ -14,19 +14,21 @@ import simplejson as json from ddt import data, ddt from django.conf import settings from django.urls import reverse -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from edx_toggles.toggles.testutils import override_waffle_flag +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from common.djangoapps.student.tests.factories import GlobalStaffFactory from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase +from lms.djangoapps.courseware.toggles import COURSEWARE_USE_LEGACY_FRONTEND from openedx.core.lib.url_utils import quote_slashes +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) class TestRecommender(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Check that Recommender state is saved properly """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE STUDENTS = [ {'email': 'view@test.com', 'password': 'foo'}, {'email': 'view2@test.com', 'password': 'foo'} diff --git a/openedx/tests/xblock_integration/xblock_testcase.py b/openedx/tests/xblock_integration/xblock_testcase.py index 55aa83772c..2f142b6bca 100644 --- a/openedx/tests/xblock_integration/xblock_testcase.py +++ b/openedx/tests/xblock_integration/xblock_testcase.py @@ -48,12 +48,14 @@ import pytz from bs4 import BeautifulSoup from django.conf import settings from django.urls import reverse +from edx_toggles.toggles.testutils import override_waffle_flag from xblock.plugin import Plugin -from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory import lms.djangoapps.lms_xblock.runtime from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase +from lms.djangoapps.courseware.toggles import COURSEWARE_USE_LEGACY_FRONTEND class XBlockEventTestMixin: @@ -240,7 +242,7 @@ class XBlockScenarioTestCaseMixin: with cls.store.bulk_operations(cls.course.id, emit_signals=False): for chapter_config in cls.test_configuration: chapter = ItemFactory.create( - parent=cls.course, + parent_location=cls.course.location, display_name="ch_" + chapter_config['urlname'], category='chapter' ) @@ -335,6 +337,7 @@ class XBlockStudentTestCaseMixin: self.login(email, password) +@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True) class XBlockTestCase(XBlockStudentTestCaseMixin, XBlockScenarioTestCaseMixin, XBlockEventTestMixin, @@ -346,7 +349,6 @@ class XBlockTestCase(XBlockStudentTestCaseMixin, Class for all XBlock-internal test cases (as opposed to integration tests). """ - MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE test_configuration = None # Children must override this! entry_point = 'xblock.test.v0'