From 996a61cf68a28190d1ec90bd1fa50b7d8199bfa4 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Tue, 10 Mar 2015 20:25:48 +0100 Subject: [PATCH] 8049696: com/sun/jdi/RunToExit fails with "ConnectException: Connection refused" Reviewed-by: sla --- jdk/test/com/sun/jdi/RunToExit.java | 117 +++++++----------- .../jdk/testlibrary/ProcessTools.java | 62 +++++++--- 2 files changed, 91 insertions(+), 88 deletions(-) diff --git a/jdk/test/com/sun/jdi/RunToExit.java b/jdk/test/com/sun/jdi/RunToExit.java index 01a15c85697..f76f4b0b9fa 100644 --- a/jdk/test/com/sun/jdi/RunToExit.java +++ b/jdk/test/com/sun/jdi/RunToExit.java @@ -24,74 +24,29 @@ /* @test * @bug 4997445 * @summary Test that with server=y, when VM runs to System.exit() no error happens - * - * @build VMConnection RunToExit Exit0 + * @library /lib/testlibrary + * @build jdk.testlibrary.* VMConnection RunToExit Exit0 * @run driver RunToExit */ -import java.io.InputStream; -import java.io.IOException; -import java.io.File; -import java.io.BufferedInputStream; import java.net.ServerSocket; import com.sun.jdi.Bootstrap; import com.sun.jdi.VirtualMachine; import com.sun.jdi.event.*; import com.sun.jdi.connect.Connector; import com.sun.jdi.connect.AttachingConnector; +import java.net.ConnectException; import java.util.Map; import java.util.List; import java.util.Iterator; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import jdk.testlibrary.ProcessTools; public class RunToExit { /* Increment this when ERROR: seen */ - static int error_seen = 0; + static volatile int error_seen = 0; static volatile boolean ready = false; - /* - * Helper class to direct process output to a StringBuffer - */ - static class IOHandler implements Runnable { - private String name; - private BufferedInputStream in; - private StringBuffer buffer; - - IOHandler(String name, InputStream in) { - this.name = name; - this.in = new BufferedInputStream(in); - this.buffer = new StringBuffer(); - } - - static void handle(String name, InputStream in) { - IOHandler handler = new IOHandler(name, in); - Thread thr = new Thread(handler); - thr.setDaemon(true); - thr.start(); - } - - public void run() { - try { - byte b[] = new byte[100]; - for (;;) { - int n = in.read(b, 0, 100); - // The first thing that will get read is - // Listening for transport dt_socket at address: xxxxx - // which shows the debuggee is ready to accept connections. - ready = true; - if (n < 0) { - break; - } - buffer.append(new String(b, 0, n)); - } - } catch (IOException ioe) { } - - String str = buffer.toString(); - if ( str.contains("ERROR:") ) { - error_seen++; - } - System.out.println(name + ": " + str); - } - - } /* * Find a connector by name @@ -111,24 +66,40 @@ public class RunToExit { /* * Launch a server debuggee with the given address */ - private static Process launch(String address, String class_name) throws IOException { - String exe = System.getProperty("java.home") - + File.separator + "bin" + File.separator + "java"; - String cmd = exe + " " + VMConnection.getDebuggeeVMOptions() + - " -agentlib:jdwp=transport=dt_socket" + - ",server=y" + ",suspend=y" + ",address=" + address + - " " + class_name; + private static Process launch(String address, String class_name) throws Exception { + String args[] = new String[]{ + "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + + address, + class_name + }; + args = VMConnection.insertDebuggeeVMOptions(args); - System.out.println("Starting: " + cmd); + ProcessBuilder launcher = ProcessTools.createJavaProcessBuilder(args); - Process p = Runtime.getRuntime().exec(cmd); + System.out.println(launcher.command().stream().collect(Collectors.joining(" ", "Starting: ", ""))); - IOHandler.handle("Input Stream", p.getInputStream()); - IOHandler.handle("Error Stream", p.getErrorStream()); + Process p = ProcessTools.startProcess( + class_name, + launcher, + RunToExit::checkForError, + RunToExit::isTransportListening, + 0, + TimeUnit.NANOSECONDS + ); return p; } + private static boolean isTransportListening(String line) { + return line.startsWith("Listening for transport dt_socket"); + } + + private static void checkForError(String line) { + if (line.contains("ERROR:")) { + error_seen++; + } + } + /* * - pick a TCP port * - Launch a server debuggee: server=y,suspend=y,address=${port} @@ -146,15 +117,6 @@ public class RunToExit { // launch the server debuggee Process process = launch(address, "Exit0"); - // wait for the debugge to be ready - while (!ready) { - try { - Thread.sleep(1000); - } catch(Exception ee) { - throw ee; - } - } - // attach to server debuggee and resume it so it can exit AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach"); Map conn_args = conn.defaultArguments(); @@ -164,7 +126,16 @@ public class RunToExit { System.out.println("Connection arguments: " + conn_args); - VirtualMachine vm = conn.attach(conn_args); + VirtualMachine vm = null; + while (vm == null) { + try { + vm = conn.attach(conn_args); + } catch (ConnectException e) { + e.printStackTrace(System.out); + System.out.println("--- Debugee not ready. Retrying in 500ms. ---"); + Thread.sleep(500); + } + } // The first event is always a VMStartEvent, and it is always in // an EventSet by itself. Wait for it. diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java index fedcd91f796..3e88f8887df 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java @@ -88,24 +88,12 @@ public final class ProcessTools { ProcessBuilder processBuilder, Consumer consumer) throws IOException { - Process p = null; try { - p = startProcess( - name, - processBuilder, - line -> { - if (consumer != null) { - consumer.accept(line); - } - return false; - }, - -1, - TimeUnit.NANOSECONDS - ); + return startProcess(name, processBuilder, consumer, null, -1, TimeUnit.NANOSECONDS); } catch (InterruptedException | TimeoutException e) { - // can't ever happen + // will never happen + throw new RuntimeException(e); } - return p; } /** @@ -133,6 +121,38 @@ public final class ProcessTools { final Predicate linePredicate, long timeout, TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, null, linePredicate, timeout, unit); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT and monitor the + * in-streams via the provided {@linkplain Consumer} + *

+ * @param name The process name + * @param processBuilder The process builder + * @param lineConsumer The {@linkplain Consumer} the lines will be forwarded to + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Consumer lineConsumer, + final Predicate linePredicate, + long timeout, + TimeUnit unit) throws IOException, InterruptedException, TimeoutException { System.out.println("["+name+"]:" + processBuilder.command().stream().collect(Collectors.joining(" "))); Process p = processBuilder.start(); @@ -141,6 +161,18 @@ public final class ProcessTools { stdout.addPump(new LineForwarder(name, System.out)); stderr.addPump(new LineForwarder(name, System.err)); + if (lineConsumer != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + lineConsumer.accept(line); + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } + + CountDownLatch latch = new CountDownLatch(1); if (linePredicate != null) { StreamPumper.LinePump pump = new StreamPumper.LinePump() {