@Test
  public void shouldUnwrapUserFutureAndReturnIt() throws Exception {
    // given
    final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock);
    given(serviceMock.safeAsync()).willReturn(CompletableFuture.completedFuture("42"));

    // when
    final CompletableFuture<String> future =
        executor.getFutureWithRetry(ctx -> serviceMock.safeAsync());

    // then
    assertThat(future.get()).isEqualTo("42");
  }
 /** Construction of TPSControlWebServiceClient to initialize executor */
 public TPSControlWebServiceClient() {
   controlExecutor = newControlExecutor();
   controlExecutor.setControlUnit(TimeUnit.SECONDS);
   Executor executor = new RetryExecutor();
   ((RetryExecutor) executor).setExecutor(controlExecutor);
   this.setExecutor(executor);
 }
  @Test
  public void shouldSucceedAfterFewAsynchronousRetries() throws Exception {
    // given
    final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock);
    given(serviceMock.safeAsync())
        .willReturn(
            failedAsync(new SocketException("First")),
            failedAsync(new IOException("Second")),
            CompletableFuture.completedFuture("42"));

    // when
    final CompletableFuture<String> future =
        executor.getFutureWithRetry(ctx -> serviceMock.safeAsync());

    // then
    assertThat(future.get()).isEqualTo("42");
  }
  @Test
  public void shouldAbortWhenTargetFutureWantsToAbort() throws Exception {
    // given
    final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock);
    given(serviceMock.safeAsync()).willReturn(failedAsync(new AbortRetryException()));

    // when
    final CompletableFuture<String> future =
        executor.getFutureWithRetry(ctx -> serviceMock.safeAsync());

    // then
    assertThat(future.isCompletedExceptionally()).isTrue();

    try {
      future.get();
      failBecauseExceptionWasNotThrown(ExecutionException.class);
    } catch (ExecutionException e) {
      final Throwable cause = e.getCause();
      assertThat(cause).isInstanceOf(AbortRetryException.class);
    }
  }
  @Test
  public void shouldRethrowOriginalExceptionFromUserFutureCompletion() throws Exception {
    // given
    final RetryExecutor executor =
        new AsyncRetryExecutor(schedulerMock).abortOn(SocketException.class);
    given(serviceMock.safeAsync()).willReturn(failedAsync(new SocketException(DON_T_PANIC)));

    // when
    final CompletableFuture<String> future =
        executor.getFutureWithRetry(ctx -> serviceMock.safeAsync());

    // then
    assertThat(future.isCompletedExceptionally()).isTrue();

    try {
      future.get();
      failBecauseExceptionWasNotThrown(ExecutionException.class);
    } catch (ExecutionException e) {
      final Throwable cause = e.getCause();
      assertThat(cause).isInstanceOf(SocketException.class);
      assertThat(cause).hasMessage(DON_T_PANIC);
    }
  }
  @Test
  public void shouldScheduleTwoTimesWhenRetries() throws Exception {
    // given
    final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock);
    given(serviceMock.safeAsync())
        .willReturn(
            failedAsync(new SocketException("First")),
            failedAsync(new IOException("Second")),
            CompletableFuture.completedFuture("42"));

    // when
    final CompletableFuture<String> future =
        executor.getFutureWithRetry(ctx -> serviceMock.safeAsync());

    // then
    future.get();

    final InOrder order = inOrder(schedulerMock);
    order.verify(schedulerMock).schedule(notNullRunnable(), eq(0L), millis());
    order
        .verify(schedulerMock, times(2))
        .schedule(notNullRunnable(), eq(DEFAULT_PERIOD_MILLIS), millis());
  }
  @Test
  public void shouldRethrowExceptionThatWasThrownFromUserTaskBeforeReturningFuture()
      throws Exception {
    // given
    final RetryExecutor executor =
        new AsyncRetryExecutor(schedulerMock).abortOn(IllegalArgumentException.class);
    given(serviceMock.safeAsync()).willThrow(new IllegalArgumentException(DON_T_PANIC));

    // when
    final CompletableFuture<String> future =
        executor.getFutureWithRetry(ctx -> serviceMock.safeAsync());

    // then
    assertThat(future.isCompletedExceptionally()).isTrue();

    try {
      future.get();
      Assertions.failBecauseExceptionWasNotThrown(ExecutionException.class);
    } catch (ExecutionException e) {
      assertThat(e.getCause()).isInstanceOf(IllegalArgumentException.class);
      assertThat(e.getCause()).hasMessage(DON_T_PANIC);
    }
  }