@ -23,6 +23,7 @@ import java.util.List;
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Objects ;
import java.util.concurrent.atomic.AtomicInteger ;
import java.util.function.Consumer ;
import java.util.function.Supplier ;
import org.assertj.core.api.ThrowingConsumer ;
import org.junit.jupiter.api.BeforeEach ;
@ -79,7 +80,7 @@ class RetryTemplateTests {
@@ -79,7 +80,7 @@ class RetryTemplateTests {
}
@Test
void retryWithImmediateSuccess ( ) throws Exception {
void retryable WithImmediateSuccess ( ) throws Exception {
AtomicInteger invocationCount = new AtomicInteger ( ) ;
Retryable < String > retryable = ( ) - > {
invocationCount . incrementAndGet ( ) ;
@ -97,7 +98,7 @@ class RetryTemplateTests {
@@ -97,7 +98,7 @@ class RetryTemplateTests {
}
@Test
void retryWithInitialFailureAndZeroRetriesRetryPolicy ( ) {
void retryable WithInitialFailureAndZeroRetriesRetryPolicy ( ) {
RetryPolicy retryPolicy = throwable - > false ; // Zero retries
RetryTemplate retryTemplate = new RetryTemplate ( retryPolicy ) ;
retryTemplate . setRetryListener ( retryListener ) ;
@ -121,9 +122,8 @@ class RetryTemplateTests {
@@ -121,9 +122,8 @@ class RetryTemplateTests {
verifyNoMoreInteractions ( retryListener ) ;
}
@Test
void retryWithInitialFailureAndZeroRetriesFixedBackOffPolicy ( ) {
void retryable WithInitialFailureAndZeroRetriesFixedBackOffPolicy ( ) {
RetryPolicy retryPolicy = RetryPolicy . withMaxRetries ( 0 ) ;
RetryTemplate retryTemplate = new RetryTemplate ( retryPolicy ) ;
@ -149,7 +149,7 @@ class RetryTemplateTests {
@@ -149,7 +149,7 @@ class RetryTemplateTests {
}
@Test
void retryWithInitialFailureAndZeroRetriesBackOffPolicyFromBuilder ( ) {
void retryable WithInitialFailureAndZeroRetriesBackOffPolicyFromBuilder ( ) {
RetryPolicy retryPolicy = RetryPolicy . builder ( ) . maxRetries ( 0 ) . build ( ) ;
RetryTemplate retryTemplate = new RetryTemplate ( retryPolicy ) ;
@ -175,7 +175,7 @@ class RetryTemplateTests {
@@ -175,7 +175,7 @@ class RetryTemplateTests {
}
@Test
void retryWithSuccessAfterInitialFailures ( ) throws Exception {
void retryable WithSuccessAfterInitialFailures ( ) throws Exception {
AtomicInteger invocationCount = new AtomicInteger ( ) ;
Retryable < String > retryable = ( ) - > {
if ( invocationCount . incrementAndGet ( ) < = 2 ) {
@ -201,7 +201,7 @@ class RetryTemplateTests {
@@ -201,7 +201,7 @@ class RetryTemplateTests {
}
@Test
void retryWithExhaustedPolicy ( ) {
void retryable WithExhaustedPolicy ( ) {
var invocationCount = new AtomicInteger ( ) ;
var retryable = new Retryable < > ( ) {
@ -239,7 +239,7 @@ class RetryTemplateTests {
@@ -239,7 +239,7 @@ class RetryTemplateTests {
}
@Test
void retryWithInterruptionDuringSleep ( ) {
void retryable WithInterruptionDuringSleep ( ) {
Exception exception = new RuntimeException ( "Boom!" ) ;
InterruptedException interruptedException = new InterruptedException ( ) ;
@ -269,7 +269,7 @@ class RetryTemplateTests {
@@ -269,7 +269,7 @@ class RetryTemplateTests {
}
@Test
void retryWithFailingRetryableAndMultiplePredicates ( ) {
void retryable WithFailingRetryableAndMultiplePredicates ( ) {
var invocationCount = new AtomicInteger ( ) ;
var exception = new NumberFormatException ( "Boom!" ) ;
@ -316,7 +316,7 @@ class RetryTemplateTests {
@@ -316,7 +316,7 @@ class RetryTemplateTests {
}
@Test
void retryWithExceptionIncludes ( ) {
void retryable WithExceptionIncludes ( ) {
var invocationCount = new AtomicInteger ( ) ;
var retryable = new Retryable < > ( ) {
@ -387,7 +387,7 @@ class RetryTemplateTests {
@@ -387,7 +387,7 @@ class RetryTemplateTests {
@ParameterizedTest
@FieldSource ( "includesAndExcludesRetryPolicies" )
void retryWithExceptionIncludesAndExcludes ( RetryPolicy retryPolicy ) {
void retryable WithExceptionIncludesAndExcludes ( RetryPolicy retryPolicy ) {
retryTemplate . setRetryPolicy ( retryPolicy ) ;
var invocationCount = new AtomicInteger ( ) ;
@ -436,12 +436,105 @@ class RetryTemplateTests {
@@ -436,12 +436,105 @@ class RetryTemplateTests {
verifyNoMoreInteractions ( retryListener ) ;
}
@Test
void supplierWithImmediateSuccess ( ) {
AtomicInteger invocationCount = new AtomicInteger ( ) ;
Supplier < String > retryable = ( ) - > {
invocationCount . incrementAndGet ( ) ;
return "always succeeds" ;
} ;
assertThat ( invocationCount ) . hasValue ( 0 ) ;
assertThat ( retryTemplate . invoke ( retryable ) ) . isEqualTo ( "always succeeds" ) ;
assertThat ( invocationCount ) . hasValue ( 1 ) ;
// RetryListener interactions:
inOrder . verify ( retryListener ) . onRetryableExecution ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
argThat ( state - > state . isSuccessful ( ) & & state . getRetryCount ( ) = = 0 ) ) ;
verifyNoMoreInteractions ( retryListener ) ;
}
@Test
void supplierWithSuccessAfterInitialFailures ( ) {
AtomicInteger invocationCount = new AtomicInteger ( ) ;
Supplier < String > retryable = ( ) - > {
if ( invocationCount . incrementAndGet ( ) < = 2 ) {
throw new CustomException ( "Boom " + invocationCount . get ( ) ) ;
}
return "finally succeeded" ;
} ;
assertThat ( invocationCount ) . hasValue ( 0 ) ;
assertThat ( retryTemplate . invoke ( retryable ) ) . isEqualTo ( "finally succeeded" ) ;
assertThat ( invocationCount ) . hasValue ( 3 ) ;
// RetryListener interactions:
inOrder . verify ( retryListener ) . onRetryableExecution ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
any ( RetryState . class ) ) ;
inOrder . verify ( retryListener ) . beforeRetry ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ) ;
inOrder . verify ( retryListener ) . onRetryFailure ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
eq ( new CustomException ( "Boom 2" ) ) ) ;
inOrder . verify ( retryListener ) . onRetryableExecution ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
any ( RetryState . class ) ) ;
inOrder . verify ( retryListener ) . beforeRetry ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ) ;
inOrder . verify ( retryListener ) . onRetrySuccess ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
eq ( "finally succeeded" ) ) ;
inOrder . verify ( retryListener ) . onRetryableExecution ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
argThat ( state - > state . isSuccessful ( ) & & state . getRetryCount ( ) = = 2 ) ) ;
verifyNoMoreInteractions ( retryListener ) ;
}
@Test
void supplierWithExhaustedPolicy ( ) {
AtomicInteger invocationCount = new AtomicInteger ( ) ;
Supplier < String > retryable = ( ) - > {
throw new CustomException ( "Boom " + invocationCount . incrementAndGet ( ) ) ;
} ;
assertThat ( invocationCount ) . hasValue ( 0 ) ;
assertThatExceptionOfType ( CustomException . class )
. isThrownBy ( ( ) - > retryTemplate . invoke ( retryable ) )
. withMessage ( "Boom 4" )
. satisfies ( throwable - > {
var counter = new AtomicInteger ( 1 ) ;
repeat ( 3 , ( ) - > {
inOrder . verify ( retryListener ) . onRetryableExecution ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
any ( RetryState . class ) ) ;
inOrder . verify ( retryListener ) . beforeRetry ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ) ;
inOrder . verify ( retryListener ) . onRetryFailure ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
eq ( new CustomException ( "Boom " + counter . incrementAndGet ( ) ) ) ) ;
} ) ;
inOrder . verify ( retryListener ) . onRetryableExecution ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
argThat ( state - > ! state . isSuccessful ( ) & & state . getRetryCount ( ) = = 3 ) ) ;
inOrder . verify ( retryListener ) . onRetryPolicyExhaustion ( eq ( retryPolicy ) ,
argThat ( r - > r . getName ( ) . equals ( retryable . getClass ( ) . getName ( ) ) ) ,
argThat ( t - > t . getMessage ( ) . equals ( "Retry policy for operation '" +
retryable . getClass ( ) . getName ( ) + "' exhausted; aborting execution" ) ) ) ;
} ) ;
// 4 = 1 initial invocation + 3 retry attempts
assertThat ( invocationCount ) . hasValue ( 4 ) ;
verifyNoMoreInteractions ( retryListener ) ;
}
@Nested
class TimeoutTests {
@Test
void retryWithImmediateSuccessAndTimeoutExceeded ( ) throws Exception {
void retryable WithImmediateSuccessAndTimeoutExceeded ( ) throws Exception {
RetryPolicy retryPolicy = RetryPolicy . builder ( ) . timeout ( Duration . ofMillis ( 10 ) ) . build ( ) ;
RetryTemplate retryTemplate = new RetryTemplate ( retryPolicy ) ;
retryTemplate . setRetryListener ( retryListener ) ;
@ -464,7 +557,7 @@ class RetryTemplateTests {
@@ -464,7 +557,7 @@ class RetryTemplateTests {
}
@Test
void retryWithInitialFailureAndZeroRetriesRetryPolicyAndTimeoutExceeded ( ) {
void retryable WithInitialFailureAndZeroRetriesRetryPolicyAndTimeoutExceeded ( ) {
RetryPolicy retryPolicy = RetryPolicy . builder ( )
. timeout ( Duration . ofMillis ( 10 ) )
. predicate ( throwable - > false ) // Zero retries
@ -492,7 +585,7 @@ class RetryTemplateTests {
@@ -492,7 +585,7 @@ class RetryTemplateTests {
}
@Test
void retryWithTimeoutExceededAfterInitialFailure ( ) {
void retryable WithTimeoutExceededAfterInitialFailure ( ) {
RetryPolicy retryPolicy = RetryPolicy . builder ( )
. timeout ( Duration . ofMillis ( 10 ) )
. delay ( Duration . ZERO )
@ -521,7 +614,7 @@ class RetryTemplateTests {
@@ -521,7 +614,7 @@ class RetryTemplateTests {
}
@Test
void retryWithTimeoutExceededAfterFirstDelayButBeforeFirstRetry ( ) {
void retryable WithTimeoutExceededAfterFirstDelayButBeforeFirstRetry ( ) {
RetryPolicy retryPolicy = RetryPolicy . builder ( )
. timeout ( Duration . ofMillis ( 20 ) )
. delay ( Duration . ofMillis ( 100 ) ) // Delay > Timeout
@ -552,7 +645,7 @@ class RetryTemplateTests {
@@ -552,7 +645,7 @@ class RetryTemplateTests {
}
@Test
void retryWithTimeoutExceededAfterFirstRetry ( ) {
void retryable WithTimeoutExceededAfterFirstRetry ( ) {
RetryPolicy retryPolicy = RetryPolicy . builder ( )
. timeout ( Duration . ofMillis ( 20 ) )
. delay ( Duration . ZERO )
@ -589,7 +682,7 @@ class RetryTemplateTests {
@@ -589,7 +682,7 @@ class RetryTemplateTests {
}
@Test
void retryWithTimeoutExceededAfterSecondRetry ( ) {
void retryable WithTimeoutExceededAfterSecondRetry ( ) {
RetryPolicy retryPolicy = RetryPolicy . builder ( )
. timeout ( Duration . ofMillis ( 20 ) )
. delay ( Duration . ZERO )