public static void retryWithBackoff(
      final int maxRetries,
      final int initialWaitMs,
      final int maxWaitMs,
      final Runnable runnable,
      final Class<?>... passThroughExceptions) {
    retryWithBackoff(
        maxRetries,
        initialWaitMs,
        maxWaitMs,
        runnable,
        () -> false,
        Arrays.stream(passThroughExceptions)
            .map(c -> (Predicate<Exception>) c::isInstance)
            .collect(Collectors.toList())
    );
  }
@Test
  public void shouldBackoffOnFailure() {
    doThrow(new RuntimeException("error")).when(runnable).run();
    try {
      RetryUtil.retryWithBackoff(3, 1, 100, runnable, sleep, () -> false, Collections.emptyList());
      fail("retry should have thrown");
    } catch (final RuntimeException e) {
    }
    verify(runnable, times(4)).run();
    final InOrder inOrder = Mockito.inOrder(sleep);
    inOrder.verify(sleep).accept((long) 1);
    inOrder.verify(sleep).accept((long) 2);
    inOrder.verify(sleep).accept((long) 4);
    inOrder.verifyNoMoreInteractions();
  }