Example #1
0
    def test_date_with_existing_schedule(self):
        """ If a schedule is created while deadlines are disabled, they shouldn't magically appear once the feature is
        turned on. """
        course = create_self_paced_course_run(days_till_start=-1)
        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=False)
        course_config = CourseDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=False, course_id=course.id)
        ScheduleConfigFactory.create(site=self.site,
                                     enabled=True,
                                     create_schedules=True)
        enrollment = CourseEnrollmentFactory(course_id=course.id,
                                             mode=CourseMode.AUDIT)

        # The enrollment has a schedule, but the upgrade deadline should be None
        self.assertIsNone(enrollment.schedule.upgrade_deadline)

        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = CourseMode.objects.get(
            course_id=course.id,
            mode_slug=CourseMode.VERIFIED).expiration_datetime
        self.assertEqual(block.date, expected)

        # Now if we turn on the feature for this course, this existing enrollment should be unaffected
        course_config.enabled = True
        course_config.save()

        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        self.assertEqual(block.date, expected)
Example #2
0
    def handle(self, *args, **options):
        courses = modulestore().get_courses()

        # Find the largest auto-generated course, and pick the next sequence id to generate the next
        # course with.
        max_org_sequence_id = max(
            int(course.org[4:]) for course in courses
            if course.org.startswith('org.'))

        XMODULE_FACTORY_LOCK.enable()
        CourseFactory.reset_sequence(max_org_sequence_id + 1, force=True)
        course = CourseFactory.create(
            start=datetime.datetime.today() - datetime.timedelta(days=30),
            end=datetime.datetime.today() + datetime.timedelta(days=30),
            number=factory.Sequence('schedules_test_course_{}'.format),
            display_name=factory.Sequence('Schedules Test Course {}'.format),
        )
        XMODULE_FACTORY_LOCK.disable()
        course_overview = CourseOverview.load_from_module_store(course.id)
        ThreeDayNudgeSchedule.create(enrollment__course=course_overview)
        TenDayNudgeSchedule.create(enrollment__course=course_overview)
        UpgradeReminderSchedule.create(enrollment__course=course_overview)
        ContentHighlightSchedule.create(enrollment__course=course_overview)

        ScheduleConfigFactory.create(site=Site.objects.get(name='example.com'))
    def test_date_with_self_paced_with_enrollment_after_course_start(self):
        """ Enrolling after a course begins should result in the upgrade deadline being set relative to the
        enrollment date.

        Additionally, OrgDynamicUpgradeDeadlineConfiguration should override the number of days until the deadline,
        and CourseDynamicUpgradeDeadlineConfiguration should override the org-level override.
        """
        global_config = DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
        course = create_self_paced_course_run(days_till_start=-1, org_id='TestOrg')
        ScheduleConfigFactory.create(site=self.site, enabled=True, create_schedules=True)
        enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT)
        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = enrollment.created + timedelta(days=global_config.deadline_days)
        self.assertEqual(block.date, expected)

        # Orgs should be able to override the deadline
        org_config = OrgDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=True, org_id=course.org, deadline_days=4
        )
        enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT)
        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = enrollment.created + timedelta(days=org_config.deadline_days)
        self.assertEqual(block.date, expected)

        # Courses should be able to override the deadline (and the org-level override)
        course_config = CourseDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=True, course_id=course.id, deadline_days=3
        )
        enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT)
        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = enrollment.created + timedelta(days=course_config.deadline_days)
        self.assertEqual(block.date, expected)
Example #4
0
    def test_site_config(self, this_org_list, other_org_list, expected_message_count, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        this_config = SiteConfigurationFactory.create(values={'course_org_filter': this_org_list})
        other_config = SiteConfigurationFactory.create(values={'course_org_filter': other_org_list})

        for config in (this_config, other_config):
            ScheduleConfigFactory.create(site=config.site)

        user1 = UserFactory.create(id=self.task.num_bins)
        user2 = UserFactory.create(id=self.task.num_bins * 2)
        current_day, offset, target_day, upgrade_deadline = self._get_dates()

        self._schedule_factory(
            enrollment__course__org=filtered_org,
            enrollment__user=user1,
        )
        self._schedule_factory(
            enrollment__course__org=unfiltered_org,
            enrollment__user=user1,
        )
        self._schedule_factory(
            enrollment__course__org=unfiltered_org,
            enrollment__user=user2,
        )

        with patch.object(self.task, 'async_send_task') as mock_schedule_send:
            self.task().apply(kwargs=dict(
                site_id=this_config.site.id, target_day_str=serialize(target_day), day_offset=offset, bin_num=0
            ))

        self.assertEqual(mock_schedule_send.apply_async.call_count, expected_message_count)
        self.assertFalse(mock_ace.send.called)
    def setUp(self):
        super(VerifiedUpgradeToolTest, self).setUp()

        self.course_verified_mode = CourseModeFactory(
            course_id=self.course.id,
            mode_slug=CourseMode.VERIFIED,
            expiration_datetime=self.now + datetime.timedelta(days=30),
        )

        patcher = patch('openedx.core.djangoapps.schedules.signals.get_current_site')
        mock_get_current_site = patcher.start()
        self.addCleanup(patcher.stop)
        mock_get_current_site.return_value = SiteFactory.create()

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)

        ScheduleConfigFactory.create(
            site=mock_get_current_site.return_value,
            create_schedules=True
        )

        self.enrollment = CourseEnrollmentFactory(
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
            course=self.course_overview,
        )
        self.request = RequestFactory().request()
        self.request.user = self.enrollment.user
        crum.set_current_request(self.request)
Example #6
0
    def handle(self, *args, **options):
        courses = modulestore().get_courses()

        # Find the largest auto-generated course, and pick the next sequence id to generate the next
        # course with.
        max_org_sequence_id = max([0] + [
            int(course.org[4:])
            for course in courses if course.org.startswith('org.')
        ])

        XMODULE_FACTORY_LOCK.enable()
        CourseFactory.reset_sequence(max_org_sequence_id + 1, force=True)
        course = CourseFactory.create(
            start=datetime.datetime.today() - datetime.timedelta(days=30),
            end=datetime.datetime.today() + datetime.timedelta(days=30),
            number=factory.Sequence('schedules_test_course_{}'.format),
            display_name=factory.Sequence(u'Schedules Test Course {}'.format),
        )
        XMODULE_FACTORY_LOCK.disable()
        course_overview = CourseOverview.load_from_module_store(course.id)
        CourseModeFactory.create(course_id=course_overview.id,
                                 mode_slug=CourseMode.AUDIT)
        CourseModeFactory.create(course_id=course_overview.id,
                                 mode_slug=CourseMode.VERIFIED)
        CourseDurationLimitExpirySchedule.create_batch(
            20, enrollment__course=course_overview)

        ScheduleConfigFactory.create(site=Site.objects.get(name='example.com'))
    def test_site_config(self, org_list, exclude_orgs, expected_message_count, mock_schedule_send, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        site1 = SiteFactory.create(domain='foo1.bar', name='foo1.bar')
        limited_config = SiteConfigurationFactory.create(values={'course_org_filter': [filtered_org]}, site=site1)
        site2 = SiteFactory.create(domain='foo2.bar', name='foo2.bar')
        unlimited_config = SiteConfigurationFactory.create(values={'course_org_filter': []}, site=site2)

        for config in (limited_config, unlimited_config):
            ScheduleConfigFactory.create(site=config.site)

        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 2, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=filtered_org,
        )
        for _ in range(2):
            ScheduleFactory.create(
                start=datetime.datetime(2017, 8, 2, 17, 44, 30, tzinfo=pytz.UTC),
                enrollment__course__org=unfiltered_org,
            )

        test_time_str = serialize(datetime.datetime(2017, 8, 2, 17, tzinfo=pytz.UTC))
        with self.assertNumQueries(2):
            tasks.recurring_nudge_schedule_hour(
                limited_config.site.id, 3, test_time_str, org_list=org_list, exclude_orgs=exclude_orgs,
            )

        self.assertEqual(mock_schedule_send.apply_async.call_count, expected_message_count)
        self.assertFalse(mock_ace.send.called)
    def setUp(self):
        super(VerifiedUpgradeToolTest, self).setUp()

        self.course_verified_mode = CourseModeFactory(
            course_id=self.course.id,
            mode_slug=CourseMode.VERIFIED,
            expiration_datetime=self.now + datetime.timedelta(days=30),
        )

        patcher = patch(
            'openedx.core.djangoapps.schedules.signals.get_current_site')
        mock_get_current_site = patcher.start()
        self.addCleanup(patcher.stop)
        mock_get_current_site.return_value = SiteFactory.create()

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)

        ScheduleConfigFactory.create(site=mock_get_current_site.return_value,
                                     create_schedules=True)

        self.enrollment = CourseEnrollmentFactory(
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
            course=self.course_overview,
        )
        self.request = RequestFactory().request()
        self.request.user = self.enrollment.user
        crum.set_current_request(self.request)
    def test_delivery_disabled(self, mock_ace):
        ScheduleConfigFactory.create(site=self.site_config.site,
                                     deliver_recurring_nudge=False)

        mock_msg = Mock()
        tasks._recurring_nudge_schedule_send(self.site_config.site.id,
                                             mock_msg)
        self.assertFalse(mock_ace.send.called)
