public void ackMessageAsync(
        final String addr,
        final long timeOut,
        final AckCallback ackCallback,
        final AckMessageRequestHeader requestHeader
    ) throws RemotingException, MQBrokerException, InterruptedException {
        ackMessageAsync(addr, timeOut, ackCallback, requestHeader, null);
    }
@Test
    public void testAckMessageAsync_Success() throws Exception {
        doAnswer((Answer<Void>) mock -> {
            InvokeCallback callback = mock.getArgument(3);
            RemotingCommand request = mock.getArgument(1);
            ResponseFuture responseFuture = new ResponseFuture(null, request.getOpaque(), 3 * 1000, null, null);
            RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null);
            response.setOpaque(request.getOpaque());
            response.setCode(ResponseCode.SUCCESS);
            responseFuture.setResponseCommand(response);
            callback.operationSucceed(responseFuture.getResponseCommand());
            return null;
        }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));

        final CountDownLatch done = new CountDownLatch(1);
        mqClientAPI.ackMessageAsync(brokerAddr, 10 * 1000, new AckCallback() {
            @Override
            public void onSuccess(AckResult ackResult) {
                assertThat(ackResult.getStatus()).isEqualTo(AckStatus.OK);
                done.countDown();
            }

            @Override
            public void onException(Throwable e) {
                Assertions.fail("want no exception but got one", e);
                done.countDown();
            }
        }, new AckMessageRequestHeader());
        done.await();
    }