def test_recalculate_schedule(self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance utcnow_patch.return_value = datetime(2017, 4, 15, 6, 0) refresh_timed_schedule_instances(self.schedule, (('CommCareUser', self.user1.get_id),), date(2017, 4, 15)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 1, 1, datetime(2017, 4, 15, 16, 0), True, date(2017, 4, 15)) self.assertEqual(send_patch.call_count, 0) # Set start date in previous month refresh_timed_schedule_instances(self.schedule, (('CommCareUser', self.user1.get_id),), date(2017, 3, 14)) old_id = instance.schedule_instance_id self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertEqual(instance.schedule_instance_id, old_id) self.assertTimedScheduleInstance(instance, 1, 2, datetime(2017, 4, 15, 16, 0), True, date(2017, 3, 14)) self.assertEqual(send_patch.call_count, 0) # Set start date two months back refresh_timed_schedule_instances(self.schedule, (('CommCareUser', self.user1.get_id),), date(2017, 2, 1)) old_id = instance.schedule_instance_id self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertEqual(instance.schedule_instance_id, old_id) self.assertTimedScheduleInstance(instance, 0, 3, datetime(2017, 4, 1, 16, 0), False, date(2017, 2, 1)) self.assertEqual(send_patch.call_count, 0)
def test_keep_in_sync_with_recipients(self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance for user1 utcnow_patch.return_value = datetime(2017, 3, 16, 6, 0) refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user1.get_id), ), date(2017, 3, 16)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 3, 16, 16, 0), True, date(2017, 3, 16), self.user1) # Add user2 refresh_timed_schedule_instances(self.schedule, (('CommCareUser', self.user1.get_id), ('CommCareUser', self.user2.get_id)), date(2017, 3, 16)) self.assertNumInstancesForSchedule(2) [instance1, instance2] = get_timed_schedule_instances_for_schedule(self.schedule) if instance1.recipient_id == self.user1.get_id: user1_instance = instance1 user2_instance = instance2 else: user1_instance = instance2 user2_instance = instance1 self.assertTimedScheduleInstance(user1_instance, 0, 1, datetime(2017, 3, 16, 16, 0), True, date(2017, 3, 16), self.user1) self.assertTimedScheduleInstance(user2_instance, 0, 1, datetime(2017, 3, 16, 16, 0), True, date(2017, 3, 16), self.user2) # Remove user1 refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user2.get_id), ), date(2017, 3, 16)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 3, 16, 16, 0), True, date(2017, 3, 16), self.user2) self.assertEqual(send_patch.call_count, 0)
def test_schedule_start_to_finish(self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance using an explicit start date (a Sunday) # Based on the schedule (with start offset 3) we should start sending on the next Monday utcnow_patch.return_value = datetime(2017, 8, 2, 7, 0) refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user1.get_id), ), date(2017, 8, 6)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 8, 14, 16, 0), True, date(2017, 8, 6), self.user1) self.assertEqual(send_patch.call_count, 0) # Send first event utcnow_patch.return_value = datetime(2017, 8, 14, 16, 1) instance.handle_current_event() save_timed_schedule_instance(instance) self.assertNumInstancesForSchedule(1) self.assertTimedScheduleInstance(instance, 0, 2, datetime(2017, 8, 15, 16, 0), True, date(2017, 8, 6), self.user1) self.assertEqual(send_patch.call_count, 1) # Send second (and final) event utcnow_patch.return_value = datetime(2017, 8, 15, 16, 1) instance.handle_current_event() save_timed_schedule_instance(instance) self.assertNumInstancesForSchedule(1) self.assertTimedScheduleInstance(instance, 0, 3, datetime(2017, 8, 16, 16, 0), False, date(2017, 8, 6), self.user1) self.assertEqual(send_patch.call_count, 2)
def test_schedule_start_to_finish(self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance utcnow_patch.return_value = datetime(2017, 3, 16, 6, 0) refresh_timed_schedule_instances(self.schedule, (('CommCareUser', self.user1.get_id),), date(2017, 3, 16)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 3, 16, 16, 0), True, date(2017, 3, 16), self.user1) self.assertEqual(send_patch.call_count, 0) # Send first event utcnow_patch.return_value = datetime(2017, 3, 16, 16, 1) instance.handle_current_event() save_timed_schedule_instance(instance) self.assertNumInstancesForSchedule(1) self.assertTimedScheduleInstance(instance, 0, 2, datetime(2017, 3, 17, 16, 0), True, date(2017, 3, 16), self.user1) self.assertEqual(send_patch.call_count, 1) # Send second (and final) event utcnow_patch.return_value = datetime(2017, 3, 17, 16, 1) instance.handle_current_event() save_timed_schedule_instance(instance) self.assertNumInstancesForSchedule(1) self.assertTimedScheduleInstance(instance, 0, 3, datetime(2017, 3, 18, 16, 0), False, date(2017, 3, 16), self.user1) self.assertEqual(send_patch.call_count, 2)
def refresh_timed_schedule_instances(schedule, recipients, start_date=None): """ :param schedule: the TimedSchedule :param start_date: the date to start the TimedSchedule :param recipients: a list of (recipient_type, recipient_id) tuples; the recipient type should be one of the values checked in ScheduleInstance.recipient """ existing_instances = { (instance.recipient_type, instance.recipient_id): instance for instance in get_timed_schedule_instances_for_schedule(schedule) } recipients = convert_to_tuple_of_tuples(recipients) new_recipients = set(recipients) for recipient_type, recipient_id in new_recipients: if (recipient_type, recipient_id) not in existing_instances: instance = TimedScheduleInstance.create_for_recipient( schedule, recipient_type, recipient_id, start_date=start_date, move_to_next_event_not_in_the_past=True, ) save_timed_schedule_instance(instance) for key, schedule_instance in existing_instances.iteritems(): if key not in new_recipients: delete_timed_schedule_instance(schedule_instance) elif start_date and start_date != schedule_instance.start_date: schedule_instance.recalculate_schedule(schedule, new_start_date=start_date) save_timed_schedule_instance(schedule_instance)
def test_setting_first_event_for_today_when_time_has_not_yet_passed( self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance using "today's date" (Monday) as the start date. # Since the time has not yet passed for today's event, we schedule it for today. utcnow_patch.return_value = datetime(2017, 8, 7, 7, 0) refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user1.get_id), )) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 8, 7, 16, 0), True, date(2017, 8, 7), self.user1) self.assertEqual(send_patch.call_count, 0)
def test_setting_first_event_for_next_monday(self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance using "today's date" (a Wednesday) as a start date. # Based on the schedule we should start sending on the next Monday utcnow_patch.return_value = datetime(2017, 8, 9, 7, 0) refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user1.get_id), )) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 8, 14, 16, 0), True, date(2017, 8, 9), self.user1) self.assertEqual(send_patch.call_count, 0)
def refresh_timed_schedule_instances(schedule_id, recipients, start_date=None): """ :param schedule_id: the TimedSchedule schedule_id :param start_date: the date to start the TimedSchedule :param recipients: a list of (recipient_type, recipient_id) tuples; the recipient type should be one of the values checked in ScheduleInstance.recipient """ with CriticalSection(['refresh-timed-schedule-instances-for-%s' % schedule_id.hex], timeout=5 * 60): schedule = TimedSchedule.objects.get(schedule_id=schedule_id) TimedScheduleInstanceRefresher( schedule, recipients, get_timed_schedule_instances_for_schedule(schedule), start_date=start_date ).refresh()
def refresh_timed_schedule_instances(schedule_id, recipients, start_date=None): """ :param schedule_id: the TimedSchedule schedule_id :param start_date: the date to start the TimedSchedule :param recipients: a list of (recipient_type, recipient_id) tuples; the recipient type should be one of the values checked in ScheduleInstance.recipient """ with CriticalSection( ['refresh-timed-schedule-instances-for-%s' % schedule_id.hex], timeout=5 * 60): schedule = TimedSchedule.objects.get(schedule_id=schedule_id) TimedScheduleInstanceRefresher( schedule, recipients, get_timed_schedule_instances_for_schedule(schedule), start_date=start_date).refresh()
def test_setting_first_event_using_explicit_start_date( self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance using an explicit start date (a Thursday). # Based on the schedule we should start sending on the next Monday utcnow_patch.return_value = datetime(2017, 8, 2, 7, 0) refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user1.get_id), ), date(2017, 8, 3)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 1, datetime(2017, 8, 7, 16, 0), True, date(2017, 8, 3), self.user1) self.assertEqual(send_patch.call_count, 0)
def test_setting_first_event_for_past_schedule(self, utcnow_patch, send_patch): self.assertNumInstancesForSchedule(0) # Schedule the instance using an explicit start date in the past. # Since the date is so far back, the schedule is automatically deactivated. utcnow_patch.return_value = datetime(2017, 8, 9, 7, 0) refresh_timed_schedule_instances( self.schedule, (('CommCareUser', self.user1.get_id), ), date(2017, 7, 1)) self.assertNumInstancesForSchedule(1) [instance] = get_timed_schedule_instances_for_schedule(self.schedule) self.assertTimedScheduleInstance(instance, 0, 3, datetime(2017, 7, 5, 16, 0), False, date(2017, 7, 1), self.user1) self.assertEqual(send_patch.call_count, 0)
def refresh_timed_schedule_instances(schedule_id, recipients, start_date_iso_string=None): """ :param schedule_id: type str that is hex representation of the TimedSchedule schedule_id (UUID) :param recipients: a list of (recipient_type, recipient_id) tuples; the recipient type should be one of the values checked in ScheduleInstance.recipient :param start_date_iso_string: the date to start the TimedSchedule formatted as an iso string """ schedule_uuid = uuid.UUID(schedule_id) start_date = iso_string_to_date( start_date_iso_string) if start_date_iso_string else None with CriticalSection( ['refresh-timed-schedule-instances-for-%s' % schedule_uuid.hex], timeout=5 * 60): schedule = TimedSchedule.objects.get(schedule_id=schedule_uuid) TimedScheduleInstanceRefresher( schedule, recipients, get_timed_schedule_instances_for_schedule(schedule), start_date=start_date).refresh()
def test_get_timed_schedule_instances_for_schedule(self): self.assertEqual( set( get_timed_schedule_instances_for_schedule( TimedSchedule(schedule_id=self.schedule_id2))), set([self.timed_instance2, self.timed_instance3]))
def test_get_timed_schedule_instances_for_schedule(self): self.assertItemsEqual( get_timed_schedule_instances_for_schedule( TimedSchedule(schedule_id=self.schedule_id2)), [self.timed_instance2_p1, self.timed_instance3_p2])
def assertNumInstancesForSchedule(self, num): self.assertEqual(len(list(get_timed_schedule_instances_for_schedule(self.schedule))), num)
def tearDown(self): for instance in get_timed_schedule_instances_for_schedule(self.schedule): delete_timed_schedule_instance(instance)
def test_get_timed_schedule_instances_for_schedule(self): self.assertItemsEqual( get_timed_schedule_instances_for_schedule(TimedSchedule(schedule_id=self.schedule_id2)), [self.timed_instance2_p1, self.timed_instance3_p2] )