diff --git a/src/main/java/io/nats/client/support/NatsRequestCompletableFuture.java b/src/main/java/io/nats/client/support/NatsRequestCompletableFuture.java index 4eab05609..88a18d9a5 100644 --- a/src/main/java/io/nats/client/support/NatsRequestCompletableFuture.java +++ b/src/main/java/io/nats/client/support/NatsRequestCompletableFuture.java @@ -12,7 +12,11 @@ * This is an internal class and is only public for access. */ public class NatsRequestCompletableFuture extends CompletableFuture { + public enum CancelAction { CANCEL, REPORT, COMPLETE } + + private static final String CLOSING_MESSAGE = "Future cancelled, connection closing."; + private static final String CANCEL_MESSAGE = "Future cancelled, response not registered in time, check connection status."; private static final long DEFAULT_TIMEOUT = Options.DEFAULT_REQUEST_CLEANUP_INTERVAL.toMillis(); // currently 5 seconds private final CancelAction cancelAction; @@ -30,19 +34,25 @@ public NatsRequestCompletableFuture(CancelAction cancelAction, Duration timeout, public void cancelClosing() { wasCancelledClosing = true; - completeExceptionally(new CancellationException("Future cancelled, connection closing.")); + completeExceptionally(new CancellationException(CLOSING_MESSAGE)); } public void cancelTimedOut() { wasCancelledTimedOut = true; - final String message = "Future cancelled, response not registered in time, likely due to server disconnect."; - completeExceptionally(useTimeoutException ? new TimeoutException(message) : new CancellationException(message)); + completeExceptionally( + useTimeoutException + ? new TimeoutException(CANCEL_MESSAGE) + : new CancellationException(CANCEL_MESSAGE)); } public CancelAction getCancelAction() { return cancelAction; } + public boolean useTimeoutException() { + return useTimeoutException; + } + public boolean hasExceededTimeout() { return System.currentTimeMillis() > timeOutAfter; } diff --git a/src/test/java/io/nats/client/impl/RequestTests.java b/src/test/java/io/nats/client/impl/RequestTests.java index f87a51960..ca8da444c 100644 --- a/src/test/java/io/nats/client/impl/RequestTests.java +++ b/src/test/java/io/nats/client/impl/RequestTests.java @@ -679,8 +679,9 @@ public void testThrowsEmptySubject() { } @Test - public void testNatsRequestCompletableFuture() throws InterruptedException { - NatsRequestCompletableFuture f = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofHours(-1), true); + public void testNatsRequestCompletableFuture() throws Exception { + // coverage for configuration + NatsRequestCompletableFuture f = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofMillis(-1000), true); assertEquals(CancelAction.CANCEL, f.getCancelAction()); assertTrue(f.hasExceededTimeout()); assertFalse(f.wasCancelledClosing()); @@ -689,17 +690,43 @@ public void testNatsRequestCompletableFuture() throws InterruptedException { f.cancelTimedOut(); // not real use, just testing flags assertTrue(f.wasCancelledClosing()); assertTrue(f.wasCancelledTimedOut()); + assertTrue(f.useTimeoutException()); - f = new NatsRequestCompletableFuture(CancelAction.COMPLETE, Duration.ofHours(-1), true); + f = new NatsRequestCompletableFuture(CancelAction.COMPLETE, Duration.ofNanos(0), true); assertEquals(CancelAction.COMPLETE, f.getCancelAction()); - f = new NatsRequestCompletableFuture(CancelAction.REPORT, Duration.ofHours(-1), true); + f = new NatsRequestCompletableFuture(CancelAction.REPORT, Duration.ofNanos(0), true); assertEquals(CancelAction.REPORT, f.getCancelAction()); // coverage for null timeout f = new NatsRequestCompletableFuture(CancelAction.CANCEL, null, true); Thread.sleep(Options.DEFAULT_REQUEST_CLEANUP_INTERVAL.toMillis() + 100); assertTrue(f.hasExceededTimeout()); + + f = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofNanos(0), false); + assertFalse(f.useTimeoutException()); + + // coverage for behavior + NatsRequestCompletableFuture fcf = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofNanos(0), false); + assertFalse(fcf.useTimeoutException()); + fcf.cancelClosing(); + assertThrows(CancellationException.class, fcf::get); + + NatsRequestCompletableFuture fct = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofNanos(0), true); + assertTrue(fct.useTimeoutException()); + fct.cancelClosing(); + assertThrows(CancellationException.class, fct::get); + + NatsRequestCompletableFuture ftof = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofNanos(0), false); + assertFalse(ftof.useTimeoutException()); + ftof.cancelTimedOut(); + assertThrows(CancellationException.class, ftof::get); + + NatsRequestCompletableFuture ftot = new NatsRequestCompletableFuture(CancelAction.CANCEL, Duration.ofNanos(0), true); + assertTrue(ftot.useTimeoutException()); + ftot.cancelTimedOut(); + ExecutionException ee = assertThrows(ExecutionException.class, ftot::get); + assertTrue(ee.getCause() instanceof TimeoutException); } @Test