Example #10
0
    def setUp(self):
        super(ScheduleSendEmailTestBase, self).setUp()

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
Example #11
0
    def test_enqueue_disabled(self, mock_schedule_bin, mock_ace):
        ScheduleConfigFactory.create(site=self.site_config.site, enqueue_recurring_nudge=False)

        current_time = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC)
        nudge.ScheduleStartResolver(self.site_config.site, current_time).send(3)
        self.assertFalse(mock_schedule_bin.called)
        self.assertFalse(mock_schedule_bin.apply_async.called)
        self.assertFalse(mock_ace.send.called)
    def setUp(self):
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)
 def _update_schedule_config(self, schedule_config_kwargs):
     """
     Updates the schedule config model by making sure the new entry
     has a later timestamp.
     """
     later_time = datetime.datetime.now(pytz.UTC) + datetime.timedelta(minutes=1)
     with freeze_time(later_time):
         ScheduleConfigFactory.create(**schedule_config_kwargs)
Example #14
0
 def _update_schedule_config(self, schedule_config_kwargs):
     """
     Updates the schedule config model by making sure the new entry
     has a later timestamp.
     """
     later_time = datetime.datetime.now(pytz.UTC) + datetime.timedelta(minutes=1)
     with freeze_time(later_time):
         ScheduleConfigFactory.create(**schedule_config_kwargs)
    def test_enqueue_disabled(self, mock_schedule_bin, mock_ace):
        ScheduleConfigFactory.create(site=self.site_config.site, enqueue_recurring_nudge=False)

        current_datetime = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC)
        nudge.ScheduleStartResolver(self.site_config.site, current_datetime).send(3)
        self.assertFalse(mock_schedule_bin.called)
        self.assertFalse(mock_schedule_bin.apply_async.called)
        self.assertFalse(mock_ace.send.called)
    def test_enqueue_disabled(self, mock_schedule_bin, mock_ace):
        ScheduleConfigFactory.create(site=self.site_config.site, enqueue_upgrade_reminder=False)

        current_day = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC)
        reminder.UpgradeReminderResolver(self.site_config.site, current_day).send(3)
        self.assertFalse(mock_schedule_bin.called)
        self.assertFalse(mock_schedule_bin.apply_async.called)
        self.assertFalse(mock_ace.send.called)
    def test_site_config(self, org_list, exclude_orgs, expected_message_count,
                         mock_schedule_send, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        site1 = SiteFactory.create(domain='foo1.bar', name='foo1.bar')
        limited_config = SiteConfigurationFactory.create(
            values={'course_org_filter': [filtered_org]}, site=site1)
        site2 = SiteFactory.create(domain='foo2.bar', name='foo2.bar')
        unlimited_config = SiteConfigurationFactory.create(
            values={'course_org_filter': []}, site=site2)

        for config in (limited_config, unlimited_config):
            ScheduleConfigFactory.create(site=config.site)

        filtered_sched = ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 2, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=filtered_org,
        )
        unfiltered_scheds = [
            ScheduleFactory.create(
                start=datetime.datetime(2017,
                                        8,
                                        2,
                                        17,
                                        44,
                                        30,
                                        tzinfo=pytz.UTC),
                enrollment__course__org=unfiltered_org,
            ) for _ in range(2)
        ]

        print(filtered_sched.enrollment)
        print(filtered_sched.enrollment.course)
        print(filtered_sched.enrollment.course.org)
        print(unfiltered_scheds[0].enrollment)
        print(unfiltered_scheds[0].enrollment.course)
        print(unfiltered_scheds[0].enrollment.course.org)
        print(unfiltered_scheds[1].enrollment)
        print(unfiltered_scheds[1].enrollment.course)
        print(unfiltered_scheds[1].enrollment.course.org)

        test_time_str = serialize(
            datetime.datetime(2017, 8, 2, 17, tzinfo=pytz.UTC))
        with self.assertNumQueries(1):
            tasks.recurring_nudge_schedule_hour(
                limited_config.site.id,
                3,
                test_time_str,
                org_list=org_list,
                exclude_orgs=exclude_orgs,
            )

        print(mock_schedule_send.mock_calls)
        self.assertEqual(mock_schedule_send.apply_async.call_count,
                         expected_message_count)
        self.assertFalse(mock_ace.send.called)
    def setUp(self):
        super(TestSendRecurringNudge, self).setUp()

        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)
Example #19
0
    def setUp(self):
        super(TestSendRecurringNudge, self).setUp()

        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)
Example #20
0
    def test_enqueue_disabled(self, mock_schedule_bin, mock_ace):
        ScheduleConfigFactory.create(site=self.site_config.site,
                                     enqueue_upgrade_reminder=False)

        current_time = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC)
        reminder.UpgradeReminderResolver(self.site_config.site,
                                         current_time).send(3)
        self.assertFalse(mock_schedule_bin.called)
        self.assertFalse(mock_schedule_bin.apply_async.called)
        self.assertFalse(mock_ace.send.called)
