Skip to content

Commit f56f6c9

Browse files
authored
[utils] improve test coverage on FutureUtils (#969)
1 parent 8317092 commit f56f6c9

File tree

2 files changed

+157
-3
lines changed

2 files changed

+157
-3
lines changed

fluss-common/src/test/java/com/alibaba/fluss/utils/concurrent/FutureUtilsTest.java

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,23 @@
2323
import org.junit.jupiter.api.Test;
2424
import org.junit.jupiter.api.extension.RegisterExtension;
2525

26+
import java.util.ArrayList;
2627
import java.util.Arrays;
28+
import java.util.Collection;
29+
import java.util.Collections;
2730
import java.util.List;
2831
import java.util.concurrent.CompletableFuture;
2932
import java.util.concurrent.ExecutionException;
3033
import java.util.concurrent.Executors;
34+
import java.util.concurrent.FutureTask;
3135
import java.util.concurrent.ScheduledExecutorService;
3236
import java.util.concurrent.TimeUnit;
3337
import java.util.concurrent.TimeoutException;
3438
import java.util.concurrent.atomic.AtomicReference;
3539

3640
import static com.alibaba.fluss.testutils.common.FlussAssertions.assertThatFuture;
3741
import static org.assertj.core.api.Assertions.assertThat;
42+
import static org.assertj.core.api.Assertions.assertThatNoException;
3843

3944
/** Tests for the utility methods in {@link FutureUtils}. */
4045
class FutureUtilsTest {
@@ -153,6 +158,11 @@ void testComposeAfterwardsBothExceptional() {
153158

154159
@Test
155160
void testCompleteAll() {
161+
FutureUtils.ConjunctFuture<Void> emptyConjunctFuture =
162+
FutureUtils.completeAll(Collections.emptyList());
163+
assertThatFuture(emptyConjunctFuture).isDone();
164+
assertThatFuture(emptyConjunctFuture).eventuallySucceeds().isNull();
165+
156166
final CompletableFuture<String> inputFuture1 = new CompletableFuture<>();
157167
final CompletableFuture<Integer> inputFuture2 = new CompletableFuture<>();
158168

@@ -389,4 +399,151 @@ void testOrTimeout() {
389399
.withCauseInstanceOf(TimeoutException.class)
390400
.withMessageContaining(expectedErrorMessage);
391401
}
402+
403+
@Test
404+
void testCompletedVoidFuture() {
405+
final CompletableFuture<Void> future = FutureUtils.completedVoidFuture();
406+
assertThatFuture(future).eventuallySucceeds().isNull();
407+
}
408+
409+
@Test
410+
void testCompleteFromCallable() {
411+
final CompletableFuture<String> successFuture = new CompletableFuture<>();
412+
FutureUtils.completeFromCallable(successFuture, () -> "Fluss");
413+
assertThatFuture(successFuture).eventuallySucceeds().isEqualTo("Fluss");
414+
415+
final CompletableFuture<String> failureFuture = new CompletableFuture<>();
416+
FutureUtils.completeFromCallable(
417+
failureFuture,
418+
() -> {
419+
throw new RuntimeException("mock runtime exception");
420+
});
421+
assertThatFuture(failureFuture)
422+
.eventuallyFailsWith(ExecutionException.class)
423+
.withCauseInstanceOf(RuntimeException.class)
424+
.withMessageContaining("mock runtime exception");
425+
}
426+
427+
@Test
428+
void testRunIfNotDoneAndGet() throws Exception {
429+
FutureUtils.runIfNotDoneAndGet(null);
430+
List<String> list = new ArrayList<>();
431+
Runnable task = () -> list.add("Fluss");
432+
FutureTask<String> futureTask = new FutureTask<>(task, "Hello Fluss");
433+
FutureUtils.runIfNotDoneAndGet(futureTask);
434+
assertThat(futureTask.get()).isEqualTo("Hello Fluss");
435+
assertThat(list.contains("Fluss")).isTrue();
436+
}
437+
438+
@Test
439+
void combineAll() throws Exception {
440+
FutureUtils.ConjunctFuture<Collection<String>> emptyConjunctFuture =
441+
FutureUtils.combineAll(Collections.emptyList());
442+
assertThatFuture(emptyConjunctFuture).isDone();
443+
assertThatFuture(emptyConjunctFuture).eventuallySucceeds().asList().isEmpty();
444+
445+
CompletableFuture<String> future1 = new CompletableFuture<String>();
446+
CompletableFuture<String> future2 = new CompletableFuture<String>();
447+
FutureUtils.ConjunctFuture<Collection<String>> conjunctFuture =
448+
FutureUtils.combineAll(Arrays.asList(future1, future2));
449+
450+
assertThatFuture(conjunctFuture).isNotDone();
451+
assertThat(conjunctFuture.getNumFuturesTotal()).isEqualTo(2);
452+
assertThat(conjunctFuture.getNumFuturesCompleted()).isZero();
453+
454+
future1.complete("Hello");
455+
future2.complete("World");
456+
assertThatFuture(conjunctFuture).eventuallySucceeds();
457+
458+
assertThatFuture(conjunctFuture).isDone();
459+
assertThat(conjunctFuture.getNumFuturesTotal()).isEqualTo(2);
460+
assertThat(conjunctFuture.getNumFuturesCompleted()).isEqualTo(2);
461+
assertThat(conjunctFuture.get()).containsExactly("Hello", "World");
462+
463+
CompletableFuture<String> successFuture = new CompletableFuture<String>();
464+
CompletableFuture<String> failureFuture = new CompletableFuture<String>();
465+
FutureUtils.ConjunctFuture<Collection<String>> failureConjunctFuture =
466+
FutureUtils.combineAll(Arrays.asList(successFuture, failureFuture));
467+
468+
failureFuture.completeExceptionally(new RuntimeException("mock runtime exception"));
469+
470+
assertThatFuture(failureConjunctFuture).isDone();
471+
assertThatFuture(failureConjunctFuture)
472+
.eventuallyFailsWith(ExecutionException.class)
473+
.withCauseInstanceOf(RuntimeException.class)
474+
.withMessageContaining("mock runtime exception");
475+
}
476+
477+
@Test
478+
void testWaitForAll() {
479+
FutureUtils.ConjunctFuture<Void> emptyConjunctFuture =
480+
FutureUtils.waitForAll(Collections.emptyList());
481+
assertThatFuture(emptyConjunctFuture).isDone();
482+
assertThatFuture(emptyConjunctFuture).eventuallySucceeds().isNull();
483+
484+
List<String> successRes = new ArrayList<>();
485+
CompletableFuture<String> future1 = new CompletableFuture<String>();
486+
CompletableFuture<String> future2 = new CompletableFuture<String>();
487+
FutureUtils.ConjunctFuture<Void> conjunctFuture =
488+
FutureUtils.waitForAll(
489+
Arrays.asList(future1, future2),
490+
(val, throwable) -> {
491+
if (throwable == null) {
492+
successRes.add(val);
493+
} else {
494+
throw new RuntimeException(throwable);
495+
}
496+
});
497+
498+
assertThatFuture(conjunctFuture).isNotDone();
499+
assertThat(conjunctFuture.getNumFuturesTotal()).isEqualTo(2);
500+
assertThat(conjunctFuture.getNumFuturesCompleted()).isZero();
501+
502+
future1.complete("Hello");
503+
future2.complete("World");
504+
assertThatFuture(conjunctFuture).eventuallySucceeds();
505+
assertThatFuture(conjunctFuture).isDone();
506+
assertThat(conjunctFuture.getNumFuturesTotal()).isEqualTo(2);
507+
assertThat(conjunctFuture.getNumFuturesCompleted()).isEqualTo(2);
508+
509+
assertThat(successRes.size()).isEqualTo(2);
510+
assertThat(successRes.contains("Hello")).isTrue();
511+
assertThat(successRes.contains("World")).isTrue();
512+
513+
List<String> failureRes = new ArrayList<>();
514+
CompletableFuture<String> successFuture = new CompletableFuture<String>();
515+
CompletableFuture<String> failureFuture = new CompletableFuture<String>();
516+
FutureUtils.ConjunctFuture<Void> failureConjunctFuture =
517+
FutureUtils.waitForAll(
518+
Arrays.asList(successFuture, failureFuture),
519+
(val, throwable) -> {
520+
if (throwable == null) {
521+
failureRes.add(val);
522+
} else {
523+
throw new RuntimeException(throwable);
524+
}
525+
});
526+
527+
failureFuture.completeExceptionally(new RuntimeException("mock runtime exception"));
528+
529+
assertThatFuture(failureConjunctFuture).isDone();
530+
assertThat(conjunctFuture.getNumFuturesTotal()).isEqualTo(2);
531+
assertThat(conjunctFuture.getNumFuturesCompleted()).isEqualTo(2);
532+
assertThatFuture(failureConjunctFuture)
533+
.eventuallyFailsWith(ExecutionException.class)
534+
.withCauseInstanceOf(RuntimeException.class)
535+
.withMessageContaining("mock runtime exception");
536+
assertThat(failureRes.isEmpty()).isTrue();
537+
}
538+
539+
@Test
540+
void testCatchingAndLoggingThrowables() {
541+
Runnable task =
542+
() -> {
543+
throw new RuntimeException("mock runtime exception");
544+
};
545+
546+
Runnable catchingRunnable = FutureUtils.catchingAndLoggingThrowables(task);
547+
assertThatNoException().isThrownBy(catchingRunnable::run);
548+
}
392549
}

fluss-test-coverage/pom.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,6 @@
249249
<exclude>com.alibaba.fluss.memory.*</exclude>
250250
<exclude>com.alibaba.fluss.utils.*</exclude>
251251
<exclude>com.alibaba.fluss.exception.*</exclude>
252-
<exclude>
253-
com.alibaba.fluss.utils.concurrent.FutureUtils.Timeout
254-
</exclude>
255252
<exclude>com.alibaba.fluss.row.arrow.*</exclude>
256253
<exclude>
257254
com.alibaba.fluss.row.columnar.BytesColumnVector.Bytes

0 commit comments

Comments
 (0)