test_self_paced_overrides.py 6.3 KB
Newer Older
1 2
"""Tests for self-paced course due date overrides."""
# pylint: disable=missing-docstring
3 4
import datetime

5
import pytz
6
from django.test.utils import override_settings
7 8 9
from mock import patch

from courseware.access import has_access
10
from courseware.tests.factories import BetaTesterFactory
11
from lms.djangoapps.ccx.tests.test_overrides import inject_field_overrides
12
from lms.djangoapps.courseware.field_overrides import OverrideFieldData, OverrideModulestoreFieldData
13
from lms.djangoapps.django_comment_client.utils import get_accessible_discussion_xblocks
14
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
15 16 17 18 19
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory


@override_settings(
20 21
    XBLOCK_FIELD_DATA_WRAPPERS=['lms.djangoapps.courseware.field_overrides:OverrideModulestoreFieldData.wrap'],
    MODULESTORE_FIELD_OVERRIDE_PROVIDERS=['courseware.self_paced_overrides.SelfPacedDateOverrideProvider'],
22 23 24 25 26 27 28
)
class SelfPacedDateOverrideTest(ModuleStoreTestCase):
    """
    Tests for self-paced due date overrides.
    """

    def setUp(self):
29
        self.reset_setting_cache_variables()
30
        super(SelfPacedDateOverrideTest, self).setUp()
31 32 33

        SelfPacedConfiguration(enabled=True).save()

34
        self.non_staff_user, __ = self.create_non_staff_user()
35 36
        self.now = datetime.datetime.now(pytz.UTC).replace(microsecond=0)
        self.future = self.now + datetime.timedelta(days=30)
37 38

    def tearDown(self):
39
        self.reset_setting_cache_variables()
40
        super(SelfPacedDateOverrideTest, self).tearDown()
41

42 43 44 45 46 47
    def reset_setting_cache_variables(self):
        """
        The overridden settings for this class get cached on class variables.
        Reset those to None before and after running the test to ensure clean
        behavior.
        """
48
        OverrideFieldData.provider_classes = None
49
        OverrideModulestoreFieldData.provider_classes = None
50

51 52
    def setup_course(self, **course_kwargs):
        """Set up a course with provided course attributes.
53 54 55 56

        Creates a child block with a due date, and ensures that field
        overrides are correctly applied for both blocks.
        """
57
        course = CourseFactory.create(**course_kwargs)
58
        section = ItemFactory.create(parent=course, due=self.now)
59
        inject_field_overrides((course, section), course, self.user)
60 61
        return (course, section)

62 63
    def create_discussion_xblocks(self, parent):
        # Create a released discussion xblock
64 65 66 67 68 69 70
        ItemFactory.create(
            parent=parent,
            category='discussion',
            display_name='released',
            start=self.now,
        )

71
        # Create a scheduled discussion xblock
72 73 74 75 76 77 78 79
        ItemFactory.create(
            parent=parent,
            category='discussion',
            display_name='scheduled',
            start=self.future,
        )

    def test_instructor_paced_due_date(self):
80
        __, ip_section = self.setup_course(display_name="Instructor Paced Course", self_paced=False)
81
        self.assertEqual(ip_section.due, self.now)
82

83
    def test_self_paced_due_date(self):
84
        __, sp_section = self.setup_course(display_name="Self-Paced Course", self_paced=True)
85 86
        self.assertIsNone(sp_section.due)

87
    def test_self_paced_disabled_due_date(self):
88
        SelfPacedConfiguration(enabled=False).save()
89
        __, sp_section = self.setup_course(display_name="Self-Paced Course", self_paced=True)
90
        self.assertEqual(sp_section.due, self.now)
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

    @patch.dict('courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
    def test_course_access_to_beta_users(self):
        """
        Test that beta testers can access `self_paced` course prior to start date.
        """
        now = datetime.datetime.now(pytz.UTC)
        one_month_from_now = now + datetime.timedelta(days=30)
        course_options = {
            'days_early_for_beta': 100,
            'self_paced': True,
            'start': one_month_from_now,
        }
        # Create a `self_paced` course and add a beta tester in it
        self_paced_course, self_paced_section = self.setup_course(**course_options)
        beta_tester = BetaTesterFactory(course_key=self_paced_course.id)

        # Verify course is `self_paced` and course has start date but not section.
109 110 111
        self.assertTrue(self_paced_course.self_paced)
        self.assertEqual(self_paced_course.start, one_month_from_now)
        self.assertIsNone(self_paced_section.start)
112 113 114 115 116 117 118

        # Verify that non-staff user do not have access to the course
        self.assertFalse(has_access(self.non_staff_user, 'load', self_paced_course))

        # Verify beta tester can access the course as well as the course sections
        self.assertTrue(has_access(beta_tester, 'load', self_paced_course))
        self.assertTrue(has_access(beta_tester, 'load', self_paced_section, self_paced_course.id))
119 120

    @patch.dict('courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
121
    def test_instructor_paced_discussion_xblock_visibility(self):
122
        """
123
        Verify that discussion xblocks scheduled for release in the future are
124 125 126
        not visible to students in an instructor-paced course.
        """
        course, section = self.setup_course(start=self.now, self_paced=False)
127
        self.create_discussion_xblocks(section)
128

129 130
        # Only the released xblocks should be visible when the course is instructor-paced.
        xblocks = get_accessible_discussion_xblocks(course, self.non_staff_user)
131
        self.assertTrue(
132
            all(xblock.display_name == 'released' for xblock in xblocks)
133 134 135
        )

    @patch.dict('courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
136
    def test_self_paced_discussion_xblock_visibility(self):
137
        """
138
        Regression test. Verify that discussion xblocks scheduled for release
139 140 141
        in the future are visible to students in a self-paced course.
        """
        course, section = self.setup_course(start=self.now, self_paced=True)
142
        self.create_discussion_xblocks(section)
143

144 145 146
        # The scheduled xblocks should be visible when the course is self-paced.
        xblocks = get_accessible_discussion_xblocks(course, self.non_staff_user)
        self.assertEqual(len(xblocks), 2)
147
        self.assertTrue(
148
            any(xblock.display_name == 'scheduled' for xblock in xblocks)
149
        )