8146015: JMXInterfaceBindingTest is failing intermittently for IPv6 addresses
authorjbachorik
Thu, 14 Jan 2016 09:49:42 +0100
changeset 35615 4df484cc4761
parent 35614 be6538e71881
child 35616 533fa4499540
8146015: JMXInterfaceBindingTest is failing intermittently for IPv6 addresses Reviewed-by: dfuchs, sspitsyn
jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java
jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java
--- a/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java	Wed Jan 06 02:31:59 2016 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java	Thu Jan 14 09:49:42 2016 +0100
@@ -130,7 +130,7 @@
 
     private static class JMXConnectorThread extends Thread {
 
-        private final InetAddress addr;
+        private final String addr;
         private final int jmxPort;
         private final int rmiPort;
         private final boolean useSSL;
@@ -139,7 +139,7 @@
         private boolean jmxConnectWorked;
         private boolean rmiConnectWorked;
 
-        private JMXConnectorThread(InetAddress addr,
+        private JMXConnectorThread(String addr,
                                    int jmxPort,
                                    int rmiPort,
                                    boolean useSSL,
@@ -163,11 +163,11 @@
         private void connect() throws IOException {
             System.out.println(
                     "JMXConnectorThread: Attempting JMX connection on: "
-                            + addr.getHostAddress() + " on port " + jmxPort);
+                            + addr + " on port " + jmxPort);
             JMXServiceURL url;
             try {
                 url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"
-                        + addr.getHostAddress() + ":" + jmxPort + "/jmxrmi");
+                        + addr + ":" + jmxPort + "/jmxrmi");
             } catch (MalformedURLException e) {
                 throw new RuntimeException("Test failed.", e);
             }
@@ -200,7 +200,7 @@
             }
             System.out.println(
                     "JMXConnectorThread: connection to rmi socket worked host/port = "
-                            + addr.getHostAddress() + "/" + rmiPort);
+                            + addr + "/" + rmiPort);
             rmiConnectWorked = true;
             // Closing the channel without sending any data will cause an
             // java.io.EOFException on the server endpoint. We don't care about this
@@ -224,7 +224,7 @@
     private static class MainThread extends Thread {
 
         private static final int WAIT_FOR_JMX_AGENT_TIMEOUT_MS = 500;
-        private final InetAddress bindAddress;
+        private final String addr;
         private final int jmxPort;
         private final int rmiPort;
         private final boolean useSSL;
@@ -233,7 +233,7 @@
         private Exception excptn;
 
         private MainThread(InetAddress bindAddress, int jmxPort, int rmiPort, boolean useSSL) {
-            this.bindAddress = bindAddress;
+            this.addr = wrapAddress(bindAddress.getHostAddress());
             this.jmxPort = jmxPort;
             this.rmiPort = rmiPort;
             this.useSSL = useSSL;
@@ -259,7 +259,7 @@
         private void waitUntilReadyForConnections() {
             CountDownLatch latch = new CountDownLatch(1);
             JMXConnectorThread connectionTester = new JMXConnectorThread(
-                    bindAddress, jmxPort, rmiPort, useSSL, latch);
+                    addr, jmxPort, rmiPort, useSSL, latch);
             connectionTester.start();
             boolean expired = false;
             try {
@@ -294,4 +294,13 @@
         }
     }
 
+    /**
+     * Will wrap IPv6 address in '[]'
+     */
+    static String wrapAddress(String address) {
+        if (address.contains(":")) {
+            return "[" + address + "]";
+        }
+        return address;
+    }
 }
--- a/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java	Wed Jan 06 02:31:59 2016 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java	Thu Jan 14 09:49:42 2016 +0100
@@ -23,9 +23,11 @@
 
 import java.io.File;
 import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.net.NetworkInterface;
+import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import jdk.testlibrary.ProcessThread;
 import jdk.testlibrary.ProcessTools;
@@ -72,25 +74,28 @@
                                                 "truststore";
     public static final String TEST_CLASSPATH = System.getProperty("test.classes", ".");
 
-    public void run(InetAddress[] addrs) {
+    public void run(List<InetAddress> addrs) {
         System.out.println("DEBUG: Running tests with plain sockets.");
         runTests(addrs, false);
         System.out.println("DEBUG: Running tests with SSL sockets.");
         runTests(addrs, true);
     }
 
-    private void runTests(InetAddress[] addrs, boolean useSSL) {
-        ProcessThread[] jvms = new ProcessThread[addrs.length];
-        for (int i = 0; i < addrs.length; i++) {
+    private void runTests(List<InetAddress> addrs, boolean useSSL) {
+        List<ProcessThread> jvms = new ArrayList<>(addrs.size());
+        int i = 1;
+        for (InetAddress addr : addrs) {
+            String address = JMXAgentInterfaceBinding.wrapAddress(addr.getHostAddress());
             System.out.println();
             String msg = String.format("DEBUG: Launching java tester for triplet (HOSTNAME,JMX_PORT,RMI_PORT) == (%s,%d,%d)",
-                    addrs[i].getHostAddress(),
+                    address,
                     JMX_PORT,
                     RMI_PORT);
             System.out.println(msg);
-            jvms[i] = runJMXBindingTest(addrs[i], useSSL);
-            jvms[i].start();
-            System.out.println("DEBUG: Started " + (i + 1) + " Process(es).");
+            ProcessThread jvm = runJMXBindingTest(address, useSSL);
+            jvms.add(jvm);
+            jvm.start();
+            System.out.println("DEBUG: Started " + (i++) + " Process(es).");
         }
         int failedProcesses = 0;
         for (ProcessThread pt: jvms) {
@@ -117,15 +122,15 @@
             }
         }
         if (failedProcesses > 0) {
-            throw new RuntimeException("Test FAILED. " + failedProcesses + " out of " + addrs.length + " process(es) failed to start the JMX agent.");
+            throw new RuntimeException("Test FAILED. " + failedProcesses + " out of " + addrs.size() + " process(es) failed to start the JMX agent.");
         }
     }
 
-    private ProcessThread runJMXBindingTest(InetAddress a, boolean useSSL) {
+    private ProcessThread runJMXBindingTest(String address, boolean useSSL) {
         List<String> args = new ArrayList<>();
         args.add("-classpath");
         args.add(TEST_CLASSPATH);
-        args.add("-Dcom.sun.management.jmxremote.host=" + a.getHostAddress());
+        args.add("-Dcom.sun.management.jmxremote.host=" + address);
         args.add("-Dcom.sun.management.jmxremote.port=" + JMX_PORT);
         args.add("-Dcom.sun.management.jmxremote.rmi.port=" + RMI_PORT);
         args.add("-Dcom.sun.management.jmxremote.authenticate=false");
@@ -138,14 +143,14 @@
             args.add("-Djavax.net.ssl.trustStorePassword=trustword");
         }
         args.add(TEST_CLASS);
-        args.add(a.getHostAddress());
+        args.add(address);
         args.add(Integer.toString(JMX_PORT));
         args.add(Integer.toString(RMI_PORT));
         args.add(Boolean.toString(useSSL));
         try {
             ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(args.toArray(new String[] {}));
             System.out.println(ProcessTools.getCommandLine(builder));
-            ProcessThread jvm = new ProcessThread("JMX-Tester-" + a.getHostAddress(), JMXInterfaceBindingTest::isJMXAgentResponseAvailable, builder);
+            ProcessThread jvm = new ProcessThread("JMX-Tester-" + address, JMXInterfaceBindingTest::isJMXAgentResponseAvailable, builder);
             return jvm;
         } catch (Exception e) {
             throw new RuntimeException("Test failed", e);
@@ -171,8 +176,8 @@
     }
 
     public static void main(String[] args) {
-        InetAddress[] addrs = getAddressesForLocalHost();
-        if (addrs.length < 2) {
+        List<InetAddress> addrs = getAddressesForLocalHost();
+        if (addrs.size() < 2) {
             System.out.println("Ignoring manual test since no more than one IPs are configured for 'localhost'");
             return;
         }
@@ -181,13 +186,24 @@
         System.out.println("All tests PASSED.");
     }
 
-    private static InetAddress[] getAddressesForLocalHost() {
-        InetAddress[] addrs;
+    private static List<InetAddress> getAddressesForLocalHost() {
+
         try {
-            addrs = InetAddress.getAllByName("localhost");
-        } catch (UnknownHostException e) {
+            return NetworkInterface.networkInterfaces()
+                .flatMap(NetworkInterface::inetAddresses)
+                .filter(JMXInterfaceBindingTest::isNonloopbackLocalhost)
+                .collect(Collectors.toList());
+        } catch (SocketException e) {
             throw new RuntimeException("Test failed", e);
         }
-        return addrs;
+    }
+
+    // we need 'real' localhost addresses only (eg. not loopback ones)
+    // so we can bind the remote JMX connector to them
+    private static boolean isNonloopbackLocalhost(InetAddress i) {
+        if (!i.isLoopbackAddress()) {
+            return i.getHostName().toLowerCase().equals("localhost");
+        }
+        return false;
     }
 }