/* * Copyright 2007 Yusuke Yamamoto * * 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. */ package twitter4j.management; import junit.framework.TestCase; import javax.management.AttributeList; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.openmbean.CompositeData; import javax.management.openmbean.TabularData; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Unit tests for APIStatistics, MBeans * * @author Nick Dellamaggiore (nick.dellamaggiore <at> gmail.com) */ public class MBeansTest extends TestCase { public MBeansTest(String name) { super(name); } /** * Tests statistics calculation for a single method */ public void testInvocationStatisticsCalculator() throws Exception { InvocationStatisticsCalculator calc = new InvocationStatisticsCalculator("foo", 5); assertEquals("foo", calc.getName()); checkCalculator(calc, 0, 0, 0, 0); calc.increment(100, true); checkCalculator(calc, 1, 0, 100, 100); calc.increment(100, true); checkCalculator(calc, 2, 0, 200, 100); calc.increment(400, false); checkCalculator(calc, 3, 1, 600, 200); // test rollover for average calc.increment(200, true); calc.increment(200, true); calc.increment(200, true); checkCalculator(calc, 6, 1, 1200, 220); for (int i = 0; i < 1000; i++) { calc.increment(i, true); } checkCalculator(calc, 1006, 1, 500700, 997); // test reset, sure it still works after resetting calc.reset(); checkCalculator(calc, 0, 0, 0, 0); calc.increment(100, true); checkCalculator(calc, 1, 0, 100, 100); } /** * Tests statistics calculation/aggregation for an entire API */ public void testAPIStatistics() throws Exception { APIStatistics stats = new APIStatistics(5); checkCalculator(stats, 0, 0, 0, 0); assertFalse(stats.getInvocationStatistics().iterator().hasNext()); stats.methodCalled("foo", 100, true); checkCalculator(stats, 1, 0, 100, 100); checkMethodStats(stats, "foo", 1, 0, 100, 100); stats.methodCalled("bar", 100, true); checkCalculator(stats, 2, 0, 200, 100); checkMethodStats(stats, "foo", 1, 0, 100, 100); checkMethodStats(stats, "bar", 1, 0, 100, 100); stats.methodCalled("foo", 400, false); checkCalculator(stats, 3, 1, 600, 200); checkMethodStats(stats, "foo", 2, 1, 500, 250); checkMethodStats(stats, "bar", 1, 0, 100, 100); // test rollover for average stats.methodCalled("foo", 200, true); stats.methodCalled("bar", 200, true); stats.methodCalled("baz", 200, true); checkCalculator(stats, 6, 1, 1200, 220); checkMethodStats(stats, "foo", 3, 1, 700, 233); checkMethodStats(stats, "bar", 2, 0, 300, 150); checkMethodStats(stats, "baz", 1, 0, 200, 200); // test reset, sure it still works after resetting stats.reset(); checkCalculator(stats, 0, 0, 0, 0); assertFalse(stats.getInvocationStatistics().iterator().hasNext()); stats.methodCalled("foo", 100, true); checkCalculator(stats, 1, 0, 100, 100); checkMethodStats(stats, "foo", 1, 0, 100, 100); } /** * Tests exposure of API statistics via a dynamic MBean */ public void testAPIStatisticsOpenMBean() throws Exception { APIStatistics stats = new APIStatistics(5); APIStatisticsOpenMBean openMBean = new APIStatisticsOpenMBean(stats); // sanity check to ensure metadata accurately describes dynamic attributes MBeanInfo info = openMBean.getMBeanInfo(); assertEquals(5, info.getAttributes().length); assertEquals(1, info.getOperations().length); List<String> attrNames = new ArrayList<String>(); for (MBeanAttributeInfo attr : info.getAttributes()) { assertNotNull(openMBean.getAttribute(attr.getName())); attrNames.add(attr.getName()); } AttributeList attrList = openMBean.getAttributes(attrNames.toArray(new String[attrNames.size()])); assertNotNull(attrList); assertEquals(5, attrList.size()); // check stats (empty case) Long callCount = (Long) openMBean.getAttribute("callCount"); assertEquals(0, callCount.longValue()); Long errorCount = (Long) openMBean.getAttribute("errorCount"); assertEquals(0, callCount.longValue()); Long totalTime = (Long) openMBean.getAttribute("totalTime"); assertEquals(0, totalTime.longValue()); Long averageTime = (Long) openMBean.getAttribute("averageTime"); assertEquals(0, averageTime.longValue()); // check table (empty case) TabularData table = (TabularData) openMBean.getAttribute("statisticsTable"); assertTrue(table.isEmpty()); stats.methodCalled("foo", 100, true); // check stats (populated case) callCount = (Long) openMBean.getAttribute("callCount"); assertEquals(1, callCount.longValue()); errorCount = (Long) openMBean.getAttribute("errorCount"); assertEquals(0, errorCount.longValue()); totalTime = (Long) openMBean.getAttribute("totalTime"); assertEquals(100, totalTime.longValue()); averageTime = (Long) openMBean.getAttribute("averageTime"); assertEquals(100, averageTime.longValue()); // check table (populated case) table = (TabularData) openMBean.getAttribute("statisticsTable"); assertFalse(table.isEmpty()); assertEquals(1, table.keySet().size()); CompositeData data = table.get(new Object[]{"foo"}); assertNotNull(data); String[] columnNames = new String[]{"methodName", "callCount", "totalTime", "avgTime"}; Object[] columnValues = data.getAll(columnNames); assertEquals(columnNames.length, columnValues.length); assertEquals("foo", columnValues[0]); assertEquals(1, ((Long) columnValues[1]).longValue()); assertEquals(100, ((Long) columnValues[2]).longValue()); assertEquals(100, ((Long) columnValues[3]).longValue()); // check reset openMBean.invoke("reset", new Object[0], new String[0]); checkCalculator(stats, 0, 0, 0, 0); assertFalse(stats.getInvocationStatistics().iterator().hasNext()); } // ***************** // Helper methods // ***************** private void checkMethodStats(APIStatistics apiStats, String methodName, long callCount, long errorCount, long totalTime, long avgTime) { InvocationStatistics methodStats = null; Iterator<? extends InvocationStatistics> itr = apiStats.getInvocationStatistics().iterator(); while (itr.hasNext()) { InvocationStatistics s = itr.next(); if (s.getName().equals(methodName)) { methodStats = s; break; } } if (methodStats != null) { checkCalculator(methodStats, callCount, errorCount, totalTime, avgTime); } else { fail("No stats available for method with name '" + methodName + "'"); } } private void checkCalculator(InvocationStatistics calc, long callCount, long errorCount, long totalTime, long avgTime) { assertEquals(callCount, calc.getCallCount()); assertEquals(errorCount, calc.getErrorCount()); assertEquals(totalTime, calc.getTotalTime()); assertEquals(avgTime, calc.getAverageTime()); } }