Example #21
0
    def setUp(self):
        super(ScheduleSendEmailTestMixin, self).setUp()

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
        CommerceConfiguration.objects.create(checkout_on_ecommerce_service=True)

        self._courses_with_verified_modes = set()
    def setUp(self):
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)
    def setUp(self):
        super(ScheduleSendEmailTestMixin, self).setUp()

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
        CommerceConfiguration.objects.create(checkout_on_ecommerce_service=True)

        self._courses_with_verified_modes = set()
 def test_date_with_self_paced_with_enrollment_before_course_start(self):
     """ Enrolling before a course begins should result in the upgrade deadline being set relative to the
     course start date. """
     global_config = DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
     course = create_self_paced_course_run(days_till_start=3)
     overview = CourseOverview.get_from_id(course.id)
     expected = overview.start + timedelta(days=global_config.deadline_days)
     ScheduleConfigFactory.create(site=self.site, enabled=True, create_schedules=True)
     enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT)
     block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
     self.assertEqual(block.date, expected)
     self._check_text(block)
Example #25
0
    def setUp(self):
        super(TestSendRecurringNudge, self).setUp()

        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
    def setUp(self):
        super(TestSendRecurringNudge, self).setUp()

        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)

        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
Example #27
0
    def test_deliver_config(self, is_enabled, mock_message, mock_ace):
        schedule_config_kwargs = {
            'site': self.site_config.site,
            self.deliver_config: is_enabled,
        }
        ScheduleConfigFactory.create(**schedule_config_kwargs)

        mock_msg = Mock()
        self.deliver_task(self.site_config.site.id, mock_msg)
        if is_enabled:
            self.assertTrue(mock_ace.send.called)
        else:
            self.assertFalse(mock_ace.send.called)
Example #28
0
    def setUp(self):
        super(TestUpgradeReminder, self).setUp()

        ScheduleFactory.create(upgrade_deadline=datetime.datetime(
            2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(upgrade_deadline=datetime.datetime(
            2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
        ScheduleFactory.create(upgrade_deadline=datetime.datetime(
            2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))

        site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=site)
        ScheduleConfigFactory.create(site=self.site_config.site)
Example #29
0
    def test_site_config(self, this_org_list, other_org_list,
                         expected_message_count, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        this_config = SiteConfigurationFactory.create(
            values={'course_org_filter': this_org_list})
        other_config = SiteConfigurationFactory.create(
            values={'course_org_filter': other_org_list})

        for config in (this_config, other_config):
            ScheduleConfigFactory.create(site=config.site)

        user1 = UserFactory.create(id=self.tested_task.num_bins)
        user2 = UserFactory.create(id=self.tested_task.num_bins * 2)
        current_day, offset, target_day = self._get_dates()

        ScheduleFactory.create(
            upgrade_deadline=target_day,
            start=target_day,
            enrollment__course__org=filtered_org,
            enrollment__course__self_paced=True,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            upgrade_deadline=target_day,
            start=target_day,
            enrollment__course__org=unfiltered_org,
            enrollment__course__self_paced=True,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            upgrade_deadline=target_day,
            start=target_day,
            enrollment__course__org=unfiltered_org,
            enrollment__course__self_paced=True,
            enrollment__user=user2,
        )

        with patch.object(self.tested_task,
                          'async_send_task') as mock_schedule_send:
            self.tested_task.apply(
                kwargs=dict(site_id=this_config.site.id,
                            target_day_str=serialize(target_day),
                            day_offset=offset,
                            bin_num=0))

        self.assertEqual(mock_schedule_send.apply_async.call_count,
                         expected_message_count)
        self.assertFalse(mock_ace.send.called)
    def test_enqueue_config(self, is_enabled):
        schedule_config_kwargs = {
            'site': self.site_config.site,
            self.enqueue_config: is_enabled,
        }
        ScheduleConfigFactory.create(**schedule_config_kwargs)

        current_datetime = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC)
        with patch.object(self.task, 'apply_async') as mock_apply_async:
            self.task.enqueue(self.site_config.site, current_datetime, 3)

        if is_enabled:
            self.assertTrue(mock_apply_async.called)
        else:
            self.assertFalse(mock_apply_async.called)
    def test_deliver_config(self, is_enabled, mock_message, mock_ace):
        user = UserFactory.create()
        schedule_config_kwargs = {
            'site': self.site_config.site,
            self.deliver_config: is_enabled,
        }
        mock_message.from_string.return_value.recipient.username = user.username
        ScheduleConfigFactory.create(**schedule_config_kwargs)

        mock_msg = Mock()
        self.deliver_task(self.site_config.site.id, mock_msg)
        if is_enabled:
            self.assertTrue(mock_ace.send.called)
        else:
            self.assertFalse(mock_ace.send.called)
Example #32
0
 def test_date_with_self_paced_with_enrollment_before_course_start(self):
     """ Enrolling before a course begins should result in the upgrade deadline being set relative to the
     course start date. """
     global_config = DynamicUpgradeDeadlineConfiguration.objects.create(
         enabled=True)
     course = create_self_paced_course_run(days_till_start=3)
     overview = CourseOverview.get_from_id(course.id)
     expected = overview.start + timedelta(days=global_config.deadline_days)
     ScheduleConfigFactory.create(site=self.site,
                                  enabled=True,
                                  create_schedules=True)
     enrollment = CourseEnrollmentFactory(course_id=course.id,
                                          mode=CourseMode.AUDIT)
     block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
     self.assertEqual(block.date, expected)
     self._check_text(block)
    def test_site_config(self, org_list, exclude_orgs, expected_message_count,
                         mock_schedule_send, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        site1 = SiteFactory.create(domain='foo1.bar', name='foo1.bar')
        limited_config = SiteConfigurationFactory.create(
            values={'course_org_filter': [filtered_org]}, site=site1)
        site2 = SiteFactory.create(domain='foo2.bar', name='foo2.bar')
        unlimited_config = SiteConfigurationFactory.create(
            values={'course_org_filter': []}, site=site2)

        for config in (limited_config, unlimited_config):
            ScheduleConfigFactory.create(site=config.site)

        user1 = UserFactory.create()
        user2 = UserFactory.create()

        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 2, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=filtered_org,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 2, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=unfiltered_org,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 2, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=unfiltered_org,
            enrollment__user=user2,
        )

        test_time_str = serialize(
            datetime.datetime(2017, 8, 2, 17, tzinfo=pytz.UTC))
        with self.assertNumQueries(2):
            tasks.recurring_nudge_schedule_hour(
                limited_config.site.id,
                day=3,
                target_hour_str=test_time_str,
                org_list=org_list,
                exclude_orgs=exclude_orgs,
            )

        self.assertEqual(mock_schedule_send.apply_async.call_count,
                         expected_message_count)
        self.assertFalse(mock_ace.send.called)
Example #34
0
    def test_date_with_self_paced_with_enrollment_after_course_start(self):
        """ Enrolling after a course begins should result in the upgrade deadline being set relative to the
        enrollment date.

        Additionally, OrgDynamicUpgradeDeadlineConfiguration should override the number of days until the deadline,
        and CourseDynamicUpgradeDeadlineConfiguration should override the org-level override.
        """
        global_config = DynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=True)
        course = create_self_paced_course_run(days_till_start=-1,
                                              org_id='TestOrg')
        ScheduleConfigFactory.create(site=self.site,
                                     enabled=True,
                                     create_schedules=True)
        enrollment = CourseEnrollmentFactory(course_id=course.id,
                                             mode=CourseMode.AUDIT)
        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = enrollment.created + timedelta(
            days=global_config.deadline_days)
        self.assertEqual(block.date, expected)

        # Orgs should be able to override the deadline
        org_config = OrgDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=True, org_id=course.org, deadline_days=4)
        enrollment = CourseEnrollmentFactory(course_id=course.id,
                                             mode=CourseMode.AUDIT)
        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = enrollment.created + timedelta(
            days=org_config.deadline_days)
        self.assertEqual(block.date, expected)

        # Courses should be able to override the deadline (and the org-level override)
        course_config = CourseDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=True, course_id=course.id, deadline_days=3)
        enrollment = CourseEnrollmentFactory(course_id=course.id,
                                             mode=CourseMode.AUDIT)
        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = enrollment.created + timedelta(
            days=course_config.deadline_days)
        self.assertEqual(block.date, expected)
