Files
edx-platform/lms/djangoapps/ccx/tests/test_overrides.py
Usama Sadiq 519384edca refactor: ran pyupgrade on lms/djangoapps (#26733)
ran pyupgrade on bulk_enroll & ccx apps.
2021-03-04 16:00:19 +05:00

172 lines
7.3 KiB
Python

"""
tests for overrides
"""
import datetime
from unittest import mock
import pytz
from ccx_keys.locator import CCXLocator
from django.test.utils import override_settings
from edx_django_utils.cache import RequestCache
from common.djangoapps.student.tests.factories import AdminFactory
from lms.djangoapps.ccx.models import CustomCourseForEdX
from lms.djangoapps.ccx.overrides import override_field_for_ccx
from lms.djangoapps.ccx.tests.utils import flatten, iter_blocks
from lms.djangoapps.courseware.courses import get_course_by_id
from lms.djangoapps.courseware.field_overrides import OverrideFieldData
from lms.djangoapps.courseware.tests.test_field_overrides import inject_field_overrides
from lms.djangoapps.courseware.testutils import FieldOverrideTestMixin
from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
@override_settings(
XBLOCK_FIELD_DATA_WRAPPERS=['lms.djangoapps.courseware.field_overrides:OverrideModulestoreFieldData.wrap'],
MODULESTORE_FIELD_OVERRIDE_PROVIDERS=['lms.djangoapps.ccx.overrides.CustomCoursesForEdxOverrideProvider'],
)
class TestFieldOverrides(FieldOverrideTestMixin, SharedModuleStoreTestCase):
"""
Make sure field overrides behave in the expected manner.
"""
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
@classmethod
def setUpClass(cls):
"""
Course is created here and shared by all the class's tests.
"""
super().setUpClass()
cls.course = CourseFactory.create()
cls.course.enable_ccx = True
# Create a course outline
start = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=pytz.UTC)
due = datetime.datetime(2010, 7, 7, 0, 0, tzinfo=pytz.UTC)
chapters = [ItemFactory.create(start=start, parent=cls.course)
for _ in range(2)]
sequentials = flatten([
[ItemFactory.create(parent=chapter) for _ in range(2)]
for chapter in chapters])
verticals = flatten([
[ItemFactory.create(due=due, parent=sequential) for _ in range(2)]
for sequential in sequentials])
blocks = flatten([ # pylint: disable=unused-variable
[ItemFactory.create(parent=vertical) for _ in range(2)]
for vertical in verticals])
def setUp(self):
"""
Set up tests
"""
super().setUp()
self.ccx = ccx = CustomCourseForEdX(
course_id=self.course.id,
display_name='Test CCX',
coach=AdminFactory.create())
ccx.save()
patch = mock.patch('lms.djangoapps.ccx.overrides.get_current_ccx')
self.get_ccx = get_ccx = patch.start()
get_ccx.return_value = ccx
self.addCleanup(patch.stop)
self.addCleanup(RequestCache.clear_all_namespaces)
inject_field_overrides(iter_blocks(ccx.course), self.course, AdminFactory.create())
self.ccx_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
self.ccx_course = get_course_by_id(self.ccx_key, depth=None)
def cleanup_provider_classes():
"""
After everything is done, clean up by un-doing the change to the
OverrideFieldData object that is done during the wrap method.
"""
OverrideFieldData.provider_classes = None
self.addCleanup(cleanup_provider_classes)
def test_override_start(self):
"""
Test that overriding start date on a chapter works.
"""
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
assert chapter.start == ccx_start
def test_override_num_queries_new_field(self):
"""
Test that for creating new field executed only create query
"""
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
# One outer SAVEPOINT/RELEASE SAVEPOINT pair around everything caused by the
# transaction.atomic decorator wrapping override_field_for_ccx.
# One SELECT and one INSERT.
# One inner SAVEPOINT/RELEASE SAVEPOINT pair around the INSERT caused by the
# transaction.atomic down in Django's get_or_create()/_create_object_from_params().
with self.assertNumQueries(6):
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
def test_override_num_queries_update_existing_field(self):
"""
Test that overriding existing field executed create, fetch and update queries.
"""
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
new_ccx_start = datetime.datetime(2015, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
with self.assertNumQueries(3):
override_field_for_ccx(self.ccx, chapter, 'start', new_ccx_start)
def test_override_num_queries_field_value_not_changed(self):
"""
Test that if value of field does not changed no query execute.
"""
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
with self.assertNumQueries(2): # 2 savepoints
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
def test_overriden_field_access_produces_no_extra_queries(self):
"""
Test no extra queries when accessing an overriden field more than once.
"""
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
# One outer SAVEPOINT/RELEASE SAVEPOINT pair around everything caused by the
# transaction.atomic decorator wrapping override_field_for_ccx.
# One SELECT and one INSERT.
# One inner SAVEPOINT/RELEASE SAVEPOINT pair around the INSERT caused by the
# transaction.atomic down in Django's get_or_create()/_create_object_from_params().
with self.assertNumQueries(6):
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
def test_override_is_inherited(self):
"""
Test that sequentials inherit overridden start date from chapter.
"""
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
assert chapter.get_children()[0].start == ccx_start
assert chapter.get_children()[1].start == ccx_start
def test_override_is_inherited_even_if_set_in_mooc(self):
"""
Test that a due date set on a chapter is inherited by grandchildren
(verticals) even if a due date is set explicitly on grandchildren in
the mooc.
"""
ccx_due = datetime.datetime(2015, 1, 1, 00, 00, tzinfo=pytz.UTC)
chapter = self.ccx_course.get_children()[0]
chapter.display_name = 'itsme!'
override_field_for_ccx(self.ccx, chapter, 'due', ccx_due)
vertical = chapter.get_children()[0].get_children()[0]
assert vertical.due == ccx_due