Path: blob/master/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java
41153 views
/*1* Copyright (c) 2015, Red Hat Inc2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.File;24import java.io.PrintWriter;25import java.net.InetAddress;26import java.net.UnknownHostException;27import java.util.ArrayList;28import java.util.List;29import java.util.concurrent.CountDownLatch;3031import jdk.test.lib.process.OutputAnalyzer;32import jdk.test.lib.process.ProcessTools;3334/**35* @test36* @bug 642576937* @summary Test JMX agent host address binding. Same ports but different38* interfaces to bind to (selecting plain or SSL sockets at random)39*40* @library /test/lib41* @modules java.management.rmi42*43* @build JMXAgentInterfaceBinding44* @run main/timeout=60 JMXInterfaceBindingTest45*/46public class JMXInterfaceBindingTest {4748public static final int COMMUNICATION_ERROR_EXIT_VAL = 1;49public static final int STOP_PROCESS_EXIT_VAL = 10;50public static final int JMX_PORT_RANGE_LOWER = 9100;51public static final int JMX_PORT_RANGE_UPPER = 9200;52public static final int JMX_PORT_RANGE_LOWER_SSL = 9201; // 9200 might be RMI Port53public static final int JMX_PORT_RANGE_UPPER_SSL = 9300;54private static final int MAX_RETRY_ATTEMTS = 10;55public static final String READY_MSG = "MainThread: Ready for connections";56public static final String TEST_CLASS = JMXAgentInterfaceBinding.class.getSimpleName();57public static final String KEYSTORE_LOC = System.getProperty("test.src", ".") +58File.separator +59"ssl" +60File.separator +61"keystore";62public static final String TRUSTSTORE_LOC = System.getProperty("test.src", ".") +63File.separator +64"ssl" +65File.separator +66"truststore";67public static final String TEST_CLASSPATH = System.getProperty("test.classes", ".");6869public void run(List<InetAddress> addrs) {70System.out.println("DEBUG: Running tests with plain sockets.");71runTests(addrs, false);72System.out.println("DEBUG: Running tests with SSL sockets.");73runTests(addrs, true);74}7576private void runTests(List<InetAddress> addrs, boolean useSSL) {77List<TestProcessThread> testThreads = new ArrayList<>(addrs.size());78CountDownLatch latch = new CountDownLatch(addrs.size());79for (InetAddress addr : addrs) {80String address = JMXAgentInterfaceBinding.wrapAddress(addr.getHostAddress());81TestProcessThread t = new TestProcessThread(address, useSSL, latch);82testThreads.add(t);83t.start();84}85try {86latch.await();87} catch (InterruptedException e) {88System.err.println("Failed to wait for the test threads to complete");89throw new RuntimeException("Test failed", e);90}9192long failedProcesses = testThreads.stream().filter(TestProcessThread::isTestFailed).count();93if (failedProcesses > 0) {94throw new RuntimeException("Test FAILED. " + failedProcesses + " out of " + addrs.size() +95" process(es) failed to start the JMX agent.");96}97}9899private static int getRandomPortInRange(int lower, int upper) {100if (upper <= lower) {101throw new IllegalArgumentException("upper <= lower");102}103int range = upper - lower;104int randPort = lower + (int)(Math.random() * range);105return randPort;106}107108public static void main(String[] args) {109List<InetAddress> addrs = getNonLoopbackAddressesForLocalHost();110if (addrs.isEmpty()) {111System.out.println("Ignoring test since no non-loopback IPs are available to bind to " +112"in addition to the loopback interface.");113return;114}115JMXInterfaceBindingTest test = new JMXInterfaceBindingTest();116// Add loopback interface too as we'd like to verify whether it's117// possible to bind to multiple addresses on the same host. This118// wasn't possible prior JDK-6425769. It used to bind to *all* local119// interfaces. We add loopback here, since that eases test setup.120addrs.add(InetAddress.getLoopbackAddress());121test.run(addrs);122System.out.println("All tests PASSED.");123}124125private static List<InetAddress> getNonLoopbackAddressesForLocalHost() {126List<InetAddress> addrs = new ArrayList<>();127try {128InetAddress localHost = InetAddress.getLocalHost();129if (!localHost.isLoopbackAddress()) {130addrs.add(localHost);131}132return addrs;133} catch (UnknownHostException e) {134throw new RuntimeException("Test failed", e);135}136}137138private static class TestProcessThread extends Thread {139private final String name;140private final String address;141private final boolean useSSL;142private final CountDownLatch latch;143private volatile boolean testFailed = false;144private OutputAnalyzer output;145146public TestProcessThread(String address, boolean useSSL, CountDownLatch latch) {147this.address = address;148this.useSSL = useSSL;149this.name = "JMX-Tester-" + address;150this.latch = latch;151}152153@Override154public void run() {155int attempts = 0;156boolean needRetry = false;157do {158if (needRetry) {159System.err.println("Retrying the test for " + name);160}161needRetry = runTest();162} while (needRetry && (attempts++ < MAX_RETRY_ATTEMTS));163164if (testFailed) {165int exitValue = output.getExitValue();166if (needRetry) {167System.err.println("Test FAILURE on " + name + " reason: run out of retries to to pick free ports");168} else if (exitValue == COMMUNICATION_ERROR_EXIT_VAL) {169// Failure case since the java processes should still be170// running.171System.err.println("Test FAILURE on " + name);172} else if (exitValue == STOP_PROCESS_EXIT_VAL) {173System.out.println("Test FAILURE on " + name + " reason: The expected line \"" + READY_MSG174+ "\" is not present in the process output");175} else {176System.err.println("Test FAILURE on " + name + " reason: Unexpected exit code => " + exitValue);177}178output.reportDiagnosticSummary();179}180latch.countDown();181}182183public boolean isTestFailed() {184return testFailed;185}186187private int getJMXPort() {188return useSSL ?189getRandomPortInRange(JMX_PORT_RANGE_LOWER_SSL, JMX_PORT_RANGE_UPPER_SSL) :190getRandomPortInRange(JMX_PORT_RANGE_LOWER, JMX_PORT_RANGE_UPPER);191}192193private Process createTestProcess() {194int jmxPort = getJMXPort();195int rmiPort = jmxPort + 1;196String msg = String.format("DEBUG: Launching java tester for triplet (HOSTNAME,JMX_PORT,RMI_PORT)" +197" == (%s,%d,%d)", address, jmxPort, rmiPort);198System.out.println(msg);199List<String> args = new ArrayList<>();200args.add("-classpath");201args.add(TEST_CLASSPATH);202args.add("-Dcom.sun.management.jmxremote.host=" + address);203args.add("-Dcom.sun.management.jmxremote.port=" + jmxPort);204args.add("-Dcom.sun.management.jmxremote.rmi.port=" + rmiPort);205args.add("-Dcom.sun.management.jmxremote.authenticate=false");206args.add("-Dcom.sun.management.jmxremote.ssl=" + Boolean.toString(useSSL));207// This is needed for testing on loopback208args.add("-Djava.rmi.server.hostname=" + address);209if (useSSL) {210args.add("-Dcom.sun.management.jmxremote.registry.ssl=true");211args.add("-Djavax.net.ssl.keyStore=" + KEYSTORE_LOC);212args.add("-Djavax.net.ssl.trustStore=" + TRUSTSTORE_LOC);213args.add("-Djavax.net.ssl.keyStorePassword=password");214args.add("-Djavax.net.ssl.trustStorePassword=trustword");215}216args.add(TEST_CLASS);217args.add(address);218args.add(Integer.toString(jmxPort));219args.add(Integer.toString(rmiPort));220args.add(Boolean.toString(useSSL));221222try {223ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(args.toArray(new String[]{}));224System.out.println(ProcessTools.getCommandLine(builder));225Process process = builder.start();226output = new OutputAnalyzer(process);227return process;228} catch (Exception e) {229throw new RuntimeException("Test failed", e);230}231}232233// Returns true if the test failed due to "Port already in use" error.234private boolean runTest() {235testFailed = true;236Process process = createTestProcess();237try {238sendMessageToProcess(process, "Exit: " + STOP_PROCESS_EXIT_VAL);239process.waitFor();240} catch (Throwable e) {241System.err.println("Failed to stop process: " + name);242throw new RuntimeException("Test failed", e);243}244if (output.getExitValue() == STOP_PROCESS_EXIT_VAL && output.getStdout().contains(READY_MSG)) {245testFailed = false;246} else if (output.getStderr().contains("Port already in use")) {247System.out.println("The test attempt for the test " + name +" failed due to the bind error");248// Need to retry249return true;250}251return false;252}253254private static void sendMessageToProcess(Process process, String message) {255try (PrintWriter pw = new PrintWriter(process.getOutputStream())) {256pw.println(message);257pw.flush();258}259}260}261}262263264