Example #35
0
    def test_site_config(self, org_list, exclude_orgs, expected_message_count, mock_schedule_send, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        site1 = SiteFactory.create(domain='foo1.bar', name='foo1.bar')
        limited_config = SiteConfigurationFactory.create(values={'course_org_filter': [filtered_org]}, site=site1)
        site2 = SiteFactory.create(domain='foo2.bar', name='foo2.bar')
        unlimited_config = SiteConfigurationFactory.create(values={'course_org_filter': []}, site=site2)

        for config in (limited_config, unlimited_config):
            ScheduleConfigFactory.create(site=config.site)

        user1 = UserFactory.create(id=tasks.RECURRING_NUDGE_NUM_BINS)
        user2 = UserFactory.create(id=tasks.RECURRING_NUDGE_NUM_BINS * 2)

        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 3, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=filtered_org,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 3, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=unfiltered_org,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 3, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=unfiltered_org,
            enrollment__user=user2,
        )

        test_time = datetime.datetime(2017, 8, 3, 17, tzinfo=pytz.UTC)
        test_time_str = serialize(test_time)
        with self.assertNumQueries(NUM_QUERIES_WITH_MATCHES, table_blacklist=WAFFLE_TABLES):
            tasks.recurring_nudge_schedule_bin(
                limited_config.site.id, target_day_str=test_time_str, day_offset=-3, bin_num=0,
                org_list=org_list, exclude_orgs=exclude_orgs,
            )

        self.assertEqual(mock_schedule_send.apply_async.call_count, expected_message_count)
        self.assertFalse(mock_ace.send.called)
    def test_site_config(self, org_list, exclude_orgs, expected_message_count, mock_schedule_send, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        site1 = SiteFactory.create(domain='foo1.bar', name='foo1.bar')
        limited_config = SiteConfigurationFactory.create(values={'course_org_filter': [filtered_org]}, site=site1)
        site2 = SiteFactory.create(domain='foo2.bar', name='foo2.bar')
        unlimited_config = SiteConfigurationFactory.create(values={'course_org_filter': []}, site=site2)

        for config in (limited_config, unlimited_config):
            ScheduleConfigFactory.create(site=config.site)

        user1 = UserFactory.create(id=tasks.RECURRING_NUDGE_NUM_BINS)
        user2 = UserFactory.create(id=tasks.RECURRING_NUDGE_NUM_BINS * 2)

        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 3, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=filtered_org,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 3, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=unfiltered_org,
            enrollment__user=user1,
        )
        ScheduleFactory.create(
            start=datetime.datetime(2017, 8, 3, 17, 44, 30, tzinfo=pytz.UTC),
            enrollment__course__org=unfiltered_org,
            enrollment__user=user2,
        )

        test_datetime = datetime.datetime(2017, 8, 3, 17, tzinfo=pytz.UTC)
        test_datetime_str = serialize(test_datetime)
        with self.assertNumQueries(NUM_QUERIES_WITH_MATCHES, table_blacklist=WAFFLE_TABLES):
            tasks.recurring_nudge_schedule_bin(
                limited_config.site.id, target_day_str=test_datetime_str, day_offset=-3, bin_num=0,
                org_list=org_list, exclude_orgs=exclude_orgs,
            )

        self.assertEqual(mock_schedule_send.apply_async.call_count, expected_message_count)
        self.assertFalse(mock_ace.send.called)
    def setUp(self):
        super(TestBinnedSchedulesBaseResolver, self).setUp()

        self.site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory(site=self.site)
        self.schedule_config = ScheduleConfigFactory.create(site=self.site)
        self.resolver = BinnedSchedulesBaseResolver(
            async_send_task=Mock(name='async_send_task'),
            site=self.site,
            target_datetime=datetime.datetime.now(),
            day_offset=3,
            bin_num=2,
        )
    def test_date_with_existing_schedule(self):
        """ If a schedule is created while deadlines are disabled, they shouldn't magically appear once the feature is
        turned on. """
        course = create_self_paced_course_run(days_till_start=-1)
        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=False)
        course_config = CourseDynamicUpgradeDeadlineConfiguration.objects.create(enabled=False, course_id=course.id)
        ScheduleConfigFactory.create(site=self.site, enabled=True, create_schedules=True)
        enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT)

        # The enrollment has a schedule, but the upgrade deadline should be None
        self.assertIsNone(enrollment.schedule.upgrade_deadline)

        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        expected = CourseMode.objects.get(course_id=course.id, mode_slug=CourseMode.VERIFIED).expiration_datetime
        self.assertEqual(block.date, expected)

        # Now if we turn on the feature for this course, this existing enrollment should be unaffected
        course_config.enabled = True
        course_config.save()

        block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
        self.assertEqual(block.date, expected)
    def handle(self, *args, **options):
        courses = modulestore().get_courses()

        # Find the largest auto-generated course, and pick the next sequence id to generate the next
        # course with.
        max_org_sequence_id = max([0] + [int(course.org[4:]) for course in courses if course.org.startswith('org.')])

        XMODULE_FACTORY_LOCK.enable()
        CourseFactory.reset_sequence(max_org_sequence_id + 1, force=True)
        course = CourseFactory.create(
            start=datetime.datetime.today() - datetime.timedelta(days=30),
            end=datetime.datetime.today() + datetime.timedelta(days=30),
            number=factory.Sequence('schedules_test_course_{}'.format),
            display_name=factory.Sequence(u'Schedules Test Course {}'.format),
        )
        XMODULE_FACTORY_LOCK.disable()
        course_overview = CourseOverview.load_from_module_store(course.id)
        CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.AUDIT)
        CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.VERIFIED)
        CourseDurationLimitExpirySchedule.create_batch(20, enrollment__course=course_overview)

        ScheduleConfigFactory.create(site=Site.objects.get(name='example.com'))
