### Question:
RetryWithExponentialBackoff { public <T> Optional<T> retry( final Supplier<T> supplier, final int maxAttemptCount, final long maxAttemptIntervalIncrease, final BiConsumer<Exception, Integer> reportFailOnce ) { for (int attemptCount = 0; attemptCount < maxAttemptCount; attemptCount++) { if (attemptCount > 0) { final long sleepTimeMillis = (1L << Math.min(attemptCount - 1, maxAttemptIntervalIncrease)) * 1000; sleep(sleepTimeMillis); } try { final T value = supplier.get(); if (value == null) { throw new IllegalStateException("Supplier supplied null"); } return Optional.of(value); } catch (final Exception e) { reportFailOnce.accept(e, attemptCount + 1); } } return Optional.empty(); }  Optional<T> retry(
            final Supplier<T> supplier,
            final int maxAttemptCount,
            final long maxAttemptIntervalIncrease,
            final BiConsumer<Exception, Integer> reportFailOnce
    ); void sleep(final long sleepTimeMillis);  }### Answer:
@Test public void testNoRetry() { final Optional result = retryWithExponentialBackoff.retry( SUPPLIER, MAX_ATTEMPT_COUNT, MAX_ATTEMPT_INTERVAL_INCREASE, reportFailOnce ); assertEquals(Optional.of(SUPPLIER_RESULT), result); verify(reportFailOnce, never()).accept(any(Exception.class), anyInt()); }
@Test public void testRetry() { when(supplier.get()) .thenThrow(new RuntimeException("something went wrong")) .thenReturn(null) .thenReturn(SUPPLIER_RESULT); final Optional result = retryWithExponentialBackoff.retry( supplier, MAX_ATTEMPT_COUNT, MAX_ATTEMPT_INTERVAL_INCREASE, reportFailOnce ); assertEquals(Optional.of(SUPPLIER_RESULT), result); verify(supplier, times(3)).get(); verify(reportFailOnce, times(2)).accept(any(Exception.class), anyInt()); verify(sleep).apply(1000L); verify(sleep).apply(2000L); }