package org.ei.drishti.service.scheduling;
import org.ei.drishti.domain.Child;
import org.ei.drishti.repository.AllChildren;
import org.ei.drishti.service.ActionService;
import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.motechproject.scheduletracking.api.service.EnrollmentRecord;
import org.motechproject.scheduletracking.api.service.EnrollmentsQuery;
import org.motechproject.scheduletracking.api.service.ScheduleTrackingService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.Arrays.asList;
import static org.apache.commons.lang.StringUtils.join;
import static org.ei.drishti.common.AllConstants.ChildImmunizationFields.*;
import static org.ei.drishti.scheduler.DrishtiScheduleConstants.ChildScheduleConstants.*;
import static org.ei.drishti.common.util.EasyMap.mapOf;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
public class ChildSchedulesServiceTest {
@Mock
private ScheduleTrackingService scheduleTrackingService;
@Mock
private AllChildren allChildren;
private ChildSchedulesService childSchedulesService;
@Before
public void setUp() throws Exception {
initMocks(this);
}
@Test
public void shouldEnrollChildIntoSchedulesAndShouldUpdateEnrollmentsForGivenImmunizations() {
new TestForChildEnrollmentAndUpdate()
.whenEnrolledWithImmunizationsGiven("bcg", "opv_0", "opv_1")
.shouldEnrollWithEnrollmentDateAsDateOfBirth(CHILD_SCHEDULE_BCG, CHILD_SCHEDULE_MEASLES, CHILD_SCHEDULE_OPV_0_AND_1)
.shouldFulfillWithFulfillmentDateAsDateOfBirth(CHILD_SCHEDULE_BCG, 1)
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("bcg")
.shouldFulfillWithFulfillmentDateAsDateOfBirth(CHILD_SCHEDULE_OPV_0_AND_1, 2)
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("opv_0")
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("opv_1")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldEnrollChildIntoSchedulesButShouldNotUpdateEnrollmentsIfImmunizationsAreNotProvided() {
new TestForChildEnrollmentAndUpdate()
.whenEnrolledWithImmunizationsGiven("")
.shouldEnrollWithEnrollmentDateAsDateOfBirth(CHILD_SCHEDULE_BCG, CHILD_SCHEDULE_MEASLES, CHILD_SCHEDULE_OPV_0_AND_1)
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldEnrollChildIntoDependentModulesIfRequiredAndShouldUpdateEnrollments() {
new TestForChildEnrollmentAndUpdate()
.whenEnrolledWithImmunizationsGiven("bcg", "opv_0", "opv_1", "measles")
.shouldEnrollWithEnrollmentDateAsDateOfBirth(CHILD_SCHEDULE_BCG, CHILD_SCHEDULE_MEASLES, CHILD_SCHEDULE_OPV_0_AND_1)
.shouldEnrollWithEnrollmentDateAsDateOfBirth(CHILD_SCHEDULE_MEASLES_BOOSTER)
.shouldFulfillWithFulfillmentDateAsDateOfBirth(CHILD_SCHEDULE_BCG, 1)
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("bcg")
.shouldFulfillWithFulfillmentDateAsDateOfBirth(CHILD_SCHEDULE_OPV_0_AND_1, 2)
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("opv_0")
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("opv_1")
.shouldFulfillWithFulfillmentDateAsDateOfBirth(CHILD_SCHEDULE_MEASLES, 1)
.shouldCloseAlertWithFulfillmentDateAsDateOfBirth("measles")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldEnrollDependentSchedulesEvenIfDependeeIsNotPresentButImmunizationIsGiven() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentWillHappenIn(CHILD_SCHEDULE_MEASLES_BOOSTER, MEASLES_BOOSTER_VALUE)
.givenEnrollmentWillHappenIn(CHILD_SCHEDULE_DPT_BOOSTER2, DPT_BOOSTER_2_VALUE)
.whenProvidedWithImmunizations("bcg opv_0 measles dptbooster_1 opvbooster")
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_MEASLES_BOOSTER)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_DPT_BOOSTER2)
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldNotEnrollDependentScheduleIfAlreadyEnrolled() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_MEASLES_BOOSTER, MEASLES_BOOSTER_VALUE)
.whenProvidedWithImmunizations("measles")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldNotEnrollDependentSchedulesIfImmunizationForThemIsAlreadyGiven() {
new TestForChildEnrollmentAndUpdate()
.givenChildIsAlreadyProvidedWithImmunizations("opv_2")
.whenProvidedWithImmunizations("opv_1")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldNotUpdateEnrollmentForAScheduleWhenNotEnrolledInSchedule() {
new TestForChildEnrollmentAndUpdate()
.whenProvidedWithImmunizations("bcg opv_0 opv_1 opv_2 opvbooster")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldUpdateEnrollmentForBCGOnlyWhenBCGHasBeenProvided() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_BCG, BCG_VALUE)
.whenProvidedWithImmunizations("bcg")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_BCG, 1)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_BCG, BCG_VALUE)
.whenProvidedWithImmunizations("SOME OTHER IMM")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldUpdateEnrollmentsForOPV() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_0_AND_1, "opv_0")
.whenProvidedWithImmunizations("opv_0")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_0_AND_1, 1)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_0_AND_1, "opv_0", "opv_1")
.whenProvidedWithImmunizations("opv_0 opv_1")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_0_AND_1, 2)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_2)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_2, "opv_2")
.whenProvidedWithImmunizations("opv_2")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_2, 1)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_3)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_3, "opv_3")
.whenProvidedWithImmunizations("opv_3")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_3, 1)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_BOOSTER)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_BOOSTER, "opvbooster")
.whenProvidedWithImmunizations("opvbooster")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_BOOSTER, 1)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_BOOSTER, "opvbooster")
.whenProvidedWithImmunizations("SOME OTHER IMMUNIZATION")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldUpdateEnrollmentForMeasles() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_MEASLES, MEASLES_VALUE)
.whenProvidedWithImmunizations("measles")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_MEASLES, 1)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_MEASLES_BOOSTER)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_MEASLES, MEASLES_VALUE)
.whenProvidedWithImmunizations("SOME OTHER IMMUNIZATION")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldUpdateEnrollmentForDPTBoosters() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_DPT_BOOSTER1, "dptbooster_1")
.whenProvidedWithImmunizations("dptbooster_1")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_DPT_BOOSTER1, 1)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_DPT_BOOSTER2)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_DPT_BOOSTER2, "dptbooster_2")
.whenProvidedWithImmunizations("dptbooster_2")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_DPT_BOOSTER2, 1)
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldUpdateEnrollmentForPentavalent() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_PENTAVALENT_1, "pentavalent_1")
.whenProvidedWithImmunizations("pentavalent_1")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_PENTAVALENT_1, 1)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_PENTAVALENT_2)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_PENTAVALENT_2, "pentavalent_2")
.whenProvidedWithImmunizations("pentavalent_2")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_PENTAVALENT_2, 1)
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_PENTAVALENT_3)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_PENTAVALENT_3, "pentavalent_3")
.whenProvidedWithImmunizations("pentavalent_3")
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_PENTAVALENT_3, 1)
.shouldNotEnrollAndFulfillAnythingElse();
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_PENTAVALENT_3, "pentavalent_3")
.whenProvidedWithImmunizations("SOME OTHER IMMUNIZATION")
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldUpdateEnrollmentsWhenMultipleDifferentKindsOfEnrollmentsArePresent() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_BCG, BCG_VALUE)
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_0_AND_1, OPV_1_VALUE)
.givenEnrollmentIn(CHILD_SCHEDULE_MEASLES, "measles")
.whenProvidedWithImmunizations("measles hepb_0 measlesbooster opv_1")
.shouldEnrollWithEnrollmentDateAsImmunizationDate(CHILD_SCHEDULE_MEASLES_BOOSTER)
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_OPV_0_AND_1, 1)
.shouldFulfillWithFulfillmentDateAsImmunizationDate(CHILD_SCHEDULE_MEASLES, 1)
.shouldNotEnrollAndFulfillAnythingElse();
}
@Test
public void shouldCloseAllOpenSchedulesWhenAChildIsUnEnrolled() {
new TestForChildEnrollmentAndUpdate()
.givenEnrollmentIn(CHILD_SCHEDULE_BCG, BCG_VALUE)
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_0_AND_1, OPV_1_VALUE)
.givenEnrollmentIn(CHILD_SCHEDULE_MEASLES, MEASLES_VALUE)
.whenUnenrolled()
.shouldUnEnrollFrom(CHILD_SCHEDULE_BCG, CHILD_SCHEDULE_OPV_0_AND_1, CHILD_SCHEDULE_MEASLES);
}
private class TestForChildEnrollmentAndUpdate {
private final String caseId = "Case X";
private final String anmId = "anm id 1";
private final String dateOfBirth = "2012-01-01";
private final String immunizationsDate = "2012-05-04";
private final ScheduleTrackingService scheduleTrackingService;
private final ScheduleService scheduleService;
private final ActionService actionService;
private List<EnrollmentRecord> allEnrollments;
public TestForChildEnrollmentAndUpdate() {
scheduleTrackingService = mock(ScheduleTrackingService.class);
scheduleService = mock(ScheduleService.class);
actionService = mock(ActionService.class);
childSchedulesService = new ChildSchedulesService(scheduleTrackingService, allChildren, scheduleService, actionService);
allEnrollments = new ArrayList<>();
}
public TestForChildEnrollmentAndUpdate givenEnrollmentIn(String schedule, String... milestoneNames) {
ArrayList<EnrollmentRecord> records = new ArrayList<>();
for (String milestoneName : milestoneNames) {
records.add(new EnrollmentRecord(caseId, schedule, milestoneName, null, null, null, null, null, null, null));
}
if (records.size() > 1) {
when(scheduleTrackingService.getEnrollment(caseId, schedule)).thenReturn(records.get(0), records.subList(1, records.size()).toArray(new EnrollmentRecord[0]));
} else {
when(scheduleTrackingService.getEnrollment(caseId, schedule)).thenReturn(records.get(0));
}
allEnrollments.addAll(records);
return this;
}
public TestForChildEnrollmentAndUpdate givenEnrollmentWillHappenIn(String schedule, String... milestoneNames) {
ArrayList<EnrollmentRecord> records = new ArrayList<>();
for (String milestoneName : milestoneNames) {
records.add(new EnrollmentRecord(caseId, schedule, milestoneName, null, null, null, null, null, null, null));
}
when(scheduleTrackingService.getEnrollment(caseId, schedule)).thenReturn(null, records.toArray(new EnrollmentRecord[0]));
allEnrollments.addAll(records);
return this;
}
public TestForChildEnrollmentAndUpdate whenUnenrolled() {
when(scheduleTrackingService.search(any(EnrollmentsQuery.class))).thenReturn(allEnrollments);
childSchedulesService.unenrollChild(caseId);
return this;
}
public TestForChildEnrollmentAndUpdate whenProvidedWithImmunizations(String providedImmunizations) {
return whenProvidedWithImmunizations(providedImmunizations, "");
}
public TestForChildEnrollmentAndUpdate whenProvidedWithImmunizations(String providedImmunizations, String previousImmunizations) {
Child child = mock(Child.class);
when(allChildren.findByCaseId(caseId)).thenReturn(child);
when(child.caseId()).thenReturn(caseId);
when(child.immunizationsGiven()).thenReturn(asList(providedImmunizations.split(" ")));
when(child.immunizationDate()).thenReturn(immunizationsDate);
childSchedulesService.updateEnrollments(caseId, Arrays.asList(previousImmunizations.split(" ")));
return this;
}
public TestForChildEnrollmentAndUpdate whenEnrolledWithImmunizationsGiven(String... immunizationsGiven) {
setExpectationsForNonDependentSchedules();
childSchedulesService.enrollChild(
new Child(caseId, null, join(asList(immunizationsGiven), " "), "4", null)
.withDateOfBirth(dateOfBirth)
.withDetails(mapOf("immunizationDate", immunizationsDate))
.withAnm(anmId));
return this;
}
private void setExpectationsForNonDependentSchedules() {
this.givenEnrollmentIn(CHILD_SCHEDULE_BCG, BCG_VALUE)
.givenEnrollmentIn(CHILD_SCHEDULE_MEASLES, MEASLES_VALUE)
.givenEnrollmentIn(CHILD_SCHEDULE_OPV_0_AND_1, OPV_0_VALUE, OPV_1_VALUE, OPV_2_VALUE, OPV_3_VALUE);
}
public TestForChildEnrollmentAndUpdate shouldEnrollWithEnrollmentDateAsDateOfBirth(String... expectedEnrolledSchedules) {
shouldEnroll(expectedEnrolledSchedules, dateOfBirth);
return this;
}
public TestForChildEnrollmentAndUpdate shouldEnrollWithEnrollmentDateAsImmunizationDate(String... expectedEnrolledSchedules) {
shouldEnroll(expectedEnrolledSchedules, immunizationsDate);
return this;
}
private void shouldEnroll(String[] expectedEnrolledSchedules, String enrollmentDate) {
for (String expectedEnrolledSchedule : expectedEnrolledSchedules) {
verify(scheduleService).enroll(caseId, expectedEnrolledSchedule, enrollmentDate);
}
}
public TestForChildEnrollmentAndUpdate shouldFulfillWithFulfillmentDateAsDateOfBirth(String expectedFulfillment, int numberOfTimes) {
shouldFulfill(expectedFulfillment, numberOfTimes, dateOfBirth);
return this;
}
public TestForChildEnrollmentAndUpdate shouldCloseAlertWithFulfillmentDateAsDateOfBirth(String expectedFulfillment) {
shouldCloseAlert(expectedFulfillment, dateOfBirth);
return this;
}
public TestForChildEnrollmentAndUpdate shouldCloseAlertWithFulfillmentDateAsImmunizationsDate(String expectedFulfillment) {
shouldCloseAlert(expectedFulfillment, immunizationsDate);
return this;
}
public TestForChildEnrollmentAndUpdate shouldFulfillWithFulfillmentDateAsImmunizationDate(String expectedFulfillment, int numberOfTimes) {
shouldFulfill(expectedFulfillment, numberOfTimes, immunizationsDate);
return this;
}
private void shouldFulfill(String expectedFulfillment, int numberOfTimes, String dateOfFulfillment) {
verify(scheduleTrackingService, times(numberOfTimes)).fulfillCurrentMilestone(caseId, expectedFulfillment, LocalDate.parse(dateOfFulfillment));
}
private void shouldCloseAlert(String expectedFulfillment, String dateOfFulfillment) {
verify(actionService).markAlertAsClosed(caseId, anmId, expectedFulfillment, dateOfFulfillment);
}
public TestForChildEnrollmentAndUpdate shouldNotEnrollAndFulfillAnythingElse() {
verify(scheduleTrackingService, atLeastOnce()).getEnrollment(eq(caseId), any(String.class));
verifyNoMoreInteractions(scheduleTrackingService);
return this;
}
public TestForChildEnrollmentAndUpdate shouldUnEnrollFrom(String... schedules) {
verify(scheduleTrackingService).search(any(EnrollmentsQuery.class));
for (String schedule : schedules) {
verify(scheduleTrackingService).unenroll(caseId, asList(schedule));
}
verifyNoMoreInteractions(scheduleTrackingService);
return this;
}
public TestForChildEnrollmentAndUpdate givenChildIsAlreadyProvidedWithImmunizations(String immunizationsAlreadyProvided) {
Child child = mock(Child.class);
when(allChildren.findByCaseId(caseId)).thenReturn(child);
when(child.caseId()).thenReturn(caseId);
when(child.immunizationsGiven()).thenReturn(asList(immunizationsAlreadyProvided.split(" ")));
when(child.immunizationDate()).thenReturn("2012-01-01");
return this;
}
}
}