Path: blob/master/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java
41153 views
/*1* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.2* 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.EOFException;24import java.io.File;25import java.io.IOException;26import java.lang.reflect.InvocationTargetException;27import java.lang.reflect.Method;28import java.net.BindException;29import java.net.ConnectException;30import java.net.ServerSocket;31import java.rmi.RemoteException;32import java.rmi.registry.LocateRegistry;33import java.rmi.registry.Registry;34import java.util.ArrayList;35import java.util.Arrays;36import java.util.List;37import java.util.Objects;38import java.util.Set;39import java.util.concurrent.TimeoutException;40import java.util.concurrent.atomic.AtomicBoolean;4142import javax.management.*;43import javax.management.remote.*;44import javax.net.ssl.SSLHandshakeException;4546import jdk.test.lib.process.ProcessTools;47import jdk.test.lib.Utils;48import jdk.internal.agent.Agent;49import jdk.internal.agent.AgentConfigurationError;50import jdk.internal.agent.ConnectorAddressLink;5152/**53* @test54* @bug 711010455* @key randomness intermittent56* @summary Makes sure that enabling/disabling the management agent through JCMD57* achieves the desired results58*59* @library /test/lib60* @modules java.management61* java.rmi62* jdk.management.agent/jdk.internal.agent63*64* @build JMXStartStopTest PortAllocator TestApp ManagementAgentJcmd65* @run main/othervm/timeout=600 -XX:+UsePerfData JMXStartStopTest66*/67public class JMXStartStopTest {68private static final String TEST_APP_NAME = "TestApp";6970private static final String TEST_SRC = System.getProperty("test.src");7172private static final boolean verbose = false;7374private static ManagementAgentJcmd jcmd = new ManagementAgentJcmd(TEST_APP_NAME, verbose);7576private static void dbg_print(String msg) {77if (verbose) {78System.out.println("DBG: " + msg);79}80}8182private static int listMBeans(MBeanServerConnection server,83ObjectName pattern,84QueryExp query)85throws Exception {8687Set<ObjectName> names = server.queryNames(pattern,query);88for (ObjectName name : names) {89MBeanInfo info = server.getMBeanInfo(name);90dbg_print("Got MBean: " + name);9192MBeanAttributeInfo[] attrs = info.getAttributes();93if (attrs == null)94continue;95for (MBeanAttributeInfo attr : attrs) {96if (attr.isReadable()) {97server.getAttribute(name, attr.getName());98}99}100}101return names.size();102}103104private static void testConnectLocal(long pid)105throws Exception {106107String jmxUrlStr = null;108109try {110jmxUrlStr = ConnectorAddressLink.importFrom((int)pid);111dbg_print("Local Service URL: " +jmxUrlStr);112if ( jmxUrlStr == null ) {113throw new Exception("No Service URL. Local agent not started?");114}115116JMXServiceURL url = new JMXServiceURL(jmxUrlStr);117118JMXConnector c = JMXConnectorFactory.connect(url, null);119120MBeanServerConnection conn = c.getMBeanServerConnection();121ObjectName pattern = new ObjectName("java.lang:type=Memory,*");122123int count = listMBeans(conn,pattern,null);124if (count == 0)125throw new Exception("Expected at least one matching "+126"MBean for "+pattern);127128} catch (IOException e) {129dbg_print("Cannot find process : " + pid);130throw e;131}132}133134private static void testNoConnect(int port) throws Exception {135testNoConnect(port, 0);136}137138private static void testNoConnect(int port, int rmiPort) throws Exception {139try {140testConnect(port, rmiPort);141throw new Exception("Didn't expect the management agent running");142} catch (Exception e) {143Throwable t = e;144while (t != null) {145if (t instanceof RemoteException ||146t instanceof SSLHandshakeException ||147t instanceof ConnectException) {148break;149}150t = t.getCause();151}152if (t == null) {153throw new Exception("Unexpected exception", e);154}155}156}157158private static void testConnect(int port) throws Exception {159testConnect(port, 0);160}161162private static void testConnect(int port, int rmiPort) throws Exception {163EOFException lastException = null;164// factor adjusted timeout (5 seconds) for the RMI to become available165long timeout = System.currentTimeMillis() + Utils.adjustTimeout(5000);166do {167try {168doTestConnect(port, rmiPort);169lastException = null;170} catch (EOFException e) {171lastException = e;172System.out.println("Error establishing RMI connection. Retrying in 500ms.");173Thread.sleep(500);174}175} while (lastException != null && System.currentTimeMillis() < timeout);176177if (lastException != null) {178// didn't manage to get the RMI running in time179// rethrow the exception180throw lastException;181}182}183184private static void doTestConnect(int port, int rmiPort) throws Exception {185dbg_print("RmiRegistry lookup...");186187dbg_print("Using port: " + port);188189dbg_print("Using rmi port: " + rmiPort);190191Registry registry = LocateRegistry.getRegistry(port);192193// "jmxrmi"194String[] relist = registry.list();195for (int i = 0; i < relist.length; ++i) {196dbg_print("Got registry: " + relist[i]);197}198199String jmxUrlStr = (rmiPort != 0) ?200String.format(201"service:jmx:rmi://localhost:%d/jndi/rmi://localhost:%d/jmxrmi",202rmiPort,203port) :204String.format(205"service:jmx:rmi:///jndi/rmi://localhost:%d/jmxrmi",206port);207208JMXServiceURL url = new JMXServiceURL(jmxUrlStr);209210JMXConnector c = JMXConnectorFactory.connect(url, null);211212MBeanServerConnection conn = c.getMBeanServerConnection();213ObjectName pattern = new ObjectName("java.lang:type=Memory,*");214215int count = listMBeans(conn,pattern,null);216if (count == 0)217throw new Exception("Expected at least one matching " +218"MBean for " + pattern);219}220221private static class Failure {222private final Throwable cause;223private final String msg;224225public Failure(Throwable cause, String msg) {226this.cause = cause;227this.msg = msg;228}229230public Failure(String msg) {231this(null, msg);232}233234public Throwable getCause() {235return cause;236}237238public String getMsg() {239return msg;240}241242@Override243public int hashCode() {244int hash = 7;245hash = 97 * hash + Objects.hashCode(this.cause);246hash = 97 * hash + Objects.hashCode(this.msg);247return hash;248}249250@Override251public boolean equals(Object obj) {252if (obj == null) {253return false;254}255if (getClass() != obj.getClass()) {256return false;257}258final Failure other = (Failure) obj;259if (!Objects.equals(this.cause, other.cause)) {260return false;261}262if (!Objects.equals(this.msg, other.msg)) {263return false;264}265return true;266}267268@Override269public String toString() {270if (cause != null) {271return msg + "\n" + cause;272} else {273return msg;274}275}276}277278private static List<Failure> failures = new ArrayList<>();279280public static void main(String args[]) throws Exception {281for (Method m : JMXStartStopTest.class.getDeclaredMethods()) {282if (m.getName().startsWith("test_")) {283long t1 = System.currentTimeMillis();284try {285boolean retry = false;286do {287try {288m.invoke(null);289retry = false;290} catch (InvocationTargetException e) {291if (e.getCause() instanceof BindException ||292e.getCause() instanceof java.rmi.ConnectException) {293System.out.println("Failed to allocate ports. Retrying ...");294retry = true;295} else {296throw e;297}298}299} while (retry);300System.out.println("=== PASSED");301} catch (Throwable e) {302failures.add(new Failure(e, m.getName() + " failed"));303} finally {304System.out.println("(took " + (System.currentTimeMillis() - t1) + "ms)\n");305}306}307}308309if (!failures.isEmpty()) {310for(Failure f : failures) {311System.err.println(f.getMsg());312f.getCause().printStackTrace(System.err);313}314throw new Error();315}316}317318private static class TestAppRun {319private Process p;320private final ProcessBuilder pb;321private final String name;322private final AtomicBoolean started = new AtomicBoolean(false);323private volatile long pid = -1;324325public TestAppRun(ProcessBuilder pb, String name) {326this.pb = pb;327this.name = name;328}329330public synchronized void start() throws InterruptedException, IOException, TimeoutException {331if (started.compareAndSet(false, true)) {332try {333AtomicBoolean error = new AtomicBoolean(false);334p = ProcessTools.startProcess(335TEST_APP_NAME + "{" + name + "}",336pb,337(line) -> {338boolean ok = line.equals("main enter");339error.set(line.contains("BindException"));340341return ok || error.get();342}343);344if (error.get()) {345throw new BindException("Starting process failed due to " +346"the requested port not being available");347}348pid = p.pid();349} catch (TimeoutException e) {350if (p != null) {351p.destroy();352p.waitFor();353}354throw e;355}356}357}358359public long getPid() {360return pid;361}362363public synchronized void stop()364throws IOException, InterruptedException {365if (started.compareAndSet(true, false)) {366p.getOutputStream().write(0);367p.getOutputStream().flush();368int ec = p.waitFor();369if (ec != 0) {370StringBuilder msg = new StringBuilder();371msg.append("Test application '").append(name);372msg.append("' failed with exit code: ");373msg.append(ec);374375failures.add(new Failure(msg.toString()));376}377}378}379}380381/**382* Runs the test application "TestApp"383* @param name Test run name384* @param args Additional arguments385* @return Returns a {@linkplain TestAppRun} instance representing the run386* @throws IOException387* @throws InterruptedException388* @throws TimeoutException389*/390private static TestAppRun doTest(String name, String ... args)391throws Exception {392List<String> pbArgs = new ArrayList<>(Arrays.asList(393"-cp",394System.getProperty("test.class.path"),395"-XX:+UsePerfData"396));397pbArgs.addAll(Arrays.asList(args));398pbArgs.add(TEST_APP_NAME);399400ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(401pbArgs.toArray(new String[pbArgs.size()])402);403TestAppRun s = new TestAppRun(pb, name);404s.start();405return s;406}407408static void test_01() throws Exception {409// Run an app with JMX enabled stop it and410// restart on other port411412System.out.println("**** Test one ****");413int ports[] = PortAllocator.allocatePorts(2);414415TestAppRun s = doTest(416"test_01",417"-Dcom.sun.management.jmxremote.port=" + ports[0],418"-Dcom.sun.management.jmxremote.authenticate=false",419"-Dcom.sun.management.jmxremote.ssl=false");420421try {422testConnect(ports[0]);423424jcmd.stop();425testNoConnect(ports[0]);426427jcmd.start("jmxremote.port=" + ports[1]);428testConnect(ports[1]);429} finally {430s.stop();431}432}433434static void test_02() throws Exception {435// Run an app without JMX enabled436// start JMX by jcmd437438System.out.println("**** Test two ****");439440int[] ports = PortAllocator.allocatePorts(1);441TestAppRun s = doTest("test_02");442try {443jcmd.start(444"jmxremote.port=" + ports[0],445"jmxremote.authenticate=false",446"jmxremote.ssl=false"447);448449testConnect(ports[0]);450} finally {451// debugPortUsage(pa);452s.stop();453}454}455456static void test_03() throws Exception {457// Run an app without JMX enabled458// start JMX by jcmd on one port than on other one459460System.out.println("**** Test three ****");461462int[] ports = PortAllocator.allocatePorts(2);463TestAppRun s = doTest("test_03");464try {465jcmd.start(466"jmxremote.port=" + ports[0],467"jmxremote.authenticate=false",468"jmxremote.ssl=false"469);470471// Second agent shouldn't start472jcmd.start(473"jmxremote.port=" + ports[1],474"jmxremote.authenticate=false",475"jmxremote.ssl=false"476);477478// First agent should connect479testConnect(ports[0]);480481// Second agent should not connect482testNoConnect(ports[1]);483} finally {484s.stop();485}486}487488static void test_04() throws Exception {489// Run an app without JMX enabled490// start JMX by jcmd on one port, specify rmi port explicitly491492System.out.println("**** Test four ****");493494int[] ports = PortAllocator.allocatePorts(2);495TestAppRun s = doTest("test_04");496try {497jcmd.start(498"jmxremote.port=" + ports[0],499"jmxremote.rmi.port=" + ports[1],500"jmxremote.authenticate=false",501"jmxremote.ssl=false"502);503504testConnect(ports[0], ports[1]);505} finally {506s.stop();507}508}509510static void test_05() throws Exception {511// Run an app without JMX enabled, it will enable local server512// but should leave remote server disabled513514System.out.println("**** Test five ****");515int[] ports = PortAllocator.allocatePorts(1);516TestAppRun s = doTest("test_05");517try {518jcmd.startLocal();519520testNoConnect(ports[0]);521testConnectLocal(s.getPid());522} finally {523s.stop();524}525}526527static void test_06() throws Exception {528// Run an app without JMX enabled529// start JMX by jcmd on one port, specify rmi port explicitly530// attempt to start it again with the same port531// Check for valid messages in the output532533System.out.println("**** Test six ****");534535int[] ports = PortAllocator.allocatePorts(2);536TestAppRun s = doTest("test_06");537try {538jcmd.start(539"jmxremote.port=" + ports[0],540"jmxremote.authenticate=false",541"jmxremote.ssl=false"542);543544testConnect(ports[0], ports[1]);545546final AtomicBoolean checks = new AtomicBoolean(false);547jcmd.start(548line -> {549if (line.contains("java.lang.RuntimeException: Invalid agent state")) {550checks.set(true);551}552},553"jmxremote.port=" + ports[0],554"jmxremote.authenticate=false",555"jmxremote.ssl=false"556);557558if (!checks.get()) {559throw new Exception("Starting agent on port " + ports[0] + " should "560+ "report an invalid agent state");561}562} finally {563s.stop();564}565}566567static void test_07() throws Exception {568// Run an app without JMX enabled569// start JMX by jcmd on one port, specify rmi port explicitly570// attempt to start it again with other port571// Check for valid messages in the output572573System.out.println("**** Test seven ****");574575int[] ports = PortAllocator.allocatePorts(2);576TestAppRun s = doTest("test_07");577try {578jcmd.start(579"jmxremote.port=" + ports[0],580"jmxremote.authenticate=false",581"jmxremote.ssl=false"582);583584testConnect(ports[0], ports[1]);585586final AtomicBoolean checks = new AtomicBoolean(false);587588jcmd.start(589line -> {590if (line.contains("java.lang.RuntimeException: Invalid agent state")) {591checks.set(true);592}593},594"jmxremote.port=" + ports[1],595"jmxremote.authenticate=false",596"jmxremote.ssl=false"597);598599if (!checks.get()) {600throw new Exception("Starting agent on poprt " + ports[1] + " should "601+ "report an invalid agent state");602}603} finally {604s.stop();605}606}607608static void test_08() throws Exception {609// Run an app without JMX enabled610// start JMX by jcmd on one port, specify rmi port explicitly611// attempt to stop it twice612// Check for valid messages in the output613614System.out.println("**** Test eight ****");615616int[] ports = PortAllocator.allocatePorts(2);617TestAppRun s = doTest("test_08");618try {619jcmd.start(620"jmxremote.port=" + ports[0],621"jmxremote.authenticate=false",622"jmxremote.ssl=false"623);624625testConnect(ports[0], ports[1]);626627jcmd.stop();628jcmd.stop();629} finally {630s.stop();631}632}633634static void test_09() throws Exception {635// Run an app without JMX enabled636// attempt to start JMX using a non-available port637// Check for valid messages in the output638639System.out.println("**** Test nine ****");640641TestAppRun s = doTest("test_09");642643try (ServerSocket ss = new ServerSocket(0)) {644int localPort = ss.getLocalPort();645int[] ports;646do {647ports = PortAllocator.allocatePorts(1);648} while (localPort == ports[0]);649650final AtomicBoolean checks = new AtomicBoolean(false);651652int retryCntr = 1;653do {654final AtomicBoolean retry = new AtomicBoolean(false);655656try {657jcmd.start(658line -> {659if (line.contains(Agent.getText(AgentConfigurationError.AGENT_EXCEPTION))) {660retry.set(true);661}662},663"jmxremote.port=" + ports[0],664"jmxremote.rmi.port=" + localPort,665"jmxremote.authenticate=false",666"jmxremote.ssl=false"667);668} catch (BindException e) {669checks.set(true);670}671if (!retry.get()) {672break;673}674System.out.println("Attempt " + retryCntr + " >>>");675System.out.println("Unexpected reply from the agent. Retrying in 500ms ...");676Thread.sleep(500);677} while (retryCntr++ < 10);678679if (!checks.get()) {680throw new Exception("Starting agent on port " + ports[0] + " should "681+ "report port in use");682}683} finally {684s.stop();685}686687}688689static void test_10() throws Exception {690// Run an app without JMX enabled, but with some properties set691// in command line.692// make sure these properties overridden corectly693694System.out.println("**** Test ten ****");695696int[] ports = PortAllocator.allocatePorts(2);697TestAppRun s = doTest(698"test_10",699"-Dcom.sun.management.jmxremote.authenticate=false",700"-Dcom.sun.management.jmxremote.ssl=true");701702try {703testNoConnect(ports[0]);704jcmd.start(705"jmxremote.port=" + ports[1],706"jmxremote.authenticate=false",707"jmxremote.ssl=false"708);709testConnect(ports[1]);710} finally {711s.stop();712}713}714715static void test_11() throws Exception {716// Run an app with JMX enabled and with some properties set717// in command line.718// stop JMX agent and then start it again with different property values719// make sure these properties overridden corectly720721System.out.println("**** Test eleven ****");722int[] ports = PortAllocator.allocatePorts(2);723TestAppRun s = doTest(724"test_11",725"-Dcom.sun.management.jmxremote.port=" + ports[0],726"-Dcom.sun.management.jmxremote.authenticate=false",727"-Dcom.sun.management.jmxremote.ssl=true");728729try {730testNoConnect(ports[0]);731732jcmd.stop();733734testNoConnect(ports[0]);735736jcmd.start(737"jmxremote.port=" + ports[1],738"jmxremote.authenticate=false",739"jmxremote.ssl=false"740);741742testConnect(ports[1]);743} finally {744s.stop();745}746}747748static void test_12() throws Exception {749// Run an app with JMX enabled and with some properties set750// in command line.751// stop JMX agent and then start it again with different property values752// specifing some property in management config file and some of them753// in command line754// make sure these properties overridden corectly755756System.out.println("**** Test twelve ****");757758int[] ports = PortAllocator.allocatePorts(2);759TestAppRun s = doTest("test_12",760"-Dcom.sun.management.config.file="761+ TEST_SRC + File.separator + "management_cl.properties",762"-Dcom.sun.management.jmxremote.authenticate=false"763);764765try {766testNoConnect(ports[0]);767768jcmd.stop();769770testNoConnect(ports[0]);771772jcmd.start(773"config.file=" + TEST_SRC + File.separator774+ "management_jcmd.properties",775"jmxremote.authenticate=false",776"jmxremote.port=" + ports[1]777);778779testConnect(ports[1]);780} finally {781s.stop();782}783}784785static void test_13() throws Exception {786// Run an app with JMX enabled and with some properties set787// in command line.788// stop JMX agent and then start it again with different property values789// stop JMX agent again and then start it without property value790// make sure these properties overridden corectly791792System.out.println("**** Test thirteen ****");793int[] ports = PortAllocator.allocatePorts(1);794TestAppRun s = doTest(795"test_13",796"-Dcom.sun.management.jmxremote.port=" + ports[0],797"-Dcom.sun.management.jmxremote.authenticate=false",798"-Dcom.sun.management.jmxremote.ssl=true");799800try {801testNoConnect(ports[0]);802803jcmd.stop();804jcmd.start(805"jmxremote.ssl=false",806"jmxremote.port=" + ports[0]807);808testConnect(ports[0]);809810jcmd.stop();811jcmd.start(812"jmxremote.port=" + ports[0]813);814815testNoConnect(ports[0]);816} finally {817s.stop();818}819}820821static void test_14() throws Exception {822// Run an app with JMX enabled823// stop remote agent824// make sure local agent is not affected825826System.out.println("**** Test fourteen ****");827int[] ports = PortAllocator.allocatePorts(1);828TestAppRun s = doTest(829"test_14",830"-Dcom.sun.management.jmxremote.port=" + ports[0],831"-Dcom.sun.management.jmxremote.authenticate=false",832"-Dcom.sun.management.jmxremote.ssl=false");833try {834testConnect(ports[0]);835jcmd.stop();836testConnectLocal(s.getPid());837} finally {838s.stop();839}840}841842static void test_15() throws Exception {843// Run an app with JMX disabled844// start local agent only845846System.out.println("**** Test fifteen ****");847848int[] ports = PortAllocator.allocatePorts(1);849TestAppRun s = doTest("test_15");850851try {852testNoConnect(ports[0]);853jcmd.startLocal();854855testConnectLocal(s.getPid());856857} finally {858s.stop();859}860}861862}863864865