diff --git a/driver-core/src/main/com/mongodb/internal/async/function/RetryState.java b/driver-core/src/main/com/mongodb/internal/async/function/RetryState.java
index 74504a1d9b..f14f4d2948 100644
--- a/driver-core/src/main/com/mongodb/internal/async/function/RetryState.java
+++ b/driver-core/src/main/com/mongodb/internal/async/function/RetryState.java
@@ -132,7 +132,7 @@ private RetryState(final int retries, final boolean retryUntilTimeoutThrowsExcep
* per attempt and only if all the following is true:
*
* - {@code onAttemptFailureOperator} completed normally;
- * - the most recent attempt is not the {@linkplain #isLastAttempt() last} one.
+ * - the most recent attempt is not known to be the {@linkplain #isLastAttempt(Throwable) last} one.
*
* The {@code retryPredicate} accepts this {@link RetryState} and the exception from the most recent attempt,
* and may mutate the exception. The {@linkplain RetryState} advances to represent the state of a new attempt
@@ -140,7 +140,7 @@ private RetryState(final int retries, final boolean retryUntilTimeoutThrowsExcep
* @throws RuntimeException Iff any of the following is true:
*
* - the {@code onAttemptFailureOperator} completed abruptly;
- * - the most recent attempt is the {@linkplain #isLastAttempt() last} one;
+ * - the most recent attempt is known to be the {@linkplain #isLastAttempt(Throwable) last} one;
* - the {@code retryPredicate} completed abruptly;
* - the {@code retryPredicate} is {@code false}.
*
@@ -187,24 +187,10 @@ private void doAdvanceOrThrow(final Throwable attemptException,
}
assertTrue(!isFirstAttempt() || previouslyChosenException == null);
Throwable newlyChosenException = callOnAttemptFailureOperator(previouslyChosenException, attemptException, onlyRuntimeExceptions, onAttemptFailureOperator);
-
- /*
- * A MongoOperationTimeoutException indicates that the operation timed out, either during command execution or server selection.
- * The timeout for server selection is determined by the computedServerSelectionMS = min(serverSelectionTimeoutMS, timeoutMS).
- *
- * It is important to check if the exception is an instance of MongoOperationTimeoutException to detect a timeout.
- */
- if (isLastAttempt() || attemptException instanceof MongoOperationTimeoutException) {
+ if (isLastAttempt(attemptException)) {
previouslyChosenException = newlyChosenException;
- /*
- * The function of isLastIteration() is to indicate if retrying has
- * been explicitly halted. Such a stop is not interpreted as
- * a timeout exception but as a deliberate cessation of retry attempts.
- */
- if (retryUntilTimeoutThrowsException && !loopState.isLastIteration()) {
- previouslyChosenException = createMongoTimeoutException(
- "Retry attempt exceeded the timeout limit.",
- previouslyChosenException);
+ if (attemptException instanceof MongoOperationTimeoutException) {
+ previouslyChosenException = createMongoTimeoutException("Retry attempt exceeded the timeout limit.", previouslyChosenException);
}
throw previouslyChosenException;
} else {
@@ -365,27 +351,23 @@ public boolean isFirstAttempt() {
* An attempt is known to be the last one iff any of the following applies:
*
* - {@link #breakAndThrowIfRetryAnd(Supplier)} / {@link #breakAndCompleteIfRetryAnd(Supplier, SingleResultCallback)} / {@link #markAsLastAttempt()} was called.
- * - A timeout is set and has been reached.
+ * - A timeout is set and has been reached, as indicated by {@code attemptException}.
* - No timeout is set, and the number of attempts is limited, and the current attempt is the last one.
*
*
* @see #attempt()
*/
- public boolean isLastAttempt() {
- if (loopState.isLastIteration()) {
- return true;
- }
- if (retryUntilTimeoutThrowsException) {
- return false;
- }
- return attempt() == attempts - 1;
+ private boolean isLastAttempt(final Throwable attemptException) {
+ boolean operationTimeout = retryUntilTimeoutThrowsException && attemptException instanceof MongoOperationTimeoutException;
+ boolean attemptLimit = attempt() == attempts - 1;
+ assertFalse(operationTimeout && attemptLimit);
+ return loopState.isLastIteration() || operationTimeout || attemptLimit;
}
/**
* A 0-based attempt number.
*
* @see #isFirstAttempt()
- * @see #isLastAttempt()
*/
public int attempt() {
return loopState.iteration();
diff --git a/driver-core/src/main/com/mongodb/internal/async/function/RetryingAsyncCallbackSupplier.java b/driver-core/src/main/com/mongodb/internal/async/function/RetryingAsyncCallbackSupplier.java
index 16f6f2e708..6ce08513aa 100644
--- a/driver-core/src/main/com/mongodb/internal/async/function/RetryingAsyncCallbackSupplier.java
+++ b/driver-core/src/main/com/mongodb/internal/async/function/RetryingAsyncCallbackSupplier.java
@@ -69,7 +69,7 @@ public final class RetryingAsyncCallbackSupplier implements AsyncCallbackSupp
* per attempt and only if all the following is true:
*
* - {@code onAttemptFailureOperator} completed normally;
- * - the most recent attempt is not the {@linkplain RetryState#isLastAttempt() last} one.
+ * - the most recent attempt is not known to be the last one.
*
* The {@code retryPredicate} accepts this {@link RetryState} and the exception from the most recent attempt,
* and may mutate the exception. The {@linkplain RetryState} advances to represent the state of a new attempt
diff --git a/driver-core/src/test/unit/com/mongodb/internal/async/function/RetryStateTest.java b/driver-core/src/test/unit/com/mongodb/internal/async/function/RetryStateTest.java
index 40a2033249..e66e131522 100644
--- a/driver-core/src/test/unit/com/mongodb/internal/async/function/RetryStateTest.java
+++ b/driver-core/src/test/unit/com/mongodb/internal/async/function/RetryStateTest.java
@@ -21,6 +21,7 @@
import com.mongodb.internal.TimeoutSettings;
import com.mongodb.internal.async.function.LoopState.AttachmentKey;
import com.mongodb.internal.operation.retry.AttachmentKeys;
+import com.mongodb.lang.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -28,11 +29,15 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
+import java.util.function.BiPredicate;
+import java.util.function.BinaryOperator;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -73,41 +78,36 @@ static Stream noTimeout() {
@ParameterizedTest
@MethodSource({"infiniteTimeout", "noTimeout"})
void unlimitedAttemptsAndAdvance(final TimeoutContext timeoutContext) {
+ RuntimeException attemptException = new RuntimeException();
RetryState retryState = new RetryState(timeoutContext);
assertAll(
() -> assertTrue(retryState.isFirstAttempt()),
- () -> assertEquals(0, retryState.attempt()),
- () -> assertFalse(retryState.isLastAttempt())
+ () -> assertEquals(0, retryState.attempt())
);
- advance(retryState);
+ retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> true);
assertAll(
() -> assertFalse(retryState.isFirstAttempt()),
- () -> assertEquals(1, retryState.attempt()),
- () -> assertFalse(retryState.isLastAttempt())
+ () -> assertEquals(1, retryState.attempt())
);
retryState.markAsLastAttempt();
assertAll(
() -> assertFalse(retryState.isFirstAttempt()),
() -> assertEquals(1, retryState.attempt()),
- () -> assertTrue(retryState.isLastAttempt())
+ () -> assertAdvanceOrThrow(attemptException, retryState, attemptException)
);
}
@Test
void limitedAttemptsAndAdvance() {
RetryState retryState = RetryState.withNonRetryableState();
- RuntimeException attemptException = new RuntimeException() {
- };
+ RuntimeException attemptException = new RuntimeException();
assertAll(
() -> assertTrue(retryState.isFirstAttempt()),
() -> assertEquals(0, retryState.attempt()),
- () -> assertTrue(retryState.isLastAttempt()),
- () -> assertThrows(attemptException.getClass(), () ->
- retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> true)),
+ () -> assertAdvanceOrThrow(attemptException, retryState, attemptException),
// when there is only one attempt, it is both the first and the last one
() -> assertTrue(retryState.isFirstAttempt()),
- () -> assertEquals(0, retryState.attempt()),
- () -> assertTrue(retryState.isLastAttempt())
+ () -> assertEquals(0, retryState.attempt())
);
}
@@ -116,11 +116,8 @@ void limitedAttemptsAndAdvance() {
void markAsLastAttemptAdvanceWithRuntimeException(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
retryState.markAsLastAttempt();
- assertTrue(retryState.isLastAttempt());
- RuntimeException attemptException = new RuntimeException() {
- };
- assertThrows(attemptException.getClass(),
- () -> retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> fail()));
+ RuntimeException attemptException = new RuntimeException();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException, (rs, e) -> fail());
}
@ParameterizedTest(name = "should advance with non-retryable error when marked as last attempt and : ''{0}''")
@@ -128,11 +125,8 @@ void markAsLastAttemptAdvanceWithRuntimeException(final TimeoutContext timeoutCo
void markAsLastAttemptAdvanceWithError(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
retryState.markAsLastAttempt();
- assertTrue(retryState.isLastAttempt());
- Error attemptException = new Error() {
- };
- assertThrows(attemptException.getClass(),
- () -> retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> fail()));
+ Error attemptException = new Error();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException, (rs, e) -> fail());
}
@ParameterizedTest
@@ -140,7 +134,7 @@ void markAsLastAttemptAdvanceWithError(final TimeoutContext timeoutContext) {
void breakAndThrowIfRetryAndFirstAttempt(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
retryState.breakAndThrowIfRetryAnd(Assertions::fail);
- assertFalse(retryState.isLastAttempt());
+ assertAdvanceOrThrow(null, retryState, new RuntimeException());
}
@ParameterizedTest
@@ -149,26 +143,27 @@ void breakAndThrowIfRetryAndFalse(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
advance(retryState);
retryState.breakAndThrowIfRetryAnd(() -> false);
- assertFalse(retryState.isLastAttempt());
+ assertAdvanceOrThrow(null, retryState, new RuntimeException());
}
@ParameterizedTest
@MethodSource({"infiniteTimeout", "noTimeout"})
- void breakAndThrowIfRetryAndTrue() {
- RetryState retryState = new RetryState(TIMEOUT_CONTEXT_NO_GLOBAL_TIMEOUT);
+ void breakAndThrowIfRetryAndTrue(final TimeoutContext timeoutContext) {
+ RetryState retryState = new RetryState(timeoutContext);
advance(retryState);
assertThrows(RuntimeException.class, () -> retryState.breakAndThrowIfRetryAnd(() -> true));
- assertTrue(retryState.isLastAttempt());
+ RuntimeException attemptException = new RuntimeException();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException);
}
@Test
void breakAndThrowIfRetryAndTrueWithExpiredTimeout() {
TimeoutContext tContextMock = mock(TimeoutContext.class);
-
RetryState retryState = new RetryState(tContextMock);
advance(retryState);
assertThrows(RuntimeException.class, () -> retryState.breakAndThrowIfRetryAnd(() -> true));
- assertTrue(retryState.isLastAttempt());
+ RuntimeException attemptException = new RuntimeException();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException);
}
@ParameterizedTest
@@ -176,12 +171,13 @@ void breakAndThrowIfRetryAndTrueWithExpiredTimeout() {
void breakAndThrowIfRetryIfPredicateThrows(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
advance(retryState);
- RuntimeException e = new RuntimeException() {
- };
- assertThrows(e.getClass(), () -> retryState.breakAndThrowIfRetryAnd(() -> {
- throw e;
- }));
- assertFalse(retryState.isLastAttempt());
+ RuntimeException exception = new RuntimeException();
+ assertEquals(
+ exception,
+ assertThrows(exception.getClass(), () -> retryState.breakAndThrowIfRetryAnd(() -> {
+ throw exception;
+ })));
+ assertAdvanceOrThrow(null, retryState, exception);
}
@ParameterizedTest
@@ -191,7 +187,7 @@ void breakAndCompleteIfRetryAndFirstAttempt(final TimeoutContext timeoutContext)
SupplyingCallback> callback = new SupplyingCallback<>();
assertFalse(retryState.breakAndCompleteIfRetryAnd(Assertions::fail, callback));
assertFalse(callback.completed());
- assertFalse(retryState.isLastAttempt());
+ assertAdvanceOrThrow(null, retryState, new RuntimeException());
}
@ParameterizedTest
@@ -202,7 +198,7 @@ void breakAndCompleteIfRetryAndFalse(final TimeoutContext timeoutContext) {
SupplyingCallback> callback = new SupplyingCallback<>();
assertFalse(retryState.breakAndCompleteIfRetryAnd(() -> false, callback));
assertFalse(callback.completed());
- assertFalse(retryState.isLastAttempt());
+ assertAdvanceOrThrow(null, retryState, new RuntimeException());
}
@ParameterizedTest
@@ -213,7 +209,8 @@ void breakAndCompleteIfRetryAndTrue(final TimeoutContext timeoutContext) {
SupplyingCallback> callback = new SupplyingCallback<>();
assertTrue(retryState.breakAndCompleteIfRetryAnd(() -> true, callback));
assertThrows(RuntimeException.class, callback::get);
- assertTrue(retryState.isLastAttempt());
+ RuntimeException attemptException = new RuntimeException();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException);
}
@ParameterizedTest
@@ -221,23 +218,23 @@ void breakAndCompleteIfRetryAndTrue(final TimeoutContext timeoutContext) {
void breakAndCompleteIfRetryAndPredicateThrows(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
advance(retryState);
- Error e = new Error() {
- };
+ Error exception = new Error();
SupplyingCallback> callback = new SupplyingCallback<>();
assertTrue(retryState.breakAndCompleteIfRetryAnd(() -> {
- throw e;
+ throw exception;
}, callback));
- assertThrows(e.getClass(), callback::get);
- assertFalse(retryState.isLastAttempt());
+ assertEquals(
+ exception,
+ assertThrows(exception.getClass(), callback::get));
+ assertAdvanceOrThrow(null, retryState, exception);
}
@ParameterizedTest
@MethodSource({"infiniteTimeout", "noTimeout"})
void advanceOrThrowPredicateFalse(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
- RuntimeException attemptException = new RuntimeException() {
- };
- assertThrows(attemptException.getClass(), () -> retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> false));
+ RuntimeException attemptException = new RuntimeException();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException, (rs, e) -> false);
}
@ParameterizedTest
@@ -247,34 +244,30 @@ void advanceReThrowDetectedTimeoutExceptionEvenIfTimeoutInRetryStateIsNotExpired
RetryState retryState = new RetryState(timeoutContext);
MongoOperationTimeoutException expectedTimeoutException = TimeoutContext.createMongoTimeoutException("Server selection failed");
- MongoOperationTimeoutException actualTimeoutException =
- assertThrows(expectedTimeoutException.getClass(), () -> retryState.advanceOrThrow(expectedTimeoutException,
- (e1, e2) -> expectedTimeoutException,
- (rs, e) -> false));
-
- Assertions.assertEquals(actualTimeoutException, expectedTimeoutException);
+ assertAdvanceOrThrow(expectedTimeoutException, retryState, expectedTimeoutException,
+ (e1, e2) -> expectedTimeoutException,
+ (rs, e) -> false);
}
@Test
@DisplayName("should throw timeout exception from retry, when transformer swallows original timeout exception")
void advanceThrowTimeoutExceptionWhenTransformerSwallowOriginalTimeoutException() {
RetryState retryState = new RetryState(TIMEOUT_CONTEXT_INFINITE_GLOBAL_TIMEOUT);
- RuntimeException previousAttemptException = new RuntimeException() {
- };
- MongoOperationTimeoutException expectedTimeoutException = TimeoutContext.createMongoTimeoutException("Server selection failed");
+ RuntimeException previousAttemptException = new RuntimeException();
+ MongoOperationTimeoutException unexpectedTimeoutException = TimeoutContext.createMongoTimeoutException("Server selection failed");
retryState.advanceOrThrow(previousAttemptException,
(e1, e2) -> previousAttemptException,
(rs, e) -> true);
MongoOperationTimeoutException actualTimeoutException =
- assertThrows(expectedTimeoutException.getClass(), () -> retryState.advanceOrThrow(expectedTimeoutException,
+ assertThrows(unexpectedTimeoutException.getClass(), () -> retryState.advanceOrThrow(unexpectedTimeoutException,
(e1, e2) -> previousAttemptException,
(rs, e) -> false));
- Assertions.assertNotEquals(actualTimeoutException, expectedTimeoutException);
- Assertions.assertEquals(EXPECTED_TIMEOUT_MESSAGE, actualTimeoutException.getMessage());
- Assertions.assertEquals(previousAttemptException, actualTimeoutException.getCause(),
+ assertNotEquals(unexpectedTimeoutException, actualTimeoutException);
+ assertEquals(EXPECTED_TIMEOUT_MESSAGE, actualTimeoutException.getMessage());
+ assertEquals(previousAttemptException, actualTimeoutException.getCause(),
"Retry timeout exception should have a cause if transformer returned non-timeout exception.");
}
@@ -283,8 +276,7 @@ void advanceThrowTimeoutExceptionWhenTransformerSwallowOriginalTimeoutException(
@DisplayName("should throw original timeout exception from retry, when transformer returns original timeout exception")
void advanceThrowOriginalTimeoutExceptionWhenTransformerReturnsOriginalTimeoutException() {
RetryState retryState = new RetryState(TIMEOUT_CONTEXT_INFINITE_GLOBAL_TIMEOUT);
- RuntimeException previousAttemptException = new RuntimeException() {
- };
+ RuntimeException previousAttemptException = new RuntimeException();
MongoOperationTimeoutException expectedTimeoutException = TimeoutContext
.createMongoTimeoutException("Server selection failed");
@@ -292,44 +284,37 @@ void advanceThrowOriginalTimeoutExceptionWhenTransformerReturnsOriginalTimeoutEx
(e1, e2) -> previousAttemptException,
(rs, e) -> true);
- MongoOperationTimeoutException actualTimeoutException =
- assertThrows(expectedTimeoutException.getClass(), () -> retryState.advanceOrThrow(expectedTimeoutException,
- (e1, e2) -> expectedTimeoutException,
- (rs, e) -> false));
-
- Assertions.assertEquals(actualTimeoutException, expectedTimeoutException);
- Assertions.assertNull(actualTimeoutException.getCause(),
- "Original timeout exception should not have a cause if transformer already returned timeout exception.");
+ assertAdvanceOrThrow(expectedTimeoutException, retryState, expectedTimeoutException,
+ (e1, e2) -> expectedTimeoutException,
+ (rs, e) -> false);
}
@Test
void advanceOrThrowPredicateTrueAndLastAttempt() {
RetryState retryState = RetryState.withNonRetryableState();
- Error attemptException = new Error() {
- };
- assertThrows(attemptException.getClass(), () -> retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> true));
+ Error attemptException = new Error();
+ assertAdvanceOrThrow(attemptException, retryState, attemptException);
}
@ParameterizedTest
@MethodSource({"infiniteTimeout", "noTimeout"})
void advanceOrThrowPredicateThrowsAfterFirstAttempt(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
- RuntimeException predicateException = new RuntimeException() {
- };
- RuntimeException attemptException = new RuntimeException() {
- };
- assertThrows(predicateException.getClass(), () -> retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> {
- assertTrue(rs.isFirstAttempt());
- assertEquals(attemptException, e);
- throw predicateException;
- }));
+ RuntimeException predicateException = new RuntimeException();
+ RuntimeException attemptException = new RuntimeException();
+ assertAdvanceOrThrow(predicateException, retryState, attemptException,
+ (e1, e2) -> e2,
+ (rs, e) -> {
+ assertTrue(rs.isFirstAttempt());
+ assertEquals(attemptException, e);
+ throw predicateException;
+ });
}
@Test
void advanceOrThrowPredicateThrowsTimeoutAfterFirstAttempt() {
RetryState retryState = new RetryState(TIMEOUT_CONTEXT_EXPIRED_GLOBAL_TIMEOUT);
- RuntimeException predicateException = new RuntimeException() {
- };
+ RuntimeException predicateException = new RuntimeException();
RuntimeException attemptException = new MongoOperationTimeoutException(EXPECTED_TIMEOUT_MESSAGE);
MongoOperationTimeoutException mongoOperationTimeoutException = assertThrows(MongoOperationTimeoutException.class,
() -> retryState.advanceOrThrow(attemptException, (e1, e2) -> e2, (rs, e) -> {
@@ -346,58 +331,52 @@ void advanceOrThrowPredicateThrowsTimeoutAfterFirstAttempt() {
@MethodSource({"infiniteTimeout", "noTimeout"})
void advanceOrThrowPredicateThrows(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
- RuntimeException firstAttemptException = new RuntimeException() {
- };
+ RuntimeException firstAttemptException = new RuntimeException();
retryState.advanceOrThrow(firstAttemptException, (e1, e2) -> e2, (rs, e) -> true);
- RuntimeException secondAttemptException = new RuntimeException() {
- };
- RuntimeException predicateException = new RuntimeException() {
- };
- assertThrows(predicateException.getClass(), () -> retryState.advanceOrThrow(secondAttemptException, (e1, e2) -> e2, (rs, e) -> {
- assertEquals(1, rs.attempt());
- assertEquals(secondAttemptException, e);
- throw predicateException;
- }));
+ RuntimeException secondAttemptException = new RuntimeException();
+ RuntimeException predicateException = new RuntimeException();
+ assertAdvanceOrThrow(predicateException, retryState, secondAttemptException,
+ (e1, e2) -> e2,
+ (rs, e) -> {
+ assertEquals(1, rs.attempt());
+ assertEquals(secondAttemptException, e);
+ throw predicateException;
+ });
}
@ParameterizedTest
@MethodSource({"infiniteTimeout", "noTimeout", "expiredTimeout"})
void advanceOrThrowTransformerThrowsAfterFirstAttempt(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
- RuntimeException transformerException = new RuntimeException() {
- };
- assertThrows(transformerException.getClass(), () -> retryState.advanceOrThrow(new AssertionError(),
+ RuntimeException transformerException = new RuntimeException();
+ assertAdvanceOrThrow(transformerException, retryState, new AssertionError(),
(e1, e2) -> {
throw transformerException;
},
- (rs, e) -> fail()));
+ (rs, e) -> fail());
}
@ParameterizedTest
- @MethodSource({"infiniteTimeout", "noTimeout"}) //TODO mock?
+ @MethodSource({"infiniteTimeout", "noTimeout"})
void advanceOrThrowTransformerThrows(final TimeoutContext timeoutContext) throws Throwable {
RetryState retryState = new RetryState(timeoutContext);
- Error firstAttemptException = new Error() {
- };
+ Error firstAttemptException = new Error();
retryState.advanceOrThrow(firstAttemptException, (e1, e2) -> e2, (rs, e) -> true);
- RuntimeException transformerException = new RuntimeException() {
- };
- assertThrows(transformerException.getClass(), () -> retryState.advanceOrThrow(new AssertionError(),
+ RuntimeException transformerException = new RuntimeException();
+ assertAdvanceOrThrow(transformerException, retryState, new AssertionError(),
(e1, e2) -> {
throw transformerException;
},
- (rs, e) -> fail()));
+ (rs, e) -> fail());
}
@ParameterizedTest
@MethodSource({"infiniteTimeout", "noTimeout"})
void advanceOrThrowTransformAfterFirstAttempt(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
- RuntimeException attemptException = new RuntimeException() {
- };
- RuntimeException transformerResult = new RuntimeException() {
- };
- assertThrows(transformerResult.getClass(), () -> retryState.advanceOrThrow(attemptException,
+ RuntimeException attemptException = new RuntimeException();
+ RuntimeException transformerResult = new RuntimeException();
+ assertAdvanceOrThrow(transformerResult, retryState, attemptException,
(e1, e2) -> {
assertNull(e1);
assertEquals(attemptException, e2);
@@ -406,7 +385,7 @@ void advanceOrThrowTransformAfterFirstAttempt(final TimeoutContext timeoutContex
(rs, e) -> {
assertEquals(attemptException, e);
return false;
- }));
+ });
}
@Test
@@ -436,14 +415,11 @@ void advanceOrThrowTransformThrowsTimeoutExceptionAfterFirstAttempt() {
@MethodSource({"infiniteTimeout", "noTimeout"})
void advanceOrThrowTransform(final TimeoutContext timeoutContext) {
RetryState retryState = new RetryState(timeoutContext);
- RuntimeException firstAttemptException = new RuntimeException() {
- };
+ RuntimeException firstAttemptException = new RuntimeException();
retryState.advanceOrThrow(firstAttemptException, (e1, e2) -> e2, (rs, e) -> true);
- RuntimeException secondAttemptException = new RuntimeException() {
- };
- RuntimeException transformerResult = new RuntimeException() {
- };
- assertThrows(transformerResult.getClass(), () -> retryState.advanceOrThrow(secondAttemptException,
+ RuntimeException secondAttemptException = new RuntimeException();
+ RuntimeException transformerResult = new RuntimeException();
+ assertAdvanceOrThrow(transformerResult, retryState, secondAttemptException,
(e1, e2) -> {
assertEquals(firstAttemptException, e1);
assertEquals(secondAttemptException, e2);
@@ -452,7 +428,7 @@ void advanceOrThrowTransform(final TimeoutContext timeoutContext) {
(rs, e) -> {
assertEquals(secondAttemptException, e);
return false;
- }));
+ });
}
@ParameterizedTest
@@ -475,4 +451,35 @@ void attachAndAttachment(final TimeoutContext timeoutContext) {
private static void advance(final RetryState retryState) {
retryState.advanceOrThrow(new RuntimeException(), (e1, e2) -> e2, (rs, e) -> true);
}
+
+ private static void assertAdvanceOrThrow(
+ @Nullable final Throwable expectedException,
+ final RetryState retryState,
+ final Throwable attemptException) {
+ assertAdvanceOrThrow(expectedException, retryState, attemptException, (rs, e) -> true);
+ }
+
+ private static void assertAdvanceOrThrow(
+ @Nullable final Throwable expectedException,
+ final RetryState retryState,
+ final Throwable attemptException,
+ final BiPredicate retryPredicate) {
+ assertAdvanceOrThrow(expectedException, retryState, attemptException, (e1, e2) -> e2, retryPredicate);
+ }
+
+ private static void assertAdvanceOrThrow(
+ @Nullable final Throwable expectedException,
+ final RetryState retryState,
+ final Throwable attemptException,
+ final BinaryOperator onAttemptFailureOperator,
+ final BiPredicate retryPredicate) {
+ if (expectedException == null) {
+ assertDoesNotThrow(() -> retryState.advanceOrThrow(attemptException, onAttemptFailureOperator, retryPredicate));
+ } else {
+ assertEquals(
+ expectedException,
+ assertThrows(expectedException.getClass(), () ->
+ retryState.advanceOrThrow(attemptException, onAttemptFailureOperator, retryPredicate)));
+ }
+ }
}