package com.nurkiewicz.asyncretry; import com.nurkiewicz.asyncretry.policy.AbortRetryException; import org.testng.annotations.Test; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; /** * @author Tomasz Nurkiewicz * @since 7/16/13, 10:51 PM */ public class AsyncRetryExecutorOneFailureTest extends AbstractBaseTestCase { @Test public void shouldNotRetryIfAbortThrown() throws Exception { //given final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock); given(serviceMock.sometimesFails()). willThrow(AbortRetryException.class); //when executor.getWithRetry(serviceMock::sometimesFails); //then verify(serviceMock).sometimesFails(); } @Test public void shouldRethrowAbortExceptionIfFirstIterationThrownIt() throws Exception { //given final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock); given(serviceMock.sometimesFails()). willThrow(AbortRetryException.class); //when final CompletableFuture<String> future = executor.getWithRetry(serviceMock::sometimesFails); //then assertThat(future.isCompletedExceptionally()).isTrue(); try { future.get(); failBecauseExceptionWasNotThrown(ExecutionException.class); } catch (ExecutionException e) { assertThat(e.getCause()).isInstanceOf(AbortRetryException.class); } } @Test public void shouldCompleteWithExceptionIfFirstIterationThrownIt() throws Exception { //given final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock).dontRetry(); given(serviceMock.sometimesFails()). willThrow(new IllegalStateException(DON_T_PANIC)); //when final CompletableFuture<String> future = executor.getWithRetry(serviceMock::sometimesFails); //then AtomicReference<Throwable> error = new AtomicReference<>(); future.whenComplete((res, t) -> { if (res == null) { error.set(t); //schedulerMock is synchronous anyway } }); assertThat(error.get()). isNotNull(). isInstanceOf(IllegalStateException.class). hasMessage(DON_T_PANIC); } @Test public void shouldRethrowLastThrownExceptionWhenAbortedInSubsequentIteration() throws Exception { //given final RetryExecutor executor = new AsyncRetryExecutor(schedulerMock); given(serviceMock.sometimesFails()). willThrow( new IllegalArgumentException("First"), new IllegalStateException("Second"), new AbortRetryException() ); //when final CompletableFuture<String> future = executor.getWithRetry(serviceMock::sometimesFails); //then assertThat(future.isCompletedExceptionally()).isTrue(); try { future.get(); failBecauseExceptionWasNotThrown(ExecutionException.class); } catch (ExecutionException e) { assertThat(e.getCause()).isInstanceOf(IllegalStateException.class); assertThat(e.getCause().getMessage()).isEqualTo("Second"); } } }