@Test
  public void shouldScheduleSecondMilestoneAlertsUsingLastFulfilTimeAsReferenceWhichIsAfterNow()
      throws IOException, URISyntaxException, SchedulerException {
    addSchedule("/schedulingIT/schedule.json");

    try {
      fakeNow(newDateTime(2050, 5, 18, 10, 0, 0));
      String enrollmentId =
          scheduleTrackingService.enroll(
              new EnrollmentRequest()
                  .setExternalId("abcde")
                  .setScheduleName("schedule")
                  .setPreferredAlertTime(null)
                  .setReferenceDate(newDate(2050, 5, 10))
                  .setReferenceTime(new Time(9, 0))
                  .setEnrollmentDate(newDate(2050, 5, 10))
                  .setEnrollmentTime(new Time(9, 0))
                  .setStartingMilestoneName("milestone1")
                  .setMetadata(null));
      scheduleTrackingService.fulfillCurrentMilestone(
          "abcde", "schedule", newDate(2050, 5, 17), new Time(11, 0));

      List<DateTime> fireTimes =
          getFireTimes(
              format(
                  "org.motechproject.scheduletracking.milestone.alert-%s.1-repeat", enrollmentId));
      assertEquals(
          asList(newDateTime(2050, 5, 18, 11, 0, 0), newDateTime(2050, 5, 19, 11, 0, 0)),
          fireTimes);
    } finally {
      stopFakingTime();
    }
  }
  @Test
  public void shouldNotScheduleAlertsInThePastForDelayedEnrollment()
      throws SchedulerException, URISyntaxException, IOException {
    addSchedule("/schedulingIT/schedule.json");

    try {
      fakeNow(newDateTime(2050, 5, 17, 9, 0, 0));

      String enrollmentId =
          scheduleTrackingService.enroll(
              new EnrollmentRequest()
                  .setExternalId("abcde")
                  .setScheduleName("schedule")
                  .setPreferredAlertTime(null)
                  .setReferenceDate(newDate(2050, 5, 10))
                  .setReferenceTime(new Time(10, 0))
                  .setEnrollmentDate(newDate(2050, 5, 17))
                  .setEnrollmentTime(new Time(0, 0))
                  .setStartingMilestoneName("milestone1")
                  .setMetadata(null));

      List<DateTime> fireTimes =
          getFireTimes(
              format(
                  "org.motechproject.scheduletracking.milestone.alert-%s.0-repeat", enrollmentId));
      assertEquals(
          asList(
              newDateTime(2050, 5, 17, 10, 0, 0),
              newDateTime(2050, 5, 18, 10, 0, 0),
              newDateTime(2050, 5, 19, 10, 0, 0)),
          fireTimes);
    } finally {
      stopFakingTime();
    }
  }
  @Test
  public void shouldScheduleFloatingAlertsAtReferenceTime()
      throws SchedulerException, URISyntaxException, IOException {
    addSchedule("schedulingIT", "schedule_with_floating_alerts.json");

    Long enrollmentId =
        scheduleTrackingService.enroll(
            new EnrollmentRequest()
                .setExternalId("abcde")
                .setScheduleName("schedule_with_floating_alerts")
                .setPreferredAlertTime(null)
                .setReferenceDate(newDate(2050, 5, 10))
                .setReferenceTime(new Time(8, 20))
                .setEnrollmentDate(newDate(2050, 5, 10))
                .setEnrollmentTime(new Time(8, 20))
                .setStartingMilestoneName("milestone1")
                .setMetadata(null));

    List<DateTime> fireTimes =
        getFireTimes(
            format("org.motechproject.scheduletracking.milestone.alert-%s.0-repeat", enrollmentId));
    assertEquals(
        asList(
            newDateTime(2050, 5, 17, 8, 20, 0),
            newDateTime(2050, 5, 18, 8, 20, 0),
            newDateTime(2050, 5, 19, 8, 20, 0),
            newDateTime(2050, 5, 20, 8, 20, 0)),
        fireTimes);
  }
  @Test
  public void shouldFloatTheAlertsForDelayedEnrollmentInTheTimeLeftTriggeringThemAtReferenceTime()
      throws SchedulerException, URISyntaxException, IOException {
    addSchedule("schedulingIT", "schedule_with_floating_alerts.json");

    try {
      AlertListener alertListener = new AlertListener();
      eventListenerRegistry.registerListener(alertListener, EventSubjects.MILESTONE_ALERT);
      TestScheduleUtil.fakeNow(newDateTime(2050, 5, 22, 10, 0, 0));
      Long enrollmentId =
          scheduleTrackingService.enroll(
              new EnrollmentRequest()
                  .setExternalId("abcde")
                  .setScheduleName("schedule_with_floating_alerts")
                  .setPreferredAlertTime(null)
                  .setReferenceDate(newDate(2050, 5, 10))
                  .setReferenceTime(new Time(9, 0))
                  .setEnrollmentDate(newDate(2050, 5, 19))
                  .setEnrollmentTime(new Time(9, 0))
                  .setStartingMilestoneName("milestone1")
                  .setMetadata(null));

      assertEquals(newDateTime(2050, 5, 22, 10, 0, 0), alertListener.getTriggerTime());

      List<DateTime> fireTimes =
          getFireTimes(
              format(
                  "org.motechproject.scheduletracking.milestone.alert-%s.0-repeat", enrollmentId));
      assertEquals(singletonList(newDateTime(2050, 5, 23, 9, 0, 0)), fireTimes);
    } finally {
      TestScheduleUtil.stopFakingTime();
      eventListenerRegistry.clearListenersForBean("alertsTestListener");
    }
  }
  @Test
  public void
      shouldFloatTheAlertsForDelayedEnrollmentTriggeringAlertsAtReferenceTimeWhichIsAfterNow()
          throws SchedulerException, URISyntaxException, IOException {
    addSchedule("schedulingIT", "schedule_with_floating_alerts.json");

    try {
      TestScheduleUtil.fakeNow(newDateTime(2050, 5, 19, 8, 0, 0));
      Long enrollmentId =
          scheduleTrackingService.enroll(
              new EnrollmentRequest()
                  .setExternalId("abcde")
                  .setScheduleName("schedule_with_floating_alerts")
                  .setPreferredAlertTime(null)
                  .setReferenceDate(newDate(2050, 5, 10))
                  .setReferenceTime(new Time(9, 0))
                  .setEnrollmentDate(newDate(2050, 5, 18))
                  .setEnrollmentTime(new Time(9, 0))
                  .setStartingMilestoneName("milestone1")
                  .setMetadata(null));

      List<DateTime> fireTimes =
          getFireTimes(
              format(
                  "org.motechproject.scheduletracking.milestone.alert-%s.0-repeat", enrollmentId));
      assertEquals(
          asList(
              newDateTime(2050, 5, 19, 9, 0, 0),
              newDateTime(2050, 5, 20, 9, 0, 0),
              newDateTime(2050, 5, 21, 9, 0, 0),
              newDateTime(2050, 5, 22, 9, 0, 0)),
          fireTimes);
    } finally {
      TestScheduleUtil.stopFakingTime();
    }
  }
 private void addSchedule(String filename) throws URISyntaxException, IOException {
   File file = new File(getClass().getResource(filename).toURI());
   String scheduleJson = FileUtils.readFileToString(file);
   scheduleTrackingService.add(scheduleJson);
 }
 private void addSchedule(String path, String filename) throws URISyntaxException, IOException {
   String scheduleJson = TestScheduleUtil.getScheduleJsonFromFile(bundleContext, path, filename);
   scheduleTrackingService.add(scheduleJson);
 }