From 01ce767d82875f4a2285bea28b9201c281e97a07 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 1 Jul 2026 08:42:09 -0400 Subject: [PATCH 1/3] Add test: StreamPollFeeder with continuous data input --- .../utils/cli/StreamPollFeederTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java b/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java index e1c24758..d2b4f3f3 100644 --- a/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java +++ b/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java @@ -20,14 +20,45 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.time.Duration; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; public class StreamPollFeederTest { + @Test + public void waitUntilFeederDoneWithContinuousData() { + // Simulates a stream with continuous data where the feeder thread + // never enters the synchronized(lock) wait block, so the done + // flag must be visible without relying on lock's happens-before. + InputStream continuousInput = new InputStream() { + @Override + public int available() { + return 1; + } + + @Override + public int read() throws IOException { + return 0; + } + }; + + assertTimeoutPreemptively( + Duration.ofSeconds(5), + () -> { + StreamPollFeeder feeder = new StreamPollFeeder(continuousInput, new ByteArrayOutputStream()); + feeder.start(); + feeder.waitUntilDone(); + assertNull(feeder.getException()); + }); + } + @Test public void waitUntilFeederDoneOnInputStream() throws Exception { From c7e8d3aa7f87648e94bf1b88d5815c63d28faec6 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 1 Jul 2026 08:42:30 -0400 Subject: [PATCH 2/3] StreamPollFeeder: declare done and exception as volatile --- .../org/apache/maven/shared/utils/cli/StreamPollFeeder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java b/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java index 72b16a8c..02c36a74 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java @@ -35,9 +35,9 @@ class StreamPollFeeder extends Thread { private final InputStream input; private final OutputStream output; - private Throwable exception; + private volatile Throwable exception; - private boolean done; + private volatile boolean done; private final Object lock = new Object(); /** From cf467a8bd0514c26caf3592f8fd74f430d564014 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 1 Jul 2026 09:01:58 -0400 Subject: [PATCH 3/3] spotless:apply formatting --- .../shared/utils/cli/StreamPollFeederTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java b/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java index d2b4f3f3..052092df 100644 --- a/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java +++ b/src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java @@ -49,14 +49,12 @@ public int read() throws IOException { } }; - assertTimeoutPreemptively( - Duration.ofSeconds(5), - () -> { - StreamPollFeeder feeder = new StreamPollFeeder(continuousInput, new ByteArrayOutputStream()); - feeder.start(); - feeder.waitUntilDone(); - assertNull(feeder.getException()); - }); + assertTimeoutPreemptively(Duration.ofSeconds(5), () -> { + StreamPollFeeder feeder = new StreamPollFeeder(continuousInput, new ByteArrayOutputStream()); + feeder.start(); + feeder.waitUntilDone(); + assertNull(feeder.getException()); + }); } @Test