package org.ei.drishti.service.scheduling; import org.apache.commons.lang.builder.EqualsBuilder; import org.ei.drishti.service.ActionService; import org.ei.drishti.service.FastForwardScheduleTestBase; import org.joda.time.LocalDate; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.motechproject.model.Time; import org.motechproject.scheduletracking.api.service.EnrollmentRecord; import org.motechproject.scheduletracking.api.service.EnrollmentsQuery; import org.motechproject.scheduletracking.api.service.ScheduleTrackingService; import org.motechproject.testing.utils.BaseUnitTest; import java.util.List; import static java.util.Arrays.asList; import static org.ei.drishti.common.util.DateUtil.fakeIt; import static org.ei.drishti.common.util.DateUtil.today; import static org.ei.drishti.scheduler.DrishtiScheduleConstants.MotherScheduleConstants.*; import static org.joda.time.LocalDate.parse; import static org.mockito.Matchers.*; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; import static org.motechproject.scheduletracking.api.domain.EnrollmentStatus.ACTIVE; import static org.powermock.api.mockito.PowerMockito.*; public class ANCSchedulesServiceTest extends BaseUnitTest { @Mock private ScheduleTrackingService trackingService; @Mock private ActionService actionService; @Mock private ScheduleService scheduleService; private ANCSchedulesService ancSchedulesService; @Before public void setUp() throws Exception { initMocks(this); ancSchedulesService = new ANCSchedulesService(trackingService, actionService, scheduleService); } @Test public void shouldEnrollMotherIntoSchedules() { fakeIt(parse("2012-01-01")); LocalDate lmp = today().minusDays(3); ancSchedulesService.enrollMother("Case X", lmp); verify(scheduleService).enroll("Case X", SCHEDULE_ANC, "ANC 1", lmp.toString()); verifyNonANCScheduleEnrollments(lmp); verifyNoMoreInteractions(trackingService); } @Test public void shouldEnrollMotherIntoANC1WhenTheMotherIsEnrolledBefore14WeeksFromLMP() throws Exception { assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 1, 1), "ANC 1"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 4, 6), "ANC 1"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 4, 7), "ANC 1"); } @Test public void shouldEnrollMotherIntoANC2WhenTheMotherIsEnrolledBetween16And28WeeksFromLMP() throws Exception { assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 4, 8), "ANC 2"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 7, 13), "ANC 2"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 7, 14), "ANC 2"); } @Test public void shouldEnrollMotherIntoANC3WhenTheMotherIsEnrolledBetween28And34WeeksFromLMP() throws Exception { assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 7, 15), "ANC 3"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 8, 24), "ANC 3"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 8, 25), "ANC 3"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 9, 8), "ANC 3"); } @Test public void shouldEnrollMotherIntoANC3WhenTheMotherIsEnrolledAfter34WeeksFromLMP() throws Exception { assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 9, 9), "ANC 4"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 10, 6), "ANC 4"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2012, 10, 7), "ANC 4"); assertEnrollmentIntoMilestoneBasedOnDate(new LocalDate(2013, 10, 7), "ANC 4"); } @Test public void shouldNotEnrollMotherIntoANC1WhenLMPDateIsAfterTodayOrMoreThan40WeeksBeforeToday() throws Exception { assertNoEnrollmentIntoMilestone(new LocalDate(2011, 12, 31)); assertNoEnrollmentIntoMilestone(new LocalDate(2012, 10, 8)); } @Test public void shouldFulfillANCScheduleWhenTheExpectedANCVisitHappens() { fakeIt(parse("2012-01-01")); new FastForwardScheduleTestBase().forANCSchedule().whenExpecting("ANC 1").providedWithVisitNumber(1).willFulfillFor("ANC 1"); } @Test public void shouldNotFulfillANCMilestoneWhichHasAlreadyBeenFulfilled() { new FastForwardScheduleTestBase().forANCSchedule().whenExpecting("ANC 3").providedWithVisitNumber(1).willNotFulfillAnything(); } @Test public void shouldFulfillAllMilestonesBetweenTheCurrentOneAndTheOneCorrespondingToTheVisitNumber() { new FastForwardScheduleTestBase().forANCSchedule().whenExpecting("ANC 1").providedWithVisitNumber(3).willFulfillFor("ANC 1", "ANC 2", "ANC 3"); } @Test public void shouldFulfillTT1MilestoneWhenTT1IsExpectedDuringANCCare() { new FastForwardScheduleTestBase().forTT1Schedule().whenExpecting("TT 1").providedWithVisitNumber(1).willFulfillFor("TT 1"); } @Test public void shouldFulfillTT2MilestoneWhenTT2IsExpectedDuringANCCare() { new FastForwardScheduleTestBase().forTT2Schedule().whenExpecting("TT 2").providedWithVisitNumber(2).willFulfillFor("TT 2"); } @Test public void shouldFulfillIFA1MilestoneWhenIFA1IsExpectedAndIFATabletsGiven() { new FastForwardScheduleTestBase().forIFA1Schedule().providedWithNumberOfIFATablets("100").whenExpecting("IFA 1").willFulfillFor("IFA 1"); } @Test public void shouldFulfillIFA2MilestoneWhenIFA2IsExpectedAndIFATabletsGiven() { new FastForwardScheduleTestBase().forIFA2Schedule().providedWithNumberOfIFATablets("100").whenExpecting("IFA 2").willFulfillFor("IFA 2"); } @Test public void shouldFulfillIFA3MilestoneWhenIFA3IsExpectedAndIFATabletsGiven() { new FastForwardScheduleTestBase().forIFA3Schedule().providedWithNumberOfIFATablets("100").whenExpecting("IFA 3").willFulfillFor("IFA 3"); } @Test public void shouldDoNothingWhenIFATabletsNotGiven() { new FastForwardScheduleTestBase().forIFA1Schedule().providedWithNumberOfIFATablets("0").whenExpecting("IFA 1").willNotFulfillAnything(); } @Test public void shouldEnrollMotherInTT2ScheduleIfTT1IsProvided() throws Exception { fakeIt(parse("2012-01-01")); when(trackingService.getEnrollment("entity id 1", "TT 1")).thenReturn( new EnrollmentRecord("entity id 1", "TT 1", "TT 1", null, null, null, null, null, null, null)); ancSchedulesService.ttVisitHasHappened("entity id 1", "ANM 1", "tt1", "2012-01-01"); verify(trackingService).fulfillCurrentMilestone(eq("entity id 1"), eq("TT 1"), eq(today()), any(Time.class)); verify(actionService).markAlertAsClosed("entity id 1", "ANM 1", "TT 1", "2012-01-01"); verify(scheduleService).enroll("entity id 1", "TT 2", "2012-01-01"); } @Test public void shouldFullFillTT1AndTT2IfTTBoosterIsProvided() throws Exception { fakeIt(parse("2012-01-01")); when(trackingService.getEnrollment("entity id 1", "TT 1")).thenReturn( new EnrollmentRecord("entity id 1", "TT 1", "TT 1", null, null, null, null, null, null, null)); when(trackingService.getEnrollment("entity id 1", "TT 2")).thenReturn( new EnrollmentRecord("entity id 1", "TT 2", "TT 2", null, null, null, null, null, null, null)); ancSchedulesService.ttVisitHasHappened("entity id 1", "ANM 1", "ttbooster", "2012-01-01"); verify(actionService).markAlertAsInactive("ANM 1", "entity id 1", "TT 1"); verify(trackingService).unenroll("entity id 1", asList("TT 1")); verifyZeroInteractions(scheduleService); } @Test public void shouldNotEnrollMotherInTT2ScheduleIfSomeOtherThingIsProvided() throws Exception { ancSchedulesService.ttVisitHasHappened("entity id 1", "ANM 1", "some other", "2012-01-01"); verifyZeroInteractions(trackingService); } @Test public void shouldNotFulfillANCIfANCScheduleIsAlreadyOver() throws Exception { when(trackingService.getEnrollment("Entity X", SCHEDULE_ANC)).thenReturn(null); ancSchedulesService.ancVisitHasHappened("Entity X", "ANM 1", 2, "2012-01-23"); verify(trackingService).getEnrollment("Entity X", SCHEDULE_ANC); verifyNoMoreInteractions(trackingService); verifyZeroInteractions(actionService); } @Test public void shouldNotFulfillCurrentMilestoneForGivenExternalIdWhenVisitHasBeenMissed() { fakeIt(parse("2012-01-01")); when(trackingService.getEnrollment("Case X", "Schedule 1")) .thenReturn(null); ancSchedulesService.forceFulfillMilestone("Case X", "Schedule 1"); verify(trackingService).getEnrollment("Case X", "Schedule 1"); verifyNoMoreInteractions(trackingService); } @Test public void shouldFulfillCurrentMilestoneForGivenExternalIdWhenVisitHasNotBeenMissed() { fakeIt(parse("2012-01-01")); when(trackingService.getEnrollment("Case X", "Schedule 1")) .thenReturn(new EnrollmentRecord("Case X", "Lab Reminders", "Lab Reminders", null, null, null, null, null, null, null)); ancSchedulesService.forceFulfillMilestone("Case X", "Schedule 1"); verify(trackingService).fulfillCurrentMilestone(eq("Case X"), eq("Schedule 1"), eq(today()), any(Time.class)); } @Test public void shouldUnenrollAMotherFromAllOpenSchedulesAndRaiseDeleteAllAlertActionDuringClose() { EnrollmentRecord record1 = new EnrollmentRecord("Case X", "Schedule 1", null, null, null, null, null, null, null, null); EnrollmentRecord record2 = new EnrollmentRecord("Case X", "Schedule 2", null, null, null, null, null, null, null, null); List<EnrollmentRecord> records = asList(record1, record2); when(trackingService.search(queryFor("Case X"))).thenReturn(records); ancSchedulesService.unEnrollFromAllSchedules("Case X"); verify(trackingService).unenroll("Case X", asList("Schedule 1")); verify(trackingService).unenroll("Case X", asList("Schedule 2")); verify(actionService).markAllAlertsAsInactive("Case X"); } @Test public void shouldFulfillHbTest1WhenHbTestIsDone() { when(trackingService.getEnrollment("Case X", "Hb Test 1")) .thenReturn(new EnrollmentRecord("Case X", "Hb Test 1", "HB Test 1", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-01-01", null, parse("2012-09-01")); verify(trackingService).fulfillCurrentMilestone(eq("Case X"), eq("Hb Test 1"), eq(parse("2013-01-01")), any(Time.class)); } @Test public void shouldEnrollANCToHbFollowupTestWhenHbTestIsDoneAndSheIsAnaemic() { when(trackingService.getEnrollment("Case X", "Hb Test 1")) .thenReturn(new EnrollmentRecord("Case X", "Hb Test 1", "HB Test 1", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-01-01", "Anaemic", null); verify(scheduleService).enroll("Case X", "Hb Followup Test", "2013-01-01"); } @Test public void shouldEnrollANCToHbTest2WhenHbTestIsDoneAndSheIsNotAnaemic() { when(trackingService.getEnrollment("Case X", "Hb Test 1")) .thenReturn(new EnrollmentRecord("Case X", "Hb Test 1", "HB Test 1", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-01-01", null, parse("2012-09-01")); verify(scheduleService).enroll("Case X", "Hb Test 2", "2012-09-01"); } @Test public void shouldFulfillHbFollowupTestWhenHbTestIsDone() { when(trackingService.getEnrollment("Case X", "Hb Test 1")).thenReturn(null); when(trackingService.getEnrollment("Case X", "Hb Followup Test")) .thenReturn(new EnrollmentRecord("Case X", "Hb Followup Test", "Hb Followup Test", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-01-01", "Anaemic", parse("2012-09-01")); verify(trackingService).fulfillCurrentMilestone(eq("Case X"), eq("Hb Followup Test"), eq(parse("2013-01-01")), any(Time.class)); } @Test public void shouldFulfillHbTest2WhenHbTestIsDoneAndFollowupIsFulfilledAndDateIs28WeeksAfterLMP() { when(trackingService.getEnrollment("Case X", "Hb Test 1")).thenReturn(null); when(trackingService.getEnrollment("Case X", "Hb Followup Test")) .thenReturn(new EnrollmentRecord("Case X", "Hb Followup Test", "Hb Followup Test", null, null, null, null, null, null, null)); when(trackingService.getEnrollment("Case X", "Hb Test 2")) .thenReturn(new EnrollmentRecord("Case X", "Hb Test 2", "Hb Test 2", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-04-16", "Anaemic", parse("2012-09-01")); verify(trackingService).fulfillCurrentMilestone(eq("Case X"), eq("Hb Test 2"), eq(parse("2013-04-16")), any(Time.class)); } @Test public void shouldFulfillScheduleWhenDeliveryHasBeenPlanned() { when(trackingService.getEnrollment("Case X", "Delivery Plan")) .thenReturn(new EnrollmentRecord("Case X", "Delivery Plan", "Delivery Plan", null, null, null, null, null, null, null)); ancSchedulesService.deliveryHasBeenPlanned("Case X", "ANM id 1", "2013-01-01"); verify(trackingService).fulfillCurrentMilestone(eq("Case X"), eq("Delivery Plan"), eq(parse("2013-01-01")), any(Time.class)); } @Test public void shouldEnrollToHbTest2WhenHbTestIsDoneAndFollowupIsFulfilledAndDateIsNot28WeeksAfterLMP() { when(trackingService.getEnrollment("Case X", "Hb Test 1")).thenReturn(null); when(trackingService.getEnrollment("Case X", "Hb Followup Test")) .thenReturn(new EnrollmentRecord("Case X", "Hb Followup Test", "Hb Followup Test", null, null, null, null, null, null, null)); when(trackingService.getEnrollment("Case X", "Hb Test 2")) .thenReturn(new EnrollmentRecord("Case X", "Hb Test 2", "Hb Test 2", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-02-16", "Anaemic", parse("2012-09-01")); verify(trackingService, times(0)).fulfillCurrentMilestone(eq("Case X"), eq("Hb Test 2"), eq(parse("2013-04-16")), any(Time.class)); verify(scheduleService).enroll("Case X", "Hb Test 2", "2012-09-01"); } @Test public void shouldFulfillHbTest2WhenHbTestIsDoneAndItsTheActiveMilestone() { when(trackingService.getEnrollment("Case X", "Hb Test 1")).thenReturn(null); when(trackingService.getEnrollment("Case X", "Hb Followup Test")).thenReturn(null); when(trackingService.getEnrollment("Case X", "Hb Test 2")) .thenReturn(new EnrollmentRecord("Case X", "Hb Test 2", "Hb Test 2", null, null, null, null, null, null, null)); ancSchedulesService.hbTestDone("Case X", "ANM 1", "2013-04-16", "Anaemic", parse("2012-09-01")); verify(trackingService).fulfillCurrentMilestone(eq("Case X"), eq("Hb Test 2"), eq(parse("2013-04-16")), any(Time.class)); } private void assertEnrollmentIntoMilestoneBasedOnDate(LocalDate enrollmentDate, String expectedMilestone) throws Exception { assertEnrollmentIntoMilestoneBasedOnDate(enrollmentDate, expectedMilestone, 1); } private void assertNoEnrollmentIntoMilestone(LocalDate enrollmentDate) throws Exception { assertEnrollmentIntoMilestoneBasedOnDate(enrollmentDate, "", 0); } private void assertEnrollmentIntoMilestoneBasedOnDate(LocalDate enrollmentDate, String expectedMilestone, int wantedNumberOfInvocations) throws Exception { setUp(); LocalDate lmp = new LocalDate(2012, 1, 1); fakeIt(enrollmentDate); ancSchedulesService.enrollMother("Case X", lmp); verifyNonANCScheduleEnrollments(lmp); verify(scheduleService, times(wantedNumberOfInvocations)).enroll("Case X", SCHEDULE_ANC, expectedMilestone, lmp.toString()); } private EnrollmentsQuery queryFor(final String externalId) { return argThat(new ArgumentMatcher<EnrollmentsQuery>() { @Override public boolean matches(Object o) { EnrollmentsQuery expectedQuery = new EnrollmentsQuery().havingExternalId(externalId).havingState(ACTIVE); return EqualsBuilder.reflectionEquals(expectedQuery.getCriteria(), ((EnrollmentsQuery) o).getCriteria()); } }); } private void verifyNonANCScheduleEnrollments(LocalDate lmp) { verify(scheduleService).enroll("Case X", SCHEDULE_EDD, lmp.toString()); verify(scheduleService).enroll("Case X", SCHEDULE_LAB, lmp.toString()); verify(scheduleService).enroll("Case X", SCHEDULE_TT_1, lmp.toString()); verify(scheduleService).enroll("Case X", SCHEDULE_IFA_1, lmp.toString()); verify(scheduleService).enroll("Case X", SCHEDULE_HB_TEST_1, lmp.toString()); } }