Guava重试:无法在InterruptedException上测试重试逻辑

时间:2016-12-31 01:35:46

标签: java easymock

目的:

要测试当某个函数抛出异常时,会重试X次。

约束:

  1. 需要使用EasyMock(在单元测试中具有一致的模拟框架)
  2. CODE SNIPPET:

    商业代码
        import com.github.rholder.retry.Retryer;
        import com.github.rholder.retry.RetryerBuilder;
    
        class Retry {
    
            public Retryer<UserData> getRetryer() {
                return RetryerBuilder.<UserData>newBuilder()
                    .retryIfException()
                    .withWaitStrategy(waitStrategy()) //exponential with 3 attempts
                    .withStopStrategy(stopStrategy())
                    .withAttemptTimeLimiter(attemptTimeLimiter())
                    .build();
            }
        }
    
        class UserClass
        {
    
            private final externalTeamLibrary; //and a constructor accepting it
    
            public publishSync(Some inputs, Retry retryParameters)
            {
                Callable<UserData> publishCallable =
                    () -> publishAsync(Some inputs) //returns Future object
                             .get(retryParameters.callTimeOutInMs(), TimeUnit.MILLISECONDS);
                return retryParameters.getRetryer().call(publishCallable);
            }
    
            public Future<FutureData> publishAsync(Some inputs)
            {
                return externalTeamLibrary.send(obj1, obj2); //returns Future object
            }
        }
    
    测试代码
        @Test
        public voide testFunction()
        {
            //real objects
            Retry realRetryInstance = // a way to get one
    
            //mocks
            ExternalTeamLibraryClass externalTeamLibraryMock=  createMock(ExternalTeamLibraryClass.class);
    
            //expectations and return values
            EasyMock.expect(externalTeamLibraryMock.send(anyObject(), anyObject()))
                    .andThrow(new InterruptException("test1"))
                    .times(3);
    
            EasyMock.replay(externalTeamLibraryMock);
    
            UserClass user = new UserClass(externalTeamLibraryMock, other stuff);
            user.publishSync(someRealInputs, realRetryInstance);
    
            //verify all mocks used
            EasyMock.verify(externalTeamLibraryMock);
        }
    

    我想要发生什么

    在显式调用publishSync并使externalTeamLibrary.send()抛出异常时,我希望真正的重试对象重试&#39; publishAsync()。重试限制是3,所以我希望对externalTeamLibrary.send()进行三次调用。

    但我得到以下错误。

    栈跟踪

    [junit] Testcase: testFunction: Caused an ERROR
    [junit] Retrying failed to complete successfully after 1 attempts.
    [junit] com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 1 attempts.
    [junit]     at com.github.rholder.retry.Retryer.call(Retryer.java:181)
    [junit]     at UserClass.publish
    [junit]     at TestClass.testFunction
    [junit] Caused by: org.apache.kafka.common.errors.InterruptException: test1
    [junit]     at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:46)
    [junit]     at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
    [junit]     at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
    [junit]     at externalTeamLibrary$$EnhancerByCGLIB$$f53a1a7e.send(<generated>)
    [junit]     at UserClass.publishAsync(line:175)
    [junit]     at UserClass.lambda$publish$1(lineZ:209)
    [junit]     at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78)
    [junit]     at com.github.rholder.retry.Retryer.call(Retryer.java:160)
    [junit] Caused by: java.lang.InterruptedException
    [junit]     at org.apache.kafka.common.errors.InterruptException.<init>(InterruptException.java:35)
    [junit]     at TestClass.testFunction
    

    在我抛出InterruptException

    的行上发生错误

    更新1

    只是顿悟了。 如果我的外部库模拟抛出org.apache.kafka.common.errors.InterruptException以外的其他内容,则重试失败并显示正确的消息重试3次后无法成功完成。

    但是当我的模拟抛出InterruptException时,第一次尝试后重试失败。两种情况下的失败点都不同。 In the guava retry code。 第174行是用于快乐的情况,其中使用了停止策略。第181行是负面情况,其中InterruptException导致InterruptedException!

    This link表明kafka的InterruptException只是InterruptedException的包装器。 所以真正的问题是如何成功重试它。如果线程在尝试执行任务时被中断,我觉得这是应该重试的,因为我们不确定它是不可恢复的。

0 个答案:

没有答案