package org.jolokia.handler; /* * Copyright 2009-2013 Roland Huss * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.IOException; import java.util.*; import javax.management.*; import org.jolokia.config.ConfigKey; import org.jolokia.request.JmxReadRequest; import org.jolokia.request.JmxRequestBuilder; import org.jolokia.restrictor.AllowAllRestrictor; import org.jolokia.restrictor.Restrictor; import org.jolokia.util.HttpMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import static org.easymock.EasyMock.*; import static org.jolokia.util.RequestType.READ; import static org.testng.Assert.*; import static org.testng.AssertJUnit.assertEquals; /** * @author roland * @since Mar 6, 2010 */ public class ReadHandlerTest extends BaseHandlerTest { // handler to test private ReadHandler handler; private ObjectName testBeanName; @BeforeMethod public void createHandler() throws MalformedObjectNameException { handler = new ReadHandler(new AllowAllRestrictor()); testBeanName = new ObjectName("jolokia:type=test"); } @Test public void singleBeanSingleAttribute() throws Exception { JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName.getCanonicalName()). attribute("testAttribute"). build(); MBeanServerConnection connection = createMock(MBeanServerConnection.class); expect(connection.getAttribute(testBeanName,"testAttribute")).andReturn("testValue"); replay(connection); Object res = handler.handleRequest(connection,request); verify(connection); assertEquals("testValue",res); } @Test public void singleBeanNoAttributes() throws Exception { JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName.getCanonicalName()). attribute(null). build(); MBeanServer server = createMock(MBeanServer.class); String attrs[] = new String[] {"attr0","atrr1","attr2"}; String vals[] = new String[] {"val0", "val1", "val2"}; prepareMBeanInfos(server, testBeanName, attrs); for (int i=0;i<attrs.length;i++) { expect(server.getAttribute(testBeanName,attrs[i])).andReturn(vals[i]); } replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server),request); verify(server); for (int i=0;i<attrs.length;i++) { assertEquals(vals[i],res.get(attrs[i])); } } @Test public void singleBeanMultiAttributes() throws Exception { JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName.getCanonicalName()). attributes(Arrays.asList("attr0", "attr1")). build(); MBeanServer server = createMock(MBeanServer.class); expect(server.isRegistered(testBeanName)).andStubReturn(true); expect(server.getAttribute(testBeanName,"attr0")).andReturn("val0"); expect(server.getAttribute(testBeanName,"attr1")).andReturn("val1"); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server),request); verify(server); assertEquals("val0", res.get("attr0")); assertEquals("val1",res.get("attr1")); } @Test(expectedExceptions = AttributeNotFoundException.class) public void singleBeanMultiAttributesWithAWrongAttributeNameThrowingException() throws Exception { JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName.getCanonicalName()). attributes(Arrays.asList("attr0", "attr1")). option(ConfigKey.IGNORE_ERRORS, "false"). build(); MBeanServer server = createMock(MBeanServer.class); expect(server.isRegistered(testBeanName)).andStubReturn(true); expect(server.getAttribute(testBeanName,"attr0")).andReturn("val0"); expect(server.getAttribute(testBeanName,"attr1")).andThrow(new AttributeNotFoundException("Couldn't find attr1")); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server),request); } @Test public void singleBeanMultiAttributesWithAWrongAttributeNameHandlingException() throws Exception { JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName.getCanonicalName()). attributes(Arrays.asList("attr0", "attr1")). option(ConfigKey.IGNORE_ERRORS, "true"). build(); MBeanServer server = createMock(MBeanServer.class); expect(server.isRegistered(testBeanName)).andStubReturn(true); expect(server.getAttribute(testBeanName,"attr0")).andReturn("val0"); expect(server.getAttribute(testBeanName,"attr1")).andThrow(new AttributeNotFoundException("Couldn't find attr1")); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server),request); verify(server); assertEquals("val0",res.get("attr0")); String err = (String) res.get("attr1"); assertTrue(err != null && err.contains("ERROR")); } // ====================================================================================================== @Test(groups = "java6") public void searchPatternNoMatch() throws Exception { ObjectName patternMBean = new ObjectName("bla:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attribute("mem1"). build(); MBeanServer server = createMock(MBeanServer.class); expect(server.queryNames(patternMBean,null)).andReturn(new HashSet()); replay(server); try { handler.handleRequest(getMBeanServerManager(server),request); fail("Exception should be thrown"); } catch (InstanceNotFoundException exp) {} } @Test(groups = "java6") public void searchPatternSingleAttribute() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attribute("mem1"). build(); ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = prepareMultiAttributeTest(patternMBean, beans); expect(server.getAttribute(beans[0],"mem1")).andReturn("memval1"); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server), request); verify(server); assertEquals(1,res.size()); assertEquals("memval1",((Map) res.get("java.lang:type=Memory")).get("mem1")); } @Test(groups = "java6") public void searchPatternNoAttribute() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest[] requests = new JmxReadRequest[2]; requests[0] = new JmxRequestBuilder(READ, patternMBean). attribute(null). build(); requests[1] = new JmxRequestBuilder(READ, patternMBean). // A single null element is enough to denote "all" attributes(Arrays.asList((String) null)). build(); for (JmxReadRequest request : requests) { ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = prepareMultiAttributeTest(patternMBean, beans); expect(server.getAttribute(beans[0],"mem0")).andReturn("memval0"); expect(server.getAttribute(beans[0],"mem1")).andReturn("memval1"); expect(server.getAttribute(beans[0],"common")).andReturn("commonVal0"); expect(server.getAttribute(beans[1],"gc0")).andReturn("gcval0"); expect(server.getAttribute(beans[1],"gc1")).andReturn("gcval1"); expect(server.getAttribute(beans[1],"gc3")).andReturn("gcval3"); expect(server.getAttribute(beans[1],"common")).andReturn("commonVal1"); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server), request); assertEquals("memval0",((Map) res.get("java.lang:type=Memory")).get("mem0")); assertEquals("memval1",((Map) res.get("java.lang:type=Memory")).get("mem1")); assertEquals("commonVal0",((Map) res.get("java.lang:type=Memory")).get("common")); assertEquals("gcval0",((Map) res.get("java.lang:type=GarbageCollection")).get("gc0")); assertEquals("gcval1",((Map) res.get("java.lang:type=GarbageCollection")).get("gc1")); assertEquals("gcval3",((Map) res.get("java.lang:type=GarbageCollection")).get("gc3")); assertEquals("commonVal1",((Map) res.get("java.lang:type=GarbageCollection")).get("common")); verify(server); } } @Test(groups = "java6") public void searchPatternNoAttributesFound() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attribute(null). build(); ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = createMock(MBeanServer.class); expect(server.queryNames(patternMBean,null)).andReturn(new HashSet(Arrays.asList(beans))); prepareMBeanInfos(server,beans[0],new String[0]); prepareMBeanInfos(server,beans[1],new String[] { "gc0" }); expect(server.getAttribute(beans[1],"gc0")).andReturn("gcval0"); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server), request); // Only a single entry fetched assertEquals(res.size(),1); verify(server); } @Test(groups = "java6") public void searchPatternNoMatchingAttribute() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attribute("blub"). build(); ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = prepareMultiAttributeTest(patternMBean, beans); replay(server); try { handler.handleRequest(getMBeanServerManager(server), request); } catch (IllegalArgumentException exp) { // expected } verify(server); } @Test(groups = "java6") public void searchPatternMultiAttributes1() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attributes(Arrays.asList("mem0","gc3")). build(); ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = prepareMultiAttributeTest(patternMBean, beans); expect(server.getAttribute(beans[0],"mem0")).andReturn("memval0"); expect(server.getAttribute(beans[1],"gc3")).andReturn("gcval3"); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server), request); verify(server); assertEquals(2,res.size()); assertEquals("memval0",((Map) res.get("java.lang:type=Memory")).get("mem0")); assertEquals("gcval3",((Map) res.get("java.lang:type=GarbageCollection")).get("gc3")); } @Test(groups = "java6") public void searchPatternMultiAttributes3() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attributes(Arrays.asList("bla")). build(); ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = prepareMultiAttributeTest(patternMBean, beans); replay(server); try { Map res = (Map) handler.handleRequest(getMBeanServerManager(server), request); fail("Request should fail since attribute name doesn't match any MBean's attribute"); } catch (IllegalArgumentException exp) { // Expect this since no MBean matches the given attribute } } @Test(groups = "java6") public void searchPatternMultiAttributes4() throws Exception { ObjectName patternMBean = new ObjectName("java.lang:type=*"); JmxReadRequest request = new JmxRequestBuilder(READ, patternMBean). attributes(Arrays.asList("common")). build(); ObjectName beans[] = { new ObjectName("java.lang:type=Memory"), new ObjectName("java.lang:type=GarbageCollection") }; MBeanServer server = prepareMultiAttributeTest(patternMBean, beans); expect(server.getAttribute(beans[0],"common")).andReturn("com1"); expect(server.getAttribute(beans[1],"common")).andReturn("com2"); replay(server); Map res = (Map) handler.handleRequest(getMBeanServerManager(server), request); verify(server); assertEquals(2,res.size()); assertEquals("com1",((Map) res.get("java.lang:type=Memory")).get("common")); assertEquals("com2",((Map) res.get("java.lang:type=GarbageCollection")).get("common")); } private MBeanServer prepareMultiAttributeTest(ObjectName pPatternMBean, ObjectName[] pBeans) throws IOException, MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IntrospectionException { MBeanServer server = createMock(MBeanServer.class); String params[][] = { new String[] {"mem0","mem1","common" }, new String[] {"gc0","gc1","gc3","common"}, }; expect(server.queryNames(pPatternMBean,null)).andReturn(new HashSet(Arrays.asList(pBeans))); for (int i=0;i< pBeans.length;i++) { prepareMBeanInfos(server, pBeans[i],params[i]); } return server; } // ============================================================================================================== @Test public void handleAllServersAtOnceTest() throws MalformedObjectNameException { JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName). attribute("attr"). build(); assertFalse(handler.handleAllServersAtOnce(request)); request = new JmxRequestBuilder(READ, testBeanName). attributes(Arrays.asList("attr1","attr2")). build(); assertTrue(handler.handleAllServersAtOnce(request)); request = new JmxRequestBuilder(READ, testBeanName). attributes((List) null). build(); assertTrue(handler.handleAllServersAtOnce(request)); request = new JmxRequestBuilder(READ, "java.lang:*"). attribute("attr"). build(); assertTrue(handler.handleAllServersAtOnce(request)); } // ============================================================================================================== @Test public void restrictAccess() throws Exception { Restrictor restrictor = createMock(Restrictor.class); expect(restrictor.isAttributeReadAllowed(testBeanName,"attr")).andReturn(false); expect(restrictor.isHttpMethodAllowed(HttpMethod.POST)).andReturn(true); handler = new ReadHandler(restrictor); JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName). attribute("attr"). build(); MBeanServer server = createMock(MBeanServer.class); replay(restrictor,server); try { handler.handleRequest(getMBeanServerManager(server),request); fail("Restrictor should forbid access"); } catch (SecurityException exp) {} verify(restrictor,server); } @Test public void restrictHttpMethodAccess() throws Exception { Restrictor restrictor = createMock(Restrictor.class); expect(restrictor.isHttpMethodAllowed(HttpMethod.POST)).andReturn(false); handler = new ReadHandler(restrictor); JmxReadRequest request = new JmxRequestBuilder(READ, testBeanName). attribute("attr"). build(); MBeanServer server = createMock(MBeanServer.class); replay(restrictor,server); try { handler.handleRequest(getMBeanServerManager(server),request); fail("Restrictor should forbid HTTP Method Access"); } catch (SecurityException exp) {} verify(restrictor,server); } // ============================================================================================================== private MBeanAttributeInfo[] prepareMBeanInfos(MBeanServerConnection pConnection, ObjectName pObjectName, String pAttrs[]) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException, IntrospectionException { MBeanInfo mBeanInfo = createMock(MBeanInfo.class); expect(pConnection.isRegistered(pObjectName)).andStubReturn(true); expect(pConnection.getMBeanInfo(pObjectName)).andReturn(mBeanInfo); MBeanAttributeInfo[] infos = new MBeanAttributeInfo[pAttrs.length]; for (int i=0;i<pAttrs.length;i++) { infos[i] = createMock(MBeanAttributeInfo.class); expect(infos[i].getName()).andReturn(pAttrs[i]); expect(infos[i].isReadable()).andReturn(true); } expect(mBeanInfo.getAttributes()).andReturn(infos); replay(mBeanInfo); for (int j=0;j<infos.length;j++) { replay(infos[j]); } return infos; } }