/* * Copyright 2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package net.jodah.failsafe; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import java.net.ConnectException; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import net.jodah.failsafe.util.concurrent.Scheduler; @Test public class AsyncExecutionTest { ConnectException e = new ConnectException(); AsyncExecution exec; FailsafeFuture<Object> future; Callable<Object> callable; Scheduler scheduler; @BeforeMethod @SuppressWarnings("unchecked") void beforeMethod() { scheduler = mock(Scheduler.class); future = mock(FailsafeFuture.class); callable = mock(Callable.class); } public void testComplete() { // Given exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy())); // When exec.complete(); // Then assertEquals(exec.getExecutions(), 1); assertTrue(exec.isComplete()); assertNull(exec.getLastResult()); assertNull(exec.getLastFailure()); verify(future).complete(null, null, null, true); } public void testCompleteForResult() { // Given exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().retryWhen(null))); // When / Then assertFalse(exec.complete(null)); exec.before(); assertTrue(exec.complete(true)); // Then assertEquals(exec.getExecutions(), 2); assertTrue(exec.isComplete()); assertEquals(exec.getLastResult(), Boolean.TRUE); assertNull(exec.getLastFailure()); verify(future).complete(true, null, null, true); } public void testGetAttemptCount() { exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy())); exec.retryOn(e); exec.before(); exec.retryOn(e); assertEquals(exec.getExecutions(), 2); } public void testRetryForResult() { // Given retry for null exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().retryWhen(null))); // When / Then assertFalse(exec.complete(null)); exec.before(); assertTrue(exec.retryFor(null)); exec.before(); assertFalse(exec.retryFor(1)); // Then assertEquals(exec.getExecutions(), 3); assertTrue(exec.isComplete()); assertEquals(exec.getLastResult(), Integer.valueOf(1)); assertNull(exec.getLastFailure()); verifyScheduler(1); verify(future).complete(1, null, null, true); // Given 2 max retries exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().retryWhen(null).withMaxRetries(2))); // When / Then resetMocks(); assertFalse(exec.complete(null)); exec.before(); assertTrue(exec.retryFor(null)); exec.before(); assertFalse(exec.retryFor(null)); // Then assertEquals(exec.getExecutions(), 3); assertTrue(exec.isComplete()); assertNull(exec.getLastResult()); assertNull(exec.getLastFailure()); verifyScheduler(1); verify(future).complete(null, null, null, false); } public void testRetryForResultAndThrowable() { // Given retry for null exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().retryWhen(null))); // When / Then assertFalse(exec.complete(null)); exec.before(); assertTrue(exec.retryFor(null, null)); exec.before(); assertTrue(exec.retryFor(1, new IllegalArgumentException())); exec.before(); assertFalse(exec.retryFor(1, null)); // Then assertEquals(exec.getExecutions(), 4); assertTrue(exec.isComplete()); assertEquals(exec.getLastResult(), Integer.valueOf(1)); assertNull(exec.getLastFailure()); verifyScheduler(2); verify(future).complete(1, null, null, true); // Given 2 max retries exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().retryWhen(null).withMaxRetries(2))); // When / Then resetMocks(); assertFalse(exec.complete(null)); exec.before(); assertTrue(exec.retryFor(null, e)); exec.before(); assertFalse(exec.retryFor(null, e)); // Then assertEquals(exec.getExecutions(), 3); assertTrue(exec.isComplete()); assertNull(exec.getLastResult()); assertEquals(exec.getLastFailure(), e); verifyScheduler(1); verify(future).complete(null, e, null, false); } public void testRetryOn() { // Given retry on IllegalArgumentException exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().retryOn(IllegalArgumentException.class))); // When / Then assertTrue(exec.retryOn(new IllegalArgumentException())); exec.before(); assertFalse(exec.retryOn(e)); // Then assertEquals(exec.getExecutions(), 2); assertTrue(exec.isComplete()); assertNull(exec.getLastResult()); assertEquals(exec.getLastFailure(), e); verifyScheduler(1); verify(future).complete(null, e, null, false); // Given 2 max retries exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy().withMaxRetries(1))); // When / Then resetMocks(); assertTrue(exec.retryOn(e)); exec.before(); assertFalse(exec.retryOn(e)); // Then assertEquals(exec.getExecutions(), 2); assertTrue(exec.isComplete()); assertNull(exec.getLastResult()); assertEquals(exec.getLastFailure(), e); verifyScheduler(1); verify(future).complete(null, e, null, false); } @Test(expectedExceptions = IllegalStateException.class) public void shouldThrowOnRetryWhenAlreadyComplete() { exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy())); exec.complete(); exec.before(); exec.retryOn(e); } public void testCompleteOrRetry() { // Given retry on IllegalArgumentException exec = new AsyncExecution(callable, scheduler, future, configFor(new RetryPolicy())); // When / Then exec.completeOrRetry(null, e); assertFalse(exec.isComplete()); exec.before(); exec.completeOrRetry(null, null); // Then assertEquals(exec.getExecutions(), 2); assertTrue(exec.isComplete()); assertNull(exec.getLastResult()); assertNull(exec.getLastFailure()); verifyScheduler(1); verify(future).complete(null, null, null, true); } @SuppressWarnings("unchecked") private void resetMocks() { reset(scheduler); reset(future); reset(callable); } @SuppressWarnings({ "unchecked", "rawtypes" }) static <T> FailsafeConfig<T, FailsafeConfig<T, ?>> configFor(RetryPolicy retryPolicy) { return (FailsafeConfig<T, FailsafeConfig<T, ?>>) new FailsafeConfig().with(retryPolicy); } private void verifyScheduler(int executions) { verify(scheduler, times(executions)).schedule(any(Callable.class), any(Long.class), any(TimeUnit.class)); } }