From 64ac9a05e85020d24e33ba55cffa1bd9b269218a Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 4 May 2023 01:10:54 +0000 Subject: [PATCH] 8306946: jdk/test/lib/process/ProcessToolsStartProcessTest.java fails with "wrong number of lines in OutputAnalyzer output" Reviewed-by: dholmes --- .../process/ProcessToolsStartProcessTest.java | 49 ++++++++----------- .../jdk/test/lib/process/ProcessTools.java | 30 ++++++++++-- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/test/lib-test/jdk/test/lib/process/ProcessToolsStartProcessTest.java b/test/lib-test/jdk/test/lib/process/ProcessToolsStartProcessTest.java index 7ba339918c5..02c10c61066 100644 --- a/test/lib-test/jdk/test/lib/process/ProcessToolsStartProcessTest.java +++ b/test/lib-test/jdk/test/lib/process/ProcessToolsStartProcessTest.java @@ -38,21 +38,21 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; public class ProcessToolsStartProcessTest { - static final int NUM_LINES = 50; static String output = ""; private static Consumer outputConsumer = s -> { output += s + "\n"; }; - static boolean testStartProcess(boolean withConsumer) throws Exception { + static boolean testStartProcess(int numOfLines, boolean withConsumer) throws Exception { boolean success = true; + output = ""; Process p; JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("java"); launcher.addToolArg("-cp"); launcher.addToolArg(Utils.TEST_CLASSES); launcher.addToolArg("ProcessToolsStartProcessTest"); - launcher.addToolArg("test"); // This one argument triggers producing the output + launcher.addToolArg(Integer.toString(numOfLines)); ProcessBuilder pb = new ProcessBuilder(); pb.command(launcher.getCommand()); @@ -73,49 +73,40 @@ public class ProcessToolsStartProcessTest { if (withConsumer) { int numLines = output.split("\n").length; - if (numLines != NUM_LINES ) { + if (numLines != numOfLines) { System.out.print("FAILED: wrong number of lines in Consumer output\n"); success = false; + System.out.print(output); } - System.out.println("DEBUG: Consumer output: got " + numLines + " lines , expected " - + NUM_LINES + ". Output follow:"); - System.out.print(output); - System.out.println("DEBUG: done with Consumer output."); } int numLinesOut = out.getStdout().split("\n").length; - if (numLinesOut != NUM_LINES) { + if (numLinesOut != numOfLines) { System.out.print("FAILED: wrong number of lines in OutputAnalyzer output\n"); + System.out.print(out.getStdout()); success = false; } - System.out.println("DEBUG: OutputAnalyzer output: got " + numLinesOut + " lines, expected " - + NUM_LINES + ". Output follows:"); - System.out.print(out.getStdout()); - System.out.println("DEBUG: done with OutputAnalyzer stdout."); return success; } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { if (args.length > 0) { - for (int i = 0; i < NUM_LINES; i++) { - System.out.println("A line on stdout " + i); + int iter = Integer.parseInt(args[0]); + for (int i = 0; i < iter; i++) { + System.out.println("A line on stdout: " + i + " " + ".".repeat(i)); } } else { - try { - boolean test1Result = testStartProcess(false); - boolean test2Result = testStartProcess(true); - if (!test1Result || !test2Result) { - throw new RuntimeException("One or more tests failed. See output for details."); + for (int i = 1; i < 5; i++) { + System.out.println("ITERATION " + i); + boolean test1Result = testStartProcess(i * 10 + i, false); + if (!test1Result) { + throw new RuntimeException("First test (no consumer) failed. See output for details."); + } + boolean test2Result = testStartProcess(i * 10 + i, true); + if (!test2Result) { + throw new RuntimeException("Second test (with consumer) failed. See output for details."); } - } catch (RuntimeException re) { - re.printStackTrace(); - System.out.println("Test ERROR"); - throw re; - } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Test ERROR"); - throw new RuntimeException(ex); } } } diff --git a/test/lib/jdk/test/lib/process/ProcessTools.java b/test/lib/jdk/test/lib/process/ProcessTools.java index 2e3d670a8f8..b6669e75364 100644 --- a/test/lib/jdk/test/lib/process/ProcessTools.java +++ b/test/lib/jdk/test/lib/process/ProcessTools.java @@ -48,6 +48,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -116,7 +117,7 @@ public final class ProcessTools { throws IOException { try { return startProcess(name, processBuilder, consumer, null, -1, TimeUnit.NANOSECONDS); - } catch (InterruptedException | TimeoutException e) { + } catch (InterruptedException | TimeoutException | CancellationException e) { // will never happen throw new RuntimeException(e); } @@ -158,23 +159,38 @@ public final class ProcessTools { BufferOutputStream and BufferInputStream allow to re-use p.getInputStream() amd p.getOutputStream() of processes started with ProcessTools.startProcess(...). Implementation cashes ALL process output and allow to read it through InputStream. + The stream uses Future task from StreamPumper.process() to check if output is complete. */ private static class BufferOutputStream extends ByteArrayOutputStream { private int current = 0; final private Process p; + private Future task; + public BufferOutputStream(Process p) { this.p = p; } + synchronized void setTask(Future task) { + this.task = task; + } synchronized int readNext() { if (current > count) { throw new RuntimeException("Shouldn't ever happen. start: " + current + " count: " + count + " buffer: " + this); } while (current == count) { - if (!p.isAlive()) { - return -1; + if (!p.isAlive() && (task != null)) { + try { + task.get(10, TimeUnit.MILLISECONDS); + if (current == count) { + return -1; + } + } catch (TimeoutException e) { + // continue execution, so wait() give a chance to write + } catch (InterruptedException | ExecutionException e) { + return -1; + } } try { wait(1); @@ -194,7 +210,7 @@ public final class ProcessTools { buffer = new BufferOutputStream(p); } - OutputStream getOutputStream() { + BufferOutputStream getOutputStream() { return buffer; } @@ -242,6 +258,8 @@ public final class ProcessTools { stdout.addPump(new LineForwarder(name, System.out)); stderr.addPump(new LineForwarder(name, System.err)); + + BufferInputStream stdOut = new BufferInputStream(p); BufferInputStream stdErr = new BufferInputStream(p); @@ -259,7 +277,6 @@ public final class ProcessTools { stderr.addPump(pump); } - CountDownLatch latch = new CountDownLatch(1); if (linePredicate != null) { StreamPumper.LinePump pump = new StreamPumper.LinePump() { @@ -282,6 +299,9 @@ public final class ProcessTools { final Future stdoutTask = stdout.process(); final Future stderrTask = stderr.process(); + stdOut.getOutputStream().setTask(stdoutTask); + stdErr.getOutputStream().setTask(stderrTask); + try { if (timeout > -1) {