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