Example #40
0
    def setUp(self):
        super(TestBinnedSchedulesBaseResolver, self).setUp()

        self.site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory(site=self.site)
        self.schedule_config = ScheduleConfigFactory.create(site=self.site)
        self.resolver = BinnedSchedulesBaseResolver(
            async_send_task=Mock(name='async_send_task'),
            site=self.site,
            target_datetime=datetime.datetime.now(),
            day_offset=3,
            bin_num=2,
        )
    def handle(self, *args, **options):
        courses = modulestore().get_courses()

        # Find the largest auto-generated course, and pick the next sequence id to generate the next
        # course with.
        max_org_sequence_id = max(int(course.org[4:]) for course in courses if course.org.startswith('org.'))

        XMODULE_FACTORY_LOCK.enable()
        CourseFactory.reset_sequence(max_org_sequence_id + 1, force=True)
        course = CourseFactory.create(
            start=datetime.datetime.today() - datetime.timedelta(days=30),
            end=datetime.datetime.today() + datetime.timedelta(days=30),
            number=factory.Sequence('schedules_test_course_{}'.format),
            display_name=factory.Sequence('Schedules Test Course {}'.format),
        )
        XMODULE_FACTORY_LOCK.disable()
        course_overview = CourseOverview.load_from_module_store(course.id)
        ThreeDayNudgeSchedule.create(enrollment__course=course_overview)
        TenDayNudgeSchedule.create(enrollment__course=course_overview)
        UpgradeReminderSchedule.create(enrollment__course=course_overview)
        ContentHighlightSchedule.create(enrollment__course=course_overview)

        ScheduleConfigFactory.create(site=Site.objects.get(name='example.com'))
Example #42
0
    def test_site_config(self, this_org_list, other_org_list,
                         expected_message_count, mock_ace):
        filtered_org = 'filtered_org'
        unfiltered_org = 'unfiltered_org'
        this_config = SiteConfigurationFactory.create(
            site_values={'course_org_filter': this_org_list})
        other_config = SiteConfigurationFactory.create(
            site_values={'course_org_filter': other_org_list})

        for config in (this_config, other_config):
            ScheduleConfigFactory.create(site=config.site)

        user1 = UserFactory.create(id=self._next_user_id())
        user2 = UserFactory.create(id=user1.id + self.task.num_bins)
        current_day, offset, target_day, upgrade_deadline = self._get_dates()  # lint-amnesty, pylint: disable=unused-variable

        self._schedule_factory(
            enrollment__course__org=filtered_org,
            enrollment__user=user1,
        )
        self._schedule_factory(
            enrollment__course__org=unfiltered_org,
            enrollment__user=user1,
        )
        self._schedule_factory(
            enrollment__course__org=unfiltered_org,
            enrollment__user=user2,
        )

        with patch.object(self.task, 'async_send_task') as mock_schedule_send:
            self.task().apply(kwargs=dict(site_id=this_config.site.id,
                                          target_day_str=serialize(target_day),
                                          day_offset=offset,
                                          bin_num=0))

        assert mock_schedule_send.apply_async.call_count == expected_message_count
        assert not mock_ace.send.called
Example #43
0
    def test_date_with_org_and_course_config_overrides(
            self, enroll_first, org_config_enabled, org_config_opt_out,
            course_config_enabled, course_config_opt_out,
            expected_dynamic_deadline):
        """ Runs through every combination of org-level plus course-level DynamicUpgradeDeadlineConfiguration enabled
        and opt-out states to verify that course-level overrides the org-level config. """
        course = create_self_paced_course_run(days_till_start=-1,
                                              org_id='TestOrg')
        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
        ScheduleConfigFactory.create(site=self.site,
                                     enabled=True,
                                     create_schedules=True)
        if enroll_first:
            enrollment = CourseEnrollmentFactory(course_id=course.id,
                                                 mode=CourseMode.AUDIT,
                                                 course__self_paced=True)
        OrgDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=org_config_enabled,
            opt_out=org_config_opt_out,
            org_id=course.id.org)
        CourseDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=course_config_enabled,
            opt_out=course_config_opt_out,
            course_id=course.id)
        if not enroll_first:
            enrollment = CourseEnrollmentFactory(course_id=course.id,
                                                 mode=CourseMode.AUDIT,
                                                 course__self_paced=True)

        # The enrollment has a schedule, and the upgrade_deadline is set when expected_dynamic_deadline is True
        if not enroll_first:
            self.assertEqual(enrollment.schedule.upgrade_deadline is not None,
                             expected_dynamic_deadline)
        # The CourseEnrollment.upgrade_deadline property method is checking the configs
        self.assertEqual(enrollment.dynamic_upgrade_deadline is not None,
                         expected_dynamic_deadline)
    def test_date_with_org_and_course_config_overrides(self, enroll_first, org_config_enabled, org_config_opt_out,
                                                       course_config_enabled, course_config_opt_out,
                                                       expected_dynamic_deadline):
        """ Runs through every combination of org-level plus course-level DynamicUpgradeDeadlineConfiguration enabled
        and opt-out states to verify that course-level overrides the org-level config. """
        course = create_self_paced_course_run(days_till_start=-1, org_id='TestOrg')
        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)
        ScheduleConfigFactory.create(site=self.site, enabled=True, create_schedules=True)
        if enroll_first:
            enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT, course__self_paced=True)
        OrgDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=org_config_enabled, opt_out=org_config_opt_out, org_id=course.id.org
        )
        CourseDynamicUpgradeDeadlineConfiguration.objects.create(
            enabled=course_config_enabled, opt_out=course_config_opt_out, course_id=course.id
        )
        if not enroll_first:
            enrollment = CourseEnrollmentFactory(course_id=course.id, mode=CourseMode.AUDIT, course__self_paced=True)

        # The enrollment has a schedule, and the upgrade_deadline is set when expected_dynamic_deadline is True
        if not enroll_first:
            self.assertEqual(enrollment.schedule.upgrade_deadline is not None, expected_dynamic_deadline)
        # The CourseEnrollment.upgrade_deadline property method is checking the configs
        self.assertEqual(enrollment.dynamic_upgrade_deadline is not None, expected_dynamic_deadline)
Example #45
0
    def create_schedule(self, offset=0):  # lint-amnesty, pylint: disable=missing-function-docstring
        self.config = ScheduleConfigFactory()  # lint-amnesty, pylint: disable=attribute-defined-outside-init

        start = datetime.datetime.now(utc) - datetime.timedelta(days=100)
        self.course = CourseFactory.create(start=start, self_paced=True)  # lint-amnesty, pylint: disable=attribute-defined-outside-init

        self.enrollment = CourseEnrollmentFactory(  # lint-amnesty, pylint: disable=attribute-defined-outside-init
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
        )
        self.enrollment.created = start + datetime.timedelta(days=offset)
        self.enrollment.save()

        self.schedule = self.enrollment.schedule  # lint-amnesty, pylint: disable=attribute-defined-outside-init
        self.schedule.start_date = self.enrollment.created
        self.schedule.save()

        self.user = self.enrollment.user  # lint-amnesty, pylint: disable=attribute-defined-outside-init
Example #46
0
    def create_schedule(self, enrollment_offset=0, course_start_offset=-100):
        """Makes a course, schedule, and enrollment ready to test"""
        # pylint: disable=attribute-defined-outside-init
        self.config = ScheduleConfigFactory()

        start = datetime.datetime.now(utc) + datetime.timedelta(
            days=course_start_offset)
        self.course = CourseFactory.create(start=start, self_paced=True)

        self.enrollment = CourseEnrollmentFactory(
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
        )
        self.enrollment.created = start + datetime.timedelta(
            days=enrollment_offset)
        self.enrollment.save()

        self.schedule = self.enrollment.schedule
        self.schedule.start_date = self.enrollment.created
        self.schedule.save()

        self.user = self.enrollment.user
Example #47
0
    def create_schedule(self, offset=0):  # lint-amnesty, pylint: disable=missing-function-docstring
        self.config = ScheduleConfigFactory(create_schedules=True)  # lint-amnesty, pylint: disable=attribute-defined-outside-init

        site_patch = patch('openedx.core.djangoapps.schedules.signals.get_current_site', return_value=self.config.site)
        self.addCleanup(site_patch.stop)
        site_patch.start()

        start = datetime.datetime.now(utc) - datetime.timedelta(days=100)
        self.course = CourseFactory.create(start=start, self_paced=True)  # lint-amnesty, pylint: disable=attribute-defined-outside-init

        self.enrollment = CourseEnrollmentFactory(  # lint-amnesty, pylint: disable=attribute-defined-outside-init
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
        )
        self.enrollment.created = start + datetime.timedelta(days=offset)
        self.enrollment.save()

        self.schedule = self.enrollment.schedule  # lint-amnesty, pylint: disable=attribute-defined-outside-init
        self.schedule.start_date = self.enrollment.created
        self.schedule.save()

        self.user = self.enrollment.user  # lint-amnesty, pylint: disable=attribute-defined-outside-init
    def create_schedule(self, offset=0):
        self.config = ScheduleConfigFactory(create_schedules=True)

        site_patch = patch('openedx.core.djangoapps.schedules.signals.get_current_site', return_value=self.config.site)
        self.addCleanup(site_patch.stop)
        site_patch.start()

        start = datetime.datetime.now(utc) - datetime.timedelta(days=100)
        self.course = CourseFactory.create(start=start, self_paced=True)

        self.enrollment = CourseEnrollmentFactory(
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
        )
        self.enrollment.created = start + datetime.timedelta(days=offset)
        self.enrollment.save()

        self.schedule = self.enrollment.schedule
        self.schedule.start_date = self.enrollment.created
        self.schedule.save()

        self.user = self.enrollment.user
Example #49
0
    def setUp(self):
        super(TestBinnedSchedulesBaseResolver, self).setUp()

        self.site = SiteFactory.create()
        self.site_config = SiteConfigurationFactory.create(site=self.site)
        self.schedule_config = ScheduleConfigFactory.create(site=self.site)
Example #50
0
    def setUp(self):
        super(TestScheduleMessageBaseTask, self).setUp()

        self.site = SiteFactory.create()
        self.schedule_config = ScheduleConfigFactory.create(site=self.site)
        self.basetask = ScheduleMessageBaseTask
    def test_delivery_disabled(self, mock_ace):
        ScheduleConfigFactory.create(site=self.site_config.site, deliver_recurring_nudge=False)

        mock_msg = Mock()
        tasks._recurring_nudge_schedule_send(self.site_config.site.id, mock_msg)
        self.assertFalse(mock_ace.send.called)