SchedulerImpl implements Scheduler { @Override public <T> ScheduledCompletableFuture<T> before(CompletableFuture<T> promise, Duration timeout) { final AtomicBoolean done = new AtomicBoolean(); final Consumer<Runnable> runOnce = runnable -> { if (!done.getAndSet(true)) { runnable.run(); } }; final ScheduledCompletableFutureOnce<T> wrappedPromise = new ScheduledCompletableFutureOnce<>(); Callable<T> callable = () -> { wrappedPromise.completeExceptionally(new TimeoutException()); return null; }; final ScheduledCompletableFutureOnce<T> afterPromise = afterInternal(wrappedPromise, callable, timeout); wrappedPromise.exceptionally(e -> { if (e instanceof CancellationException) { afterPromise.cancel(true); } return null; }); promise.thenAccept(p -> runOnce.accept(() -> wrappedPromise.complete(p))) .exceptionally(ex -> { runOnce.accept(() -> wrappedPromise.completeExceptionally(ex)); return null; }); return wrappedPromise; }  @Override ScheduledCompletableFuture<Instant> after(Duration duration); @Override ScheduledCompletableFuture<T> after(Callable<T> callable, Duration duration); @Override ScheduledCompletableFuture<T> before(CompletableFuture<T> promise, Duration timeout); @Override ScheduledCompletableFuture<Instant> at(Instant instant); @Override ScheduledCompletableFuture<T> at(Callable<T> callable, Instant instant); @Override ScheduledCompletableFuture<T> schedule(SchedulerRunnable runnable, TemporalAdjuster temporalAdjuster);  }
@Test @Timeout(value = 300, unit = TimeUnit.MILLISECONDS) public void testBeforeTimeoutException() throws Throwable { CompletableFuture<Integer> d = new CompletableFuture<>(); ScheduledCompletableFuture<Integer> before = scheduler.before(d, Duration.ofMillis(100)); Thread.sleep(200); d.complete(3); d.get(); assertTrue(before.isDone(), "Scheduled job should be done"); assertTrue(before.getPromise().isCompletedExceptionally(), "Before CompletableFuture should have completed with an exception"); assertThrows(TimeoutException.class, () -> { try { before.get(); } catch (ExecutionException e) { throw e.getCause(); } }); }
@Test @Timeout(value = 300, unit = TimeUnit.MILLISECONDS) public void testBeforeCancelled() throws InterruptedException, InvocationTargetException, ExecutionException { CompletableFuture<Integer> d = new CompletableFuture<>(); ScheduledCompletableFuture<Integer> before = scheduler.before(d, Duration.ofMillis(100)); before.cancel(true); assertTrue(before.getPromise().isCompletedExceptionally(), "Scheduled job cancelled before timeout"); assertThrows(CancellationException.class, () -> { before.get(); }); }
@Test @Timeout(value = 300, unit = TimeUnit.MILLISECONDS) public void testBeforeResolved() throws InterruptedException, ExecutionException { CompletableFuture<Boolean> d = new CompletableFuture<>(); ScheduledCompletableFuture<Boolean> before = scheduler.before(d, Duration.ofMillis(100)); d.complete(Boolean.TRUE); assertTrue(before.isDone(), "Scheduled job should finish done"); assertTrue(before.get(), "Before CompletableFuture should return correct value"); }
@Test @Timeout(value = 300, unit = TimeUnit.MILLISECONDS) public void testBeforeResolvedWithException() throws Throwable { CompletableFuture<Integer> d = new CompletableFuture<>(); ScheduledCompletableFuture<Integer> before = scheduler.before(d, Duration.ofMillis(100)); d.completeExceptionally(new FileNotFoundException("testBeforeTimeoutException")); assertTrue(before.isDone(), "Scheduled job should be done"); assertTrue(before.getPromise().isCompletedExceptionally(), "Before CompletableFuture should have completed with an exception"); assertThrows(FileNotFoundException.class, () -> { try { before.get(); } catch (ExecutionException e) { throw e.getCause(); } }); }
@Test @Timeout(value = 300, unit = TimeUnit.MILLISECONDS) public void testAfterTimeoutException() throws Throwable { CompletableFuture<Integer> d = new CompletableFuture<>(); ScheduledCompletableFuture<Integer> before = scheduler.before(d, Duration.ofMillis(100)); Thread.sleep(200); d.complete(3); d.get(); assertTrue(before.isDone(), "Scheduled job should be done"); assertTrue(before.getPromise().isCompletedExceptionally(), "Before CompletableFuture should have completed with an exception"); assertThrows(TimeoutException.class, () -> { try { before.get(); } catch (ExecutionException e) { throw e.getCause(); } }); }