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:
Michael Terry
2022-01-31 14:00:57 -05:00
parent bcb0aa923e
commit b905de757b
42 changed files with 577 additions and 878 deletions

View File

@@ -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"
)

View File

@@ -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,
)

View File

@@ -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(

View File

@@ -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')

View File

@@ -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.

View File

@@ -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

View File

@@ -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):

View File

@@ -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': [

View File

@@ -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'),

View File

@@ -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

View File

@@ -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.

View File

@@ -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,

View File

@@ -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

View File

@@ -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')

View File

@@ -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)

View File

@@ -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(

View File

@@ -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')

View File

@@ -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
)

View File

@@ -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)

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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):

View File

@@ -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']:

View File

@@ -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])

View File

@@ -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()

View File

@@ -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,

View File

@@ -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)

View File

@@ -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(

View File

@@ -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

View File

@@ -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 """

View File

@@ -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(

View File

@@ -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

View File

@@ -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
)

View File

@@ -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",

View File

@@ -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(

View File

@@ -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,

View File

@@ -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()

View File

@@ -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

View File

@@ -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'}

View File

@@ -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'}

View File

@@ -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'