Skip to content

Commit

Permalink
[Bug #314] Add tests ensuring proper ThrottledFuture#then callbacks e…
Browse files Browse the repository at this point in the history
…xecution when future is cancelled.
  • Loading branch information
lukaskabc authored and ledsoft committed Nov 20, 2024
1 parent 3f938ec commit 8315b90
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public interface ChainableFuture<T, F extends ChainableFuture<T, F>> extends Fut
* Action is executed no matter if the future is completed successfully, exceptionally or cancelled.
* <p>
* If the future is already completed, it is executed synchronously.
* <p>
* Note that you <b>must</b> use the future passed as the parameter and not the original future object.
* @param action action receiving this future after completion
* @return this future
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ public ThrottledFuture<T> setCachedResult(@Nullable final T cachedResult) {

@Override
public boolean cancel(boolean mayInterruptIfRunning) {
final boolean wasCanceled = isCancelled();
if(!future.cancel(mayInterruptIfRunning)) {
return false;
}

if (task != null) {
if (!wasCanceled && task != null) {
callbackLock.lock();
onCompletion.forEach(c -> c.accept(this));
callbackLock.unlock();
Expand Down Expand Up @@ -268,7 +269,7 @@ public ThrottledFuture<T> then(Consumer<ThrottledFuture<T>> action) {

/**
* @return {@code true} if this future completed
* exceptionally
* exceptionally or was cancelled.
*/
public boolean isCompletedExceptionally() {
return future.isCompletedExceptionally();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,59 @@ void thenActionIsExecutedOnceFutureIsCancelled() {
}

@Test
void thenActionIsExecutedWhenFutureCompletedExceptionally() {
void thenActionIsExecutedOnlyOnceWhenFutureIsCancelled() {
final AtomicInteger executionCount = new AtomicInteger(0);
final ThrottledFuture<?> future = ThrottledFuture.of(() -> null);
future.then(f -> executionCount.incrementAndGet());
assertEquals(0, executionCount.get());
future.cancel(false);
assertEquals(1, executionCount.get());
future.cancel(false);
future.cancel(true);
assertEquals(1, executionCount.get());
}

@Test
void thenActionIsExecutedWhenFutureCompletesExceptionally() {
final AtomicBoolean completed = new AtomicBoolean(false);
final ThrottledFuture<?> future = ThrottledFuture.of(() -> {
throw new RuntimeException();
});
future.then(futureResult -> completed.set(true));
assertFalse(completed.get());
future.run(null);
assertTrue(completed.get());
}

@Test
void isCompletedExceptionallyReturnsTrueWhenFutureCompletesExceptionally() {
final ThrottledFuture<?> future = ThrottledFuture.of(() -> {
throw new RuntimeException();
});
future.run(null);
assertTrue(future.isCompletedExceptionally());
}

@Test
void isCompletedExceptionallyReturnsFalseWhenFutureCompletesNormally() {
final ThrottledFuture<?> future = ThrottledFuture.of(() -> null);
future.run(null);
assertFalse(future.isCompletedExceptionally());
assertFalse(future.isCancelled());
assertTrue(future.isDone());
}

@Test
void isCompletedExceptionallyReturnsTrueWhenFutureIsCancelled() {
final ThrottledFuture<?> future = ThrottledFuture.of(() -> null);
future.cancel(false);
assertTrue(future.isCompletedExceptionally());
assertTrue(future.isCancelled());
assertTrue(future.isDone());
}

@Test
void thenActionIsExecutedWhenFutureIsAlreadyCompletedExceptionally() {
final AtomicBoolean completed = new AtomicBoolean(false);
final ThrottledFuture<?> future = ThrottledFuture.of(() -> {
throw new RuntimeException();
Expand Down

0 comments on commit 8315b90

Please sign in to comment.