def test_pillow_processes_changes(self, find_duplicate_cases_mock): kafka_sec = get_topic_offset(topics.FORM_SQL) case1 = self.factory.create_case(case_name="foo", case_type=self.case_type, update={"age": 2}) case2 = self.factory.create_case(case_name="foo", case_type=self.case_type, update={"age": 2}) find_duplicate_cases_mock.return_value = [case1.case_id, case2.case_id] AutomaticUpdateRule.clear_caches( self.domain, AutomaticUpdateRule.WORKFLOW_DEDUPLICATE) new_kafka_sec = get_topic_offset(topics.FORM_SQL) self.pillow.process_changes(since=kafka_sec, forever=False) self._assert_case_duplicate_pair(case1.case_id, [case2.case_id]) self._assert_case_duplicate_pair(case2.case_id, [case1.case_id]) self.assertEqual(CaseDuplicate.objects.count(), 2) self.assertEqual( CommCareCase.objects.get_case( case1.case_id, self.domain).get_case_property('age'), '5') self.assertEqual( CommCareCase.objects.get_case(case1.case_id, self.domain).name, 'Herman Miller') # The new changes present should not be processed by the pillow # processor, since they were updates from a duplicate action. with patch.object(CaseDeduplicationProcessor, '_process_case_update') as p: self.pillow.process_changes(since=new_kafka_sec, forever=False) p.assert_not_called()
def test_run_messaging_rule(self, task_patch): schedule = AlertSchedule.create_simple_alert( self.domain, SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_action( CreateScheduleInstanceActionDefinition, alert_schedule_id=schedule.schedule_id, recipients=(('Self', None),), ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) with create_case(self.domain, 'person') as case1, create_case(self.domain, 'person') as case2: run_messaging_rule(self.domain, rule.pk) self.assertEqual(task_patch.call_count, 2) task_patch.assert_has_calls( [ call(self.domain, case1.case_id, rule.pk), call(self.domain, case2.case_id, rule.pk), ], any_order=True )
def test_timed_schedule_instance_creation(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=time(9, 0)), SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_criteria( MatchPropertyDefinition, property_name='start_sending', property_value='Y', match_type=MatchPropertyDefinition.MATCH_EQUAL, ) rule.add_action( CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),) ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 5, 1, 7, 0) with create_case(self.domain, 'person') as case: # Rule does not match, no instances created instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0) # Make the rule match. On the first iteration, the instance is created. On the second, # no new instance is created since it already exists. for minute in [1, 2]: utcnow_patch.return_value = datetime(2017, 5, 1, 7, minute) update_case(self.domain, case.case_id, case_properties={'start_sending': 'Y'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 5, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 5, 1, 13, 0)) self.assertTrue(instances[0].active) # Make the rule not match. Instance should no longer exist. utcnow_patch.return_value = datetime(2017, 5, 1, 7, 3) update_case(self.domain, case.case_id, case_properties={'start_sending': 'N'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0)
def response_data_cleanup(domain, new_plan_version): """ Any active automatic case update rules should be deactivated. """ try: AutomaticUpdateRule.by_domain( domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, ).update(active=False) AutomaticUpdateRule.clear_caches( domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE) return True except Exception: log_accounting_error("Failed to deactivate automatic update rules " "for domain %s." % domain.name) return False
def response_data_cleanup(domain, new_plan_version): """ Any active automatic case update rules should be deactivated. """ try: AutomaticUpdateRule.by_domain( domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, ).update(active=False) AutomaticUpdateRule.clear_caches(domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE) return True except Exception: log_accounting_error( "Failed to deactivate automatic update rules " "for domain %s." % domain.name ) return False
def _set_up_rule(self, include_closed): self.rule = AutomaticUpdateRule.objects.create( domain=self.domain, name='test', case_type=self.case_type, active=True, deleted=False, filter_on_server_modified=False, server_modified_boundary=None, workflow=AutomaticUpdateRule.WORKFLOW_DEDUPLICATE, ) _, self.action = self.rule.add_action( CaseDeduplicationActionDefinition, match_type=CaseDeduplicationMatchTypeChoices.ALL, case_properties=["case_name", "age"], include_closed=include_closed) self.action.save() AutomaticUpdateRule.clear_caches( self.domain, AutomaticUpdateRule.WORKFLOW_DEDUPLICATE)
def setUpClass(cls): super().setUpClass() cls.domain = 'naboo' cls.case_type = 'people' cls.factory = CaseFactory(cls.domain) cls.pillow = get_xform_pillow(skip_ucr=True) cls.rule = AutomaticUpdateRule.objects.create( domain=cls.domain, name='test', case_type=cls.case_type, active=True, deleted=False, filter_on_server_modified=False, server_modified_boundary=None, workflow=AutomaticUpdateRule.WORKFLOW_DEDUPLICATE, ) _, cls.action = cls.rule.add_action( CaseDeduplicationActionDefinition, match_type=CaseDeduplicationMatchTypeChoices.ALL, case_properties=["case_name", "age"], ) cls.action.set_properties_to_update([ CaseDeduplicationActionDefinition.PropertyDefinition( name='age', value_type=CaseDeduplicationActionDefinition.VALUE_TYPE_EXACT, value='5', ), CaseDeduplicationActionDefinition.PropertyDefinition( name='case_name', value_type=CaseDeduplicationActionDefinition.VALUE_TYPE_EXACT, value='Herman Miller', ) ]) cls.action.save() AutomaticUpdateRule.clear_caches( cls.domain, AutomaticUpdateRule.WORKFLOW_DEDUPLICATE)
def test_start_offset(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=time(9, 0)), SMSContent(message={'en': 'Hello'}), start_offset=2, ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_action( CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),), ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 8, 1, 15, 0) with create_case(self.domain, 'person') as case: instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 3, 13, 0)) self.assertEqual(instances[0].schedule_revision, schedule.get_schedule_revision()) self.assertTrue(instances[0].active) # Change the schedule's start offset and force a case update to reprocess the schedule instance. # The start date should not change, but the schedule instance should respond to the new start offset # by calculating a new next_event_due timestamp. schedule.start_offset = 5 schedule.save() schedule = TimedSchedule.objects.get(schedule_id=schedule.schedule_id) utcnow_patch.return_value = datetime(2017, 8, 4, 7, 0) update_case(self.domain, case.case_id, case_properties={'new_property': 'new value'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0)) self.assertEqual(instances[0].schedule_revision, schedule.get_schedule_revision()) self.assertTrue(instances[0].active) # Making another arbitrary update doesn't cause any recalculating to happen with patch('corehq.messaging.scheduling.scheduling_partitioned.models.AbstractTimedScheduleInstance.recalculate_schedule') as recalculate_patch: update_case(self.domain, case.case_id, case_properties={'new_property': 'new value 2'}) self.assertEqual(recalculate_patch.call_count, 0) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0)) self.assertEqual(instances[0].schedule_revision, schedule.get_schedule_revision()) self.assertTrue(instances[0].active)
def test_visit_scheduler_integration(self, utcnow_patch, module_and_form_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=time(9, 0)), SMSContent(message={'en': 'Hello'}), total_iterations=1, ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) _, definition = rule.add_action( CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),) ) module, form = get_visit_scheduler_module_and_form_for_test() definition.set_scheduler_module_info(CreateScheduleInstanceActionDefinition.SchedulerModuleInfo( enabled=True, app_id='n/a for test', form_unique_id=form.unique_id, visit_number=1, window_position=VISIT_WINDOW_START, )) definition.save() AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 8, 1, 7, 0) module_and_form_patch.return_value = module, form with create_case(self.domain, 'person') as case: # Schedule phase does not match, nothing is scheduled instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0) update_case(self.domain, case.case_id, case_properties={'add': '2017-08-01', 'current_schedule_phase': '2'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 6)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0)) self.assertTrue(instances[0].active) # If the anchor date gets updated (due to correction, for example), the schedule recalculates update_case(self.domain, case.case_id, case_properties={'add': '2017-08-10'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 15)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 15, 13, 0)) self.assertTrue(instances[0].active) # If the anchor date is in the past, the schedule instance is deactivated update_case(self.domain, case.case_id, case_properties={'add': '2017-07-01'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 7, 6)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 2) self.assertEqual(instances[0].next_event_due, datetime(2017, 7, 7, 13, 0)) self.assertFalse(instances[0].active) # If the anchor date is reset, the schedule instance is reactivated update_case(self.domain, case.case_id, case_properties={'add': '2017-08-01'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 6)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0)) self.assertTrue(instances[0].active) # Making an arbitrary update doesn't cause any recalculating to happen with patch('corehq.messaging.scheduling.scheduling_partitioned.models.AbstractTimedScheduleInstance.recalculate_schedule') as recalculate_patch: update_case(self.domain, case.case_id, case_properties={'new_property': 'new value'}) self.assertEqual(recalculate_patch.call_count, 0) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 8, 6)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0)) self.assertTrue(instances[0].active) # Terminate the schedule, no more schedule instances should be scheduled update_case(self.domain, case.case_id, case_properties={'current_schedule_phase': '-1'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0)
def test_timed_schedule_case_property_timed_event(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, CasePropertyTimedEvent(case_property_name='reminder_time'), SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_criteria( MatchPropertyDefinition, property_name='start_sending', property_value='Y', match_type=MatchPropertyDefinition.MATCH_EQUAL, ) rule.add_action( CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),), ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 5, 1, 7, 0) with create_case(self.domain, 'person') as case: # Rule does not match, no instances created instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0) # Make the rule match, but don't give a preferred time. Default scheduling time is used. update_case(self.domain, case.case_id, case_properties={'start_sending': 'Y'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 5, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 5, 1, 16, 0)) self.assertTrue(instances[0].active) # Update the preferred time, and the schedule should recalculate update_case(self.domain, case.case_id, case_properties={'reminder_time': '09:00'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 5, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 5, 1, 13, 0)) self.assertTrue(instances[0].active) # Update the preferred time to a bad value and the default time is used again. update_case(self.domain, case.case_id, case_properties={'reminder_time': 'x'}) instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].start_date, date(2017, 5, 1)) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 5, 1, 16, 0)) self.assertTrue(instances[0].active)
def test_alert_schedule_reset(self, utcnow_patch): schedule = AlertSchedule.create_simple_alert( self.domain, SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_criteria( MatchPropertyDefinition, property_name='start_sending', property_value='Y', match_type=MatchPropertyDefinition.MATCH_EQUAL, ) rule.add_action( CreateScheduleInstanceActionDefinition, alert_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),), reset_case_property_name='reset_property', ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 5, 1, 7, 0) with create_case(self.domain, 'person') as case: # Rule does not match, no instances created instances = get_case_alert_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0) # Make the rule match. On the first iteration, the instance is created. On the second, # nothing is changed. for minute in (1, 2): utcnow_patch.return_value = datetime(2017, 5, 1, 7, minute) update_case(self.domain, case.case_id, case_properties={'start_sending': 'Y', 'reset_property': 'a'}) instances = get_case_alert_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].alert_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 5, 1, 7, 1)) self.assertEqual(instances[0].last_reset_case_property_value, 'a') self.assertTrue(instances[0].active) # Update the reset property, and the instance is reset. utcnow_patch.return_value = datetime(2017, 6, 1, 7, 0) update_case(self.domain, case.case_id, case_properties={'reset_property': 'b'}) instances = get_case_alert_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 1) self.assertEqual(instances[0].case_id, case.case_id) self.assertEqual(instances[0].rule_id, rule.pk) self.assertEqual(instances[0].alert_schedule_id, schedule.schedule_id) self.assertEqual(instances[0].domain, self.domain) self.assertEqual(instances[0].recipient_type, 'CommCareUser') self.assertEqual(instances[0].recipient_id, self.user.get_id) self.assertEqual(instances[0].current_event_num, 0) self.assertEqual(instances[0].schedule_iteration_num, 1) self.assertEqual(instances[0].next_event_due, datetime(2017, 6, 1, 7, 0)) self.assertEqual(instances[0].last_reset_case_property_value, 'b') self.assertTrue(instances[0].active)