Skip to content
Merged
Prev Previous commit
Next Next commit
Fix flaky optional_spec111 TCK multicast test
The test subscribes 3 subscribers to the same publisher and asserts
all receive elements in the same order. With a new single-thread
executor per mapping call, each CF ran on its own thread, making
delivery order depend on thread scheduling. Sometimes elements
arrived in order (test passed), sometimes not (assertion failed,
caught by TCK, converted to skip).

Use a shared single-thread executor per publisher (matching the
pattern already used by the Ordered publisher variants) so CFs
complete sequentially in submission order. The test now
deterministically passes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • Loading branch information
andimarek and claude committed Mar 6, 2026
commit 4936a15a319bd8b5b2ca4c5172ffedc89567a65e
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;

Expand Down Expand Up @@ -50,6 +51,7 @@ public boolean skipStochasticTests() {

@NonNull
private static Function<Integer, CompletionStage<String>> mapperFunc() {
ExecutorService executor = Executors.newSingleThreadExecutor();
return i -> CompletableFuture.supplyAsync(() -> {
int ms = rand(0, 5);
try {
Expand All @@ -58,7 +60,7 @@ private static Function<Integer, CompletionStage<String>> mapperFunc() {
throw new RuntimeException(e);
}
return i + "!";
}, Executors.newSingleThreadExecutor());
}, executor);
}

static Random rn = new Random();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;

Expand All @@ -32,14 +33,16 @@ public long maxElementsFromPublisher() {
@Override
public Publisher<String> createPublisher(long elements) {
Publisher<Integer> publisher = Flowable.range(0, (int) elements);
Function<Integer, CompletionStage<String>> mapper = i -> CompletableFuture.supplyAsync(() -> i + "!", Executors.newSingleThreadExecutor());
ExecutorService executor = Executors.newSingleThreadExecutor();
Function<Integer, CompletionStage<String>> mapper = i -> CompletableFuture.supplyAsync(() -> i + "!", executor);
return new CompletionStageMappingPublisher<>(publisher, mapper);
}

@Override
public Publisher<String> createFailedPublisher() {
Publisher<Integer> publisher = Flowable.error(() -> new RuntimeException("Bang"));
Function<Integer, CompletionStage<String>> mapper = i -> CompletableFuture.supplyAsync(() -> i + "!", Executors.newSingleThreadExecutor());
ExecutorService executor = Executors.newSingleThreadExecutor();
Function<Integer, CompletionStage<String>> mapper = i -> CompletableFuture.supplyAsync(() -> i + "!", executor);
return new CompletionStageMappingPublisher<>(publisher, mapper);
}

Expand Down