Skip to content

Commit

Permalink
8303697: ProcessTools doesn't print last line of process output
Browse files Browse the repository at this point in the history
Reviewed-by: dholmes, stuefe
  • Loading branch information
lmesnik committed Mar 17, 2023
1 parent d5a1507 commit 8d2ebf2
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 5 deletions.
70 changes: 70 additions & 0 deletions test/lib-test/jdk/test/lib/process/ProcessToolsLastLineTest.java
@@ -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);

}

}
}
22 changes: 17 additions & 5 deletions test/lib/jdk/test/lib/process/StreamPumper.java
@@ -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
Expand Down Expand Up @@ -95,13 +95,15 @@ public StreamPumper(InputStream in, OutputStream out) {

/**
* 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;
Expand Down Expand Up @@ -133,6 +135,10 @@ public void run() {

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;
Expand All @@ -143,6 +149,12 @@ public void run() {
}
}

// 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();
Expand Down

1 comment on commit 8d2ebf2

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.