### Question:
RetryingMessageReader implements MessageReader { @Override @Retryable(include = { AmazonClientException.class }, maxAttempts = MAX_ATTEMPTS, backoff = @Backoff(delay = INITIAL_DELAY_MS, multiplier = BACKOFF_MULTIPLIER)) public void delete(MessageEvent messageEvent) { delegate.delete(messageEvent); } RetryingMessageReader(MessageReader delegate); @Override @Retryable(value = { AmazonClientException.class }, maxAttempts = MAX_ATTEMPTS, backoff = @Backoff(delay = INITIAL_DELAY_MS, multiplier = BACKOFF_MULTIPLIER)) Optional<MessageEvent> read(); @Override @Retryable(include = { AmazonClientException.class }, maxAttempts = MAX_ATTEMPTS, backoff = @Backoff(delay = INITIAL_DELAY_MS, multiplier = BACKOFF_MULTIPLIER)) void delete(MessageEvent messageEvent); @Override void close(); @Recover Optional<MessageEvent> recoverRead(AmazonClientException e); @Recover void recoverDelete(AmazonClientException e, MessageEvent messageEvent);  }### Answer:
@Test public void typicalDelete() { retryingMessageReader.delete(event); verify(delegate).delete(event); }
@Test public void retryDelete() { doThrow(new AmazonClientException("Exception")).doNothing() .when(delegate) .delete(event); retryingMessageReader.delete(event); verify(delegate, times(2)).delete(event); }
@Test public void retryMaxAttemptsDelete() { when(event.getMessageProperties()).thenReturn(Map.of(SqsMessageProperty.SQS_MESSAGE_RECEIPT_HANDLE, HANDLE)); doThrow(new AmazonClientException("Exception")).when(delegate) .delete(event); assertThatThrownBy(() -> retryingMessageReader.delete(event)).isInstanceOf(BeekeeperException.class) .hasMessageContaining("Error deleting message " + HANDLE + " from queue after " + MAX_ATTEMPTS + " attempts."); verify(delegate, times(MAX_ATTEMPTS)).delete(event); }