8303697: ProcessTools doesn't print last line of process output

Reviewed-by: dholmes, stuefe
This commit is contained in:
Leonid Mesnik 2023-03-17 13:45:41 +00:00
parent d5a150706e
commit 8d2ebf248e
2 changed files with 87 additions and 5 deletions

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8303697
* @summary Test verifies that ProcessTools.startProcess() print all lines even the last line doesn't end with '\n'
* @library /test/lib
* @run main ProcessToolsLastLineTest
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Asserts;
public class ProcessToolsLastLineTest {
static void test(String output) throws Exception {
final StringBuffer sb = new StringBuffer();
Process p = ProcessTools.startProcess("process",
ProcessTools.createJavaProcessBuilder(ProcessToolsLastLineTest.class.getName(), output),
line -> { sb.append(line);});
p.waitFor();
String expectedOutput = output.replace("\n", "");
Asserts.assertEQ(sb.toString(), expectedOutput);
}
public static void main(String[] args) throws Exception {
// The line which exceeds internal StreamPumper buffer (256 bytes)
String VERY_LONG_LINE = "X".repeat(257);
if (args.length > 0) {
System.out.print(args[0]);
} else {
test("\n");
test("\nARG1");
test("\nARG1\n");
test("ARG1\n");
test("ARG1");
test("ARG1\nARG2");
test("ARG1\nARG2\n");
test("\nARG1\nARG2\n");
test("\nARG1\n" + VERY_LONG_LINE + "\nARG2\n");
test("\nARG1\n" + VERY_LONG_LINE);
test("\nARG1\n" + VERY_LONG_LINE + VERY_LONG_LINE + VERY_LONG_LINE + "\nARG2\n");
test("\nARG1\n" + VERY_LONG_LINE + VERY_LONG_LINE + VERY_LONG_LINE);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -95,13 +95,15 @@ public final class StreamPumper implements Runnable {
/**
* Implements Thread.run(). Continuously read from {@code in} and write to
* {@code out} until {@code in} has reached end of stream. Abort on
* interruption. Abort on IOExceptions.
* {@code out} until {@code in} has reached end of stream.
* Additionally this method also splits the data read from the buffer into lines,
* and processes each line using linePumps.
* Abort on interruption. Abort on IOExceptions.
*/
@Override
public void run() {
try (BufferedInputStream is = new BufferedInputStream(in)) {
ByteArrayOutputStream lineBos = new ByteArrayOutputStream();
try (BufferedInputStream is = new BufferedInputStream(in);
ByteArrayOutputStream lineBos = new ByteArrayOutputStream()) {
byte[] buf = new byte[BUF_SIZE];
int len = 0;
int linelen = 0;
@ -133,6 +135,10 @@ public final class StreamPumper implements Runnable {
i++;
}
// If no crlf was found, or there was additional data after the last crlf was found, then write the leftover data
// in lineBos. If there is more data to read it will be concatenated with the current data on the next iteration.
// If there is no more data, or no more crlf found, all the remaining data will be processed after the loop, as the
// final line.
if (lastcrlf == -1) {
lineBos.write(buf, 0, len);
linelen += len;
@ -143,6 +149,12 @@ public final class StreamPumper implements Runnable {
}
}
// If there was no terminating crlf the remaining data has been written to lineBos,
// but this final line of data now needs to be processed by the linePumper.
final String line = lineBos.toString();
if (!line.isEmpty()) {
linePumps.forEach((lp) -> lp.processLine(line));
}
} catch (IOException e) {
if (!e.getMessage().equalsIgnoreCase("stream closed")) {
e.printStackTrace();