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.http.jmx; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.net.HttpURLConnection; 025import java.net.URL; 026import java.net.URLEncoder; 027import java.util.regex.Matcher; 028import java.util.regex.Pattern; 029import javax.servlet.http.HttpServletResponse; 030import org.apache.hadoop.hbase.HBaseClassTestRule; 031import org.apache.hadoop.hbase.http.HttpServer; 032import org.apache.hadoop.hbase.http.HttpServerFunctionalTest; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.apache.hadoop.hbase.testclassification.SmallTests; 035import org.junit.AfterClass; 036import org.junit.BeforeClass; 037import org.junit.ClassRule; 038import org.junit.Test; 039import org.junit.experimental.categories.Category; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043@Category({ MiscTests.class, SmallTests.class }) 044public class TestJMXJsonServlet extends HttpServerFunctionalTest { 045 046 @ClassRule 047 public static final HBaseClassTestRule CLASS_RULE = 048 HBaseClassTestRule.forClass(TestJMXJsonServlet.class); 049 050 private static final Logger LOG = LoggerFactory.getLogger(TestJMXJsonServlet.class); 051 private static HttpServer server; 052 private static URL baseUrl; 053 054 @BeforeClass 055 public static void setup() throws Exception { 056 // Eclipse doesn't pick this up correctly from the plugin 057 // configuration in the pom. 058 System.setProperty(HttpServerFunctionalTest.TEST_BUILD_WEBAPPS, "target/test-classes/webapps"); 059 server = createTestServer(); 060 server.start(); 061 baseUrl = getServerURL(server); 062 } 063 064 @AfterClass 065 public static void cleanup() throws Exception { 066 server.stop(); 067 } 068 069 public static void assertReFind(String re, String value) { 070 Pattern p = Pattern.compile(re); 071 Matcher m = p.matcher(value); 072 assertTrue("'" + p + "' does not match " + value, m.find()); 073 } 074 075 public static void assertNotFind(String re, String value) { 076 Pattern p = Pattern.compile(re); 077 Matcher m = p.matcher(value); 078 assertFalse("'" + p + "' should not match " + value, m.find()); 079 } 080 081 @Test 082 public void testQuery() throws Exception { 083 String result = readOutput(new URL(baseUrl, "/jmx?qry=java.lang:type=Runtime")); 084 LOG.info("/jmx?qry=java.lang:type=Runtime RESULT: " + result); 085 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Runtime\"", result); 086 assertReFind("\"modelerType\"", result); 087 088 result = readOutput(new URL(baseUrl, "/jmx?qry=java.lang:type=Memory")); 089 LOG.info("/jmx?qry=java.lang:type=Memory RESULT: " + result); 090 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 091 assertReFind("\"modelerType\"", result); 092 093 result = readOutput(new URL(baseUrl, "/jmx")); 094 LOG.info("/jmx RESULT: " + result); 095 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 096 097 // test to get an attribute of a mbean 098 result = readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::HeapMemoryUsage")); 099 LOG.info("/jmx RESULT: " + result); 100 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 101 assertReFind("\"committed\"\\s*:", result); 102 103 // negative test to get an attribute of a mbean 104 result = readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::")); 105 LOG.info("/jmx RESULT: " + result); 106 assertReFind("\"ERROR\"", result); 107 108 // test to get JSONP result 109 result = readOutput(new URL(baseUrl, "/jmx?qry=java.lang:type=Memory&callback=mycallback1")); 110 LOG.info("/jmx?qry=java.lang:type=Memory&callback=mycallback RESULT: " + result); 111 assertReFind("^mycallback1\\(\\{", result); 112 assertReFind("\\}\\);$", result); 113 114 // negative test to get an attribute of a mbean as JSONP 115 result = readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::&callback=mycallback2")); 116 LOG.info("/jmx RESULT: " + result); 117 assertReFind("^mycallback2\\(\\{", result); 118 assertReFind("\"ERROR\"", result); 119 assertReFind("\\}\\);$", result); 120 121 // test to get an attribute of a mbean as JSONP 122 result = readOutput( 123 new URL(baseUrl, "/jmx?get=java.lang:type=Memory::HeapMemoryUsage&callback=mycallback3")); 124 LOG.info("/jmx RESULT: " + result); 125 assertReFind("^mycallback3\\(\\{", result); 126 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 127 assertReFind("\"committed\"\\s*:", result); 128 assertReFind("\\}\\);$", result); 129 130 // test exclude the specific mbean 131 result = 132 readOutput(new URL(baseUrl, "/jmx?excl=Hadoop:service=HBase,name=RegionServer,sub=Regions")); 133 LOG.info("/jmx RESULT: " + result); 134 assertNotFind("\"name\"\\s*:\\s*\"Hadoop:service=HBase,name=RegionServer,sub=Regions\"", 135 result); 136 } 137 138 @Test 139 public void testGetPattern() throws Exception { 140 // test to get an attribute of a mbean as JSONP 141 String result = 142 readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::[a-zA-z_]*NonHeapMemoryUsage")); 143 LOG.info("/jmx RESULT: " + result); 144 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 145 assertReFind("\"committed\"\\s*:", result); 146 assertReFind("\"NonHeapMemoryUsage\"\\s*:", result); 147 assertNotFind("\"HeapMemoryUsage\"\\s*:", result); 148 149 result = readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::[^Non]*HeapMemoryUsage")); 150 LOG.info("/jmx RESULT: " + result); 151 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 152 assertReFind("\"committed\"\\s*:", result); 153 assertReFind("\"HeapMemoryUsage\"\\s*:", result); 154 assertNotFind("\"NonHeapHeapMemoryUsage\"\\s*:", result); 155 156 result = readOutput(new URL(baseUrl, 157 "/jmx?get=java.lang:type=Memory::[a-zA-z_]*HeapMemoryUsage,[a-zA-z_]*NonHeapMemoryUsage")); 158 LOG.info("/jmx RESULT: " + result); 159 assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); 160 assertReFind("\"committed\"\\s*:", result); 161 } 162 163 @Test 164 public void testPatternMatching() throws Exception { 165 assertReFind("[a-zA-z_]*Table1[a-zA-z_]*memStoreSize", 166 "Namespace_default_table_Table1_metric_memStoreSize"); 167 assertReFind("[a-zA-z_]*memStoreSize", "Namespace_default_table_Table1_metric_memStoreSize"); 168 } 169 170 @Test 171 public void testDisallowedJSONPCallback() throws Exception { 172 String callback = "function(){alert('bigproblems!')};foo"; 173 URL url = new URL(baseUrl, 174 "/jmx?qry=java.lang:type=Memory&callback=" + URLEncoder.encode(callback, "UTF-8")); 175 HttpURLConnection cnxn = (HttpURLConnection) url.openConnection(); 176 assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cnxn.getResponseCode()); 177 } 178 179 @Test 180 public void testUnderscoresInJSONPCallback() throws Exception { 181 String callback = "my_function"; 182 URL url = new URL(baseUrl, 183 "/jmx?qry=java.lang:type=Memory&callback=" + URLEncoder.encode(callback, "UTF-8")); 184 HttpURLConnection cnxn = (HttpURLConnection) url.openConnection(); 185 assertEquals(HttpServletResponse.SC_OK, cnxn.getResponseCode()); 186 } 187}