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)
This commit is contained in:
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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': [
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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": "<h1>Test</h1>\n<p>This is a very long body that will be truncated for the preview.</p>",
|
||||
})
|
||||
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']:
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = "<ol></ol>"
|
||||
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 = "<ol></ol>"
|
||||
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 = "<a href=\"/jump_to_id/identifier\">Intracourse Link</a>"
|
||||
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 = "<a href=\"/jump_to_id/identifier\">Intracourse Link</a>"
|
||||
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 = "<a href=\"/course/identifier\">Linked Content</a>"
|
||||
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 = "<a href=\"/course/identifier\">Linked Content</a>"
|
||||
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 """
|
||||
|
||||
@@ -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': <django reverse name>, 'params': [<list of params in the URL>]}
|
||||
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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user