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( 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)
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)
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)
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)
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)
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)
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)
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 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 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 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)
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)
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)
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)
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)
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'))
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_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
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)
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
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
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
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)
def setUp(self): super(TestScheduleMessageBaseTask, self).setUp() self.site = SiteFactory.create() self.schedule_config = ScheduleConfigFactory.create(site=self.site) self.basetask = ScheduleMessageBaseTask