### Question:
RetryStrategies { public static BiIntFunction<Throwable, Completable> retryWithExponentialBackoffAndJitter( final int maxRetries, final Predicate<Throwable> causeFilter, final Duration initialDelay, final Executor timerExecutor) { checkMaxRetries(maxRetries); requireNonNull(timerExecutor); requireNonNull(causeFilter); final long initialDelayNanos = initialDelay.toNanos(); return (retryCount, cause) -> { if (retryCount > maxRetries || !causeFilter.test(cause)) { return failed(cause); } return timerExecutor.timer(ThreadLocalRandom.current().nextLong(0, initialDelayNanos << (retryCount - 1)), NANOSECONDS); }; } private  RetryStrategies(); static BiIntFunction<Throwable, Completable> retryWithConstantBackoff(final int maxRetries,
                                                                                 final Predicate<Throwable> causeFilter,
                                                                                 final Duration delay,
                                                                                 final Executor timerExecutor); static BiIntFunction<Throwable, Completable> retryWithConstantBackoffAndJitter(
            final int maxRetries,
            final Predicate<Throwable> causeFilter,
            final Duration delay,
            final Executor timerExecutor); static BiIntFunction<Throwable, Completable> retryWithExponentialBackoff(
            final int maxRetries,
            final Predicate<Throwable> causeFilter,
            final Duration initialDelay,
            final Executor timerExecutor); static BiIntFunction<Throwable, Completable> retryWithExponentialBackoffAndJitter(
            final int maxRetries,
            final Predicate<Throwable> causeFilter,
            final Duration initialDelay,
            final Executor timerExecutor);  }### Answer:
@Test public void testExpBackoffWithJitter() throws Exception { Duration initialDelay = ofSeconds(1); RetryStrategy strategy = new RetryStrategy(retryWithExponentialBackoffAndJitter(2, cause -> true, initialDelay, timerExecutor)); LegacyMockedCompletableListenerRule signalListener = strategy.invokeAndListen(DELIBERATE_EXCEPTION); verifyDelayWithJitter(initialDelay.toNanos(), 1); timers.take().verifyListenCalled().onComplete(); signalListener.verifyCompletion(); verifyNoMoreInteractions(timerExecutor); signalListener = strategy.invokeAndListen(DELIBERATE_EXCEPTION); long nextDelay = initialDelay.toNanos() << 1; verifyDelayWithJitter(nextDelay, 2); timers.take().verifyListenCalled().onComplete(); signalListener.verifyCompletion(); verifyNoMoreInteractions(timerExecutor); }
@Test public void testExpBackoffWithJitterMaxRetries() throws Exception { Duration backoff = ofSeconds(1); testMaxRetries(retryWithExponentialBackoffAndJitter(1, cause -> true, backoff, timerExecutor), () -> verifyDelayWithJitter(backoff.toNanos(), 1)); }
@Test public void testExpBackoffWithJitterCauseFilter() { testCauseFilter(retryWithExponentialBackoffAndJitter(1, cause -> cause instanceof IllegalStateException, ofSeconds(1), timerExecutor)); }