diff --git a/integration/src/test/java/io/github/dfa1/vortex/integration/RaincloudConformanceIntegrationTest.java b/integration/src/test/java/io/github/dfa1/vortex/integration/RaincloudConformanceIntegrationTest.java index 18f62862..d349559d 100644 --- a/integration/src/test/java/io/github/dfa1/vortex/integration/RaincloudConformanceIntegrationTest.java +++ b/integration/src/test/java/io/github/dfa1/vortex/integration/RaincloudConformanceIntegrationTest.java @@ -18,6 +18,7 @@ import org.opentest4j.TestAbortedException; import java.io.BufferedReader; +import java.io.Closeable; import java.io.IOException; import java.io.PipedReader; import java.io.PipedWriter; @@ -122,6 +123,14 @@ private static void assertMatchesParquetOracle(Path vortex, Path parquet) throws assertFilesMatch(vortexReader, oracleReader); } catch (Throwable t) { mainError = t; + } finally { + // assertFilesMatch may stop reading early (oracle abort, line mismatch) while a + // producer is still writing — closing the read end here, rather than relying on + // the outer try-with-resources (which only runs after join() below), unblocks a + // producer parked on a full PipedWriter buffer with a "Pipe closed" IOException + // instead of hanging join() forever (#259). + closeQuietly(vortexReader); + closeQuietly(oracleReader); } try { @@ -173,6 +182,18 @@ private static void assertMatchesParquetOracle(Path vortex, Path parquet) throws } } + /// Closes a stream ignoring the outcome, used only to unblock a producer thread + /// parked writing to the other end of a pipe before joining it. + /// + /// @param closeable the stream to close + private static void closeQuietly(Closeable closeable) { + try { + closeable.close(); + } catch (IOException ignored) { + // best effort: only used to unblock a producer thread before join() + } + } + /// Runs the full conformance check but reports the outcome as an aborted test /// either way: only triaged matrix entries may count as green or red. The abort /// message says which way to flip the entry.