@Test(timeout=60000)
public void testScheduler() throws Exception {

  final NoOpCheckable target1 = new NoOpCheckable();
  final NoOpCheckable target2 = new NoOpCheckable();
  final FakeTimer timer = new FakeTimer();
  ThrottledAsyncChecker<Boolean, Boolean> checker =
      new ThrottledAsyncChecker<>(timer, MIN_ERROR_CHECK_GAP, 0,
                                  getExecutorService());
  // check target1 and ensure we get back the expected result.
  assertTrue(checker.schedule(target1, true).isPresent());
  waitTestCheckableCheckCount(target1, 1L);
  // Check target1 again without advancing the timer. target1 should not
  // be checked again.
  assertFalse(checker.schedule(target1, true).isPresent());
  waitTestCheckableCheckCount(target1, 1L);
  // Schedule target2 scheduled without advancing the timer.
  // target2 should be checked as it has never been checked before.
  assertTrue(checker.schedule(target2, true).isPresent());
  waitTestCheckableCheckCount(target2, 1L);
  // Advance the timer but just short of the min gap.
  // Neither target1 nor target2 should be checked again.
  timer.advance(MIN_ERROR_CHECK_GAP - 1);
  assertFalse(checker.schedule(target1, true).isPresent());
  waitTestCheckableCheckCount(target1, 1L);
  assertFalse(checker.schedule(target2, true).isPresent());
  waitTestCheckableCheckCount(target2, 1L);
  // Advance the timer again.
  // Both targets should be checked now.
  timer.advance(MIN_ERROR_CHECK_GAP);
  assertTrue(checker.schedule(target1, true).isPresent());
  waitTestCheckableCheckCount(target1, 2L);
  assertTrue(checker.schedule(target2, true).isPresent());
  waitTestCheckableCheckCount(target2, 2L);
}