001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import static org.junit.jupiter.api.Assertions.assertThrows; 021import static org.junit.jupiter.api.Assertions.assertTrue; 022import static org.junit.jupiter.api.Assertions.fail; 023 024import java.io.IOException; 025import javax.management.MBeanServerConnection; 026import javax.management.remote.JMXConnector; 027import javax.management.remote.JMXConnectorFactory; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 030import org.apache.hadoop.hbase.net.BoundSocketMaker; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.testclassification.MiscTests; 033import org.apache.hadoop.hbase.util.JVMClusterUtil; 034import org.junit.jupiter.api.AfterAll; 035import org.junit.jupiter.api.BeforeAll; 036import org.junit.jupiter.api.Tag; 037import org.junit.jupiter.api.Test; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041@Tag(MiscTests.TAG) 042@Tag(MediumTests.TAG) 043public class TestJMXListener { 044 045 private static final Logger LOG = LoggerFactory.getLogger(TestJMXListener.class); 046 private static HBaseTestingUtil UTIL = new HBaseTestingUtil(); 047 private static int CONNECTOR_PORT; 048 049 @BeforeAll 050 public static void setupBeforeClass() throws Exception { 051 // Default RMI timeouts are too long. Make them short for test. 052 System.setProperty("sun.rmi.transport.connectionTimeout", Integer.toString(5000)); 053 System.setProperty("sun.rmi.transport.tcp.handshakeTimeout", Integer.toString(5000)); 054 System.setProperty("sun.rmi.transport.tcp.responseTimeout", Integer.toString(5000)); 055 System.setProperty("sun.rmi.transport.tcp.readTimeout", Integer.toString(5000)); 056 Configuration conf = UTIL.getConfiguration(); 057 // To test what happens when the jmx listener can't put up its port, uncomment the below. 058 BoundSocketMaker bsm = null; // new BoundSocketMaker(HBaseTestingUtility::randomFreePort); 059 conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, JMXListener.class.getName()); 060 CONNECTOR_PORT = bsm == null ? HBaseTestingUtil.randomFreePort() : bsm.getPort(); 061 // Make sure the JMX listener is up before we proceed. If it is not up, retry. It may not 062 // come up if there is a port clash/bind exception except its called something else in rmi. 063 for (int i = 0; i < 10; i++) { 064 conf.setInt("regionserver.rmi.registry.port", CONNECTOR_PORT); 065 UTIL.startMiniCluster(); 066 // Make sure we can get make a JMX connection before proceeding. It may have failed setup 067 // because of port clash/bind-exception. Deal with it here. 068 JMXConnector connector = null; 069 try { 070 connector = JMXConnectorFactory 071 .connect(JMXListener.buildJMXServiceURL(CONNECTOR_PORT, CONNECTOR_PORT)); 072 break; 073 } catch (IOException ioe) { 074 UTIL.shutdownMiniCluster(); 075 CONNECTOR_PORT = HBaseTestingUtil.randomFreePort(); 076 } finally { 077 if (connector != null) { 078 connector.close(); 079 } 080 } 081 } 082 if (bsm != null) { 083 bsm.close(); 084 } 085 } 086 087 @AfterAll 088 public static void tearDownAfterClass() throws Exception { 089 UTIL.shutdownMiniCluster(); 090 } 091 092 @Test 093 public void testStart() throws Exception { 094 JMXConnector connector = 095 JMXConnectorFactory.connect(JMXListener.buildJMXServiceURL(CONNECTOR_PORT, CONNECTOR_PORT)); 096 097 MBeanServerConnection mb = connector.getMBeanServerConnection(); 098 String domain = mb.getDefaultDomain(); 099 assertTrue(!domain.isEmpty(), "default domain is not correct"); 100 connector.close(); 101 102 } 103 104 // shutdown hbase only. then try connect, IOException expected 105 106 @Test 107 public void testStop() throws Exception { 108 SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster(); 109 LOG.info("shutdown hbase cluster..."); 110 cluster.shutdown(); 111 LOG.info("wait for the hbase cluster shutdown..."); 112 cluster.waitUntilShutDown(); 113 114 JMXConnector connector = JMXConnectorFactory 115 .newJMXConnector(JMXListener.buildJMXServiceURL(CONNECTOR_PORT, CONNECTOR_PORT), null); 116 assertThrows(IOException.class, () -> connector.connect()); 117 118 } 119 120 @Test 121 public void testGetRegionServerCoprocessors() throws Exception { 122 for (JVMClusterUtil.RegionServerThread rs : UTIL.getHBaseCluster().getRegionServerThreads()) { 123 boolean find = false; 124 for (String s : rs.getRegionServer().getRegionServerCoprocessors()) { 125 if (s.equals(JMXListener.class.getSimpleName())) { 126 find = true; 127 break; 128 } 129 } 130 if (!find) { 131 fail("where is the JMXListener?"); 132 } 133 } 134 } 135}