简体   繁体   中英

Spring Retry Junit: Testing Retry template with Custom Retry Policy

I'm trying to test a Retry template which is using a custom Retry Policy. In order to do that, I'm using this examples:

https://github.com/spring-projects/spring-retry/blob/master/src/test/java/org/springframework/retry/support/RetryTemplateTests.java#L57

Basically, my goal is to test my retry logic when I got some specific http error status (for example an http 500 error status).

This is the xml context for my junit:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int-http="http://www.springframework.org/schema/integration/http"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/integration
         http://www.springframework.org/schema/integration/spring-integration.xsd
         http://www.springframework.org/schema/integration/http
         http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">

    <bean id="retryTemplate_test" class="org.springframework.retry.support.RetryTemplate">
        <property name="retryPolicy">
            <bean
                class="util.CustomRetryPolicy">
                <property name="maxAttempts" value="5" />
            </bean>
        </property>
        <property name="backOffPolicy">
            <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                <property name="initialInterval" value="1000" />
                <property name="multiplier" value="6" />
            </bean>
        </property>
    </bean>

</beans>

where CustomRetryPolicy is like:

public class CustomRetryPolicy extends ExceptionClassifierRetryPolicy {

    private String maxAttempts;

    @PostConstruct
    public void init() {

        this.setExceptionClassifier(new Classifier<Throwable, RetryPolicy>() {
            @Override
            public RetryPolicy classify(Throwable classifiable) {
                Throwable exceptionCause = classifiable.getCause();
                if (exceptionCause instanceof HttpStatusCodeException) {
                    int statusCode = ((HttpStatusCodeException) classifiable.getCause()).getStatusCode().value();
                    return handleHttpErrorCode(statusCode);
                }
                return neverRetry();
            }
        });
    }

    public void setMaxAttempts(String maxAttempts) {
        this.maxAttempts = maxAttempts;
    }


    private RetryPolicy handleHttpErrorCode(int statusCode) {
        RetryPolicy retryPolicy = null;
        switch(statusCode) {
        case 404 :
        case 500 :
        case 503 :
        case 504 :
            retryPolicy = defaultRetryPolicy();
            break;
        default :
            retryPolicy = neverRetry();
            break;
        }

        return retryPolicy;
    }

    private RetryPolicy neverRetry() {
        return new NeverRetryPolicy();
    }

    private RetryPolicy defaultRetryPolicy() {
        final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts(Integer.valueOf(maxAttempts));
        return simpleRetryPolicy;
    }

}

And the Java class where I'm testing is:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(locations = {"classpath:my_context_for_test.xml"})
public class RetryTemplateTest{


      @Autowired
      @Qualifier("retryTemplate_test")
      RetryTemplate retryTemplate_test;

    @Test
    public void testRetry() throws Throwable {
        Map<Class<? extends Throwable>, Boolean> r = new HashMap<>();
        r.put(HttpStatusCodeException.class, true);

            MockRetryCallback callback = new MockRetryCallback();
            callback.setAttemptsBeforeSuccess(5);            
            retryTemplate_test.execute(callback);

            assertEquals(5, callback.attempts);        
    }

    private static class MockRetryCallback implements RetryCallback<Object, HttpStatusCodeException> {

        private int attempts;

        private int attemptsBeforeSuccess;


        @SuppressWarnings("serial")
        @Override
        public Object doWithRetry(RetryContext status) throws HttpStatusCodeException {
            this.attempts++;
            if (this.attempts < this.attemptsBeforeSuccess) {
                System.out.println("I'm here: "+ this.attempts);
                throw new HttpStatusCodeException(HttpStatus.INTERNAL_SERVER_ERROR) {
                };
            }
            return null;
        }

        public void setAttemptsBeforeSuccess(int attemptsBeforeSuccess) {
            this.attemptsBeforeSuccess = attemptsBeforeSuccess;
        }
    }

}

What am I doing wrong? My understanding is, using the callback, I'm mocking a response, and with that, I can handle (using my custom retry policy) that response. Also

[UPDATE]

If I try to replicate this junit , then I got the same exception. Most specifically, it fails when try to instance the exception within the MockRetryCallback class right here :

    private Exception exceptionToThrow = new Exception();

I was able to get it working with this:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class HttpRetryTest{


      @Autowired
      @Qualifier("retryTemplate_test")
      RetryOperations retryTemplate_test;

    @Test
    public void testRetry() throws Throwable {
        Map<Class<? extends Throwable>, Boolean> r = new HashMap<>();
        r.put(HttpStatusCodeException.class, true);

            MockRetryCallback callback = new MockRetryCallback();
            MockRetryCallback.attemptsBeforeSuccess =5;            
            retryTemplate_test.execute(callback);

            assertEquals(5, MockRetryCallback.attempts);        
    }

    private static class MockRetryCallback implements RetryCallback<Object, HttpStatusCodeException> {

        private static int attempts;

        private static int attemptsBeforeSuccess;


        @SuppressWarnings("serial")
        @Override
        public Object doWithRetry(RetryContext status) throws HttpStatusCodeException {
            MockRetryCallback.attempts++;
            if (MockRetryCallback.attempts <= MockRetryCallback.attemptsBeforeSuccess) {
                System.out.println("I'm here: "+ MockRetryCallback.attempts);
                throw new HttpStatusCodeException(HttpStatus.INTERNAL_SERVER_ERROR) {
                };

            }
            return null;
        }
    }
}

For something much simpler, you might check out Failsafe :

RetryPolicy<Object> retryPolicy = new RetryPolicy<>()
  .handleIf((HttpStatusCodeException e) -> e.getStatusCode().getValue() == 504)
  .withMaxAttempts(maxAttempts);

Failsafe.with(retryPolicy).get(() -> doSomething);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM