@Test
public void testFindConflictingEvents() throws Exception {

  final long currentTime = System.currentTimeMillis();
  final MediaPackage mediaPackageA = generateEvent(Opt.<String> none());
  final MediaPackage mediaPackageB = generateEvent(Opt.<String> none());
  final MediaPackage mediaPackageC = generateEvent(Opt.<String> none());
  final MediaPackage mediaPackageD = generateEvent(Opt.<String> none());
  //
  schedSvc.addEvent(new Date(currentTime + seconds(10)), new Date(currentTime + hours(1) + seconds(10)), "Device A",
          Collections.<String> emptySet(), mediaPackageA, wfProperties, Collections.<String, String> emptyMap(),
          Opt.<String> none());
  schedSvc.addEvent(new Date(currentTime + hours(24)), new Date(currentTime + hours(25)), "Device A",
          Collections.<String> emptySet(), mediaPackageB, wfProperties, Collections.<String, String> emptyMap(),
          Opt.<String> none());
  schedSvc.addEvent(new Date(currentTime - hours(1)), new Date(currentTime - minutes(10)), "Device C",
          Collections.<String> emptySet(), mediaPackageC, wfProperties, Collections.<String, String> emptyMap(),
          Opt.<String> none());
  schedSvc.addEvent(new Date(currentTime + seconds(10)), new Date(currentTime + hours(1) + seconds(10)), "Device D",
          Collections.<String> emptySet(), mediaPackageD, wfProperties, Collections.<String, String> emptyMap(),
          Opt.<String> none());
  {
    List<MediaPackage> allEvents = schedSvc.search(Opt.<String> none(), Opt.<Date> none(), Opt.<Date> none(),
            Opt.<Date> none(), Opt.<Date> none());
    assertEquals(4, allEvents.size());
  }
  final Date start = new Date(currentTime);
  final Date end = new Date(currentTime + hours(2));
  {
    List<MediaPackage> events = schedSvc.search(Opt.some("Some Other Device"), Opt.some(start), Opt.<Date> none(),
            Opt.<Date> none(), Opt.some(end));
    assertEquals(0, events.size());
  }
  {
    List<MediaPackage> events = schedSvc.search(Opt.some("Device A"), Opt.some(start), Opt.<Date> none(),
            Opt.<Date> none(), Opt.some(end));
    assertEquals(1, events.size());
  }
  {
    ZonedDateTime startZdt = ZonedDateTime.ofInstant(start.toInstant(), ZoneOffset.UTC);
    List<MediaPackage> events = schedSvc.findConflictingEvents("Device A",
            new RRule("FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;BYHOUR=" + startZdt.getHour() + ";BYMINUTE=" + startZdt.getMinute()), start, new Date(start.getTime() + hours(48)),
            new Long(seconds(36)), TimeZone.getTimeZone("America/Chicago"));
    assertEquals(2, events.size());
  }
  {
    // No events are contained in the RRule and date range: 2019-02-16T16:00:00Z to 2019-02-16T16:55:00Z, FREQ=WEEKLY;BYDAY=WE;BYHOUR=16;BYMINUTE=0
    List<MediaPackage> conflicts = schedSvc.findConflictingEvents("Device A",
            new RRule("FREQ=WEEKLY;BYDAY=WE;BYHOUR=16;BYMINUTE=0"), new Date(1550332800000L), new Date(1550336100000L), 1000, TimeZone.getTimeZone("Africa/Johannesburg"));
    assertEquals(0, conflicts.size());
  }
  {
    //Event A starts before event B, and ends during event B
    List<MediaPackage> conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(23) + minutes(30)), new Date(currentTime + hours(24) + minutes(30)));
    assertEquals(1, conflicts.size());
    //Event A starts during event B, and ends after event B
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(24) + minutes(30)), new Date(currentTime + hours(25) + minutes(30)));
    assertEquals(1, conflicts.size());
    //Event A starts at the same time as event B
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(24)), new Date(currentTime + hours(24) + minutes(30)));
    assertEquals(1, conflicts.size());
    //Event A ends at the same time as event B
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(24) + minutes(10)), new Date(currentTime + hours(25)));
    assertEquals(1, conflicts.size());
    //Event A is contained entirely within event B
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(24) + minutes(10)), new Date(currentTime + hours(24) + minutes(50)));
    assertEquals(1, conflicts.size());
    //Event A contains event B entirely
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(23)), new Date(currentTime + hours(26)));
    assertEquals(1, conflicts.size());
    //Event A ends with less than one minute before event B starts
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(23)), new Date(currentTime + hours(24) - seconds(1)));
    assertEquals(1, conflicts.size());
    //Event A begins than one minute after event B ends
    conflicts = schedSvc.findConflictingEvents("Device A", new Date(currentTime + hours(25) + seconds(1)), new Date(currentTime + hours(27)));
    assertEquals(1, conflicts.size());
  }
}