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(); /** 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..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 @@ -20,14 +20,43 @@ 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 {