package de.is24.util.monitoring.jmx;
import de.is24.util.monitoring.State;
import de.is24.util.monitoring.keyhandler.ValidatingKeyHandler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.util.Collection;
import static org.fest.assertions.Assertions.assertThat;
public class JMXExporterTest {
private ObjectName objectName;
private static final String TEST_BEAN_DOMAIN = "JXMExporterTest";
private TestMBean testMBean;
private static final String JAVA_LANG = "java.lang";
@Before
public void setup() throws MalformedObjectNameException, MBeanRegistrationException, InstanceAlreadyExistsException,
NotCompliantMBeanException, OpenDataException {
objectName = new ObjectName(TEST_BEAN_DOMAIN, "name", "testBean");
testMBean = new TestMBean();
ManagementFactory.getPlatformMBeanServer().registerMBean(testMBean, objectName);
}
@After
public void tearDown() throws InstanceNotFoundException, MBeanRegistrationException {
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
if (beanServer.isRegistered(objectName)) {
beanServer.unregisterMBean(objectName);
}
}
@Test
public void doNotFailIfSomeOperationIsNotSupported() throws MalformedObjectNameException {
JMXExporter jmxExporter = new JMXExporter(TEST_BEAN_DOMAIN + ":*");
jmxExporter.getValues();
}
@Test
public void logNumericAttributes() throws MalformedObjectNameException {
JMXExporter jmxExporter = new JMXExporter(TEST_BEAN_DOMAIN + ":*");
Collection<State> values = jmxExporter.getValues();
assertThat(values.size()).isEqualTo(7);
}
@Test
public void convertToLong() throws MalformedObjectNameException, MBeanRegistrationException,
InstanceAlreadyExistsException, NotCompliantMBeanException {
JMXExporter jmxExporter = new JMXExporter(TEST_BEAN_DOMAIN + ":*");
Collection<State> values = jmxExporter.getValues();
assertValue(values, "long", 1234567890L);
assertValue(values, "int", 65536L);
assertValue(values, "double", 1);
assertValue(values, "float", 2);
assertValue(values, "short", 17);
assertValue(values, "boolean", 1);
assertValue(values, "long_composite", 3232323232L);
}
@Test
public void beAbleToHandleJavaLangWithoutExceptionInGetValues() throws MalformedObjectNameException {
JMXExporter jmxExporter = new JMXExporter(JAVA_LANG + ":*");
jmxExporter.getValues();
}
@Test
public void generateStrictlyValidValueKeysForTestBean() throws MalformedObjectNameException {
JMXExporter jmxExporter = new JMXExporter(TEST_BEAN_DOMAIN + ":*");
Collection<State> values = jmxExporter.getValues();
ValidatingKeyHandler validatingKeyHandler = new ValidatingKeyHandler();
for (State value : values) {
validatingKeyHandler.handle(value.name);
}
}
@Test
public void generateStrictlyValidValueKeysForJavaLang() throws MalformedObjectNameException {
JMXExporter jmxExporter = new JMXExporter(JAVA_LANG + ":*");
Collection<State> values = jmxExporter.getValues();
ValidatingKeyHandler validatingKeyHandler = new ValidatingKeyHandler();
for (State value : values) {
validatingKeyHandler.handle(value.name);
}
}
@Test
public void readPatternFromFile() throws Exception {
URL url = getClass().getResource("/jmxExporter/patternTestFile.txt");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromFile(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(2);
}
@Test
public void eachPatternOnlyAddedOnce() throws Exception {
URL url = getClass().getResource("/jmxExporter/duplicatePatternTestFile.txt");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromFile(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(1);
}
@Test
public void nonExistingSilentlyIgnored() throws Exception {
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromDirectory("nonExistingDir");
assertThat(jmxExporter.listPatterns().size()).isEqualTo(0);
}
@Test
public void emptyDirIsOkay() throws Exception {
URL url = getClass().getResource("/emptyDir");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromDirectory(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(0);
}
@Test
public void readPatternFilesFromDir() throws Exception {
URL url = getClass().getResource("/jmxExporter");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromDirectory(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(2);
}
@Test
public void EmptyLinesInPatternFromFileWillNotLeadToMatchAllObjectName() throws Exception {
URL url = getClass().getResource("/jmxExporter/emptyLinePatternTestFile.txt");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromFile(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(2);
}
@Test
public void skipInvalidPatternWhenReadingFromFile() throws Exception {
URL url = getClass().getResource("/jmxExporter/invalidPatternTestFile.txt");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromFile(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(1);
}
@Test
public void doNotFailOnEmptyFile() throws Exception {
URL url = getClass().getResource("/jmxExporter/emptyPatternTestFile.txt");
JMXExporter jmxExporter = new JMXExporter();
jmxExporter.readFromFile(url.getFile());
assertThat(jmxExporter.listPatterns().size()).isEqualTo(0);
}
private void assertValue(Collection<State> values, String name, long targetValue) {
int checked = 0;
for (State state : values) {
if (state.name.endsWith(name)) {
assertThat(state.value).isEqualTo(targetValue);
checked++;
}
}
assertThat(checked).isEqualTo(1);
}
private class TestMBean implements DynamicMBean {
private String[] itemNames = new String[] { "long_composite", "string_composite" };
private String[] itemDescriptions = new String[] { "a long", "a string" };
private OpenType[] itemTypes = new OpenType[] { SimpleType.LONG, SimpleType.STRING };
private Object[] itemValues = new Object[] { new Long(3232323232L), "lalala" };
private CompositeType compositeType;
public TestMBean() throws OpenDataException {
compositeType = new CompositeType("testCompositeType", "a text composite", itemNames, itemDescriptions,
itemTypes);
}
@Override
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException,
MBeanException, ReflectionException {
}
@Override
public AttributeList getAttributes(String[] attributes) {
return null;
}
@Override
public AttributeList setAttributes(AttributeList attributes) {
return null;
}
@Override
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException,
ReflectionException {
return null;
}
@Override
public MBeanInfo getMBeanInfo() {
return new MBeanInfo("TestMBean",
"", getAttributeInfos(), null, null, null);
}
public MBeanAttributeInfo[] getAttributeInfos() {
return new MBeanAttributeInfo[] {
new MBeanAttributeInfo("long", "long", "long", true, false, false),
new MBeanAttributeInfo("long_not_supported", "long", "long", true, false, false),
new MBeanAttributeInfo("int", "int", "int", true, false, false),
new MBeanAttributeInfo("double", "double", "double", true, false, false),
new MBeanAttributeInfo("float", "float", "float", true, false, false),
new MBeanAttributeInfo("short", "short", "short", true, false, false),
new MBeanAttributeInfo("boolean", "boolean", "boolean", true, false, false),
new MBeanAttributeInfo("string", "java.lang.String", "string", true, false, false),
new MBeanAttributeInfo("composite", "javax.management.openmbean.CompositeType", "a composite", true, false,
false),
};
}
/* (non-Javadoc)
* @see de.is24.util.monitoring.jmx.JmxReportable#getAttribute(java.lang.String)
*/
public Object getAttribute(String attributeName) {
if (attributeName.equals("long")) {
return 1234567890L;
} else if (attributeName.equals("long_not_supported")) {
throw new UnsupportedOperationException("long_not_supported is not supported");
} else if (attributeName.equals("int")) {
return 65536;
} else if (attributeName.equals("double")) {
return 1.73;
} else if (attributeName.equals("float")) {
return 2.48f;
} else if (attributeName.equals("short")) {
return (short) 17;
} else if (attributeName.equals("boolean")) {
return true;
} else if (attributeName.equals("string")) {
return "string";
} else if (attributeName.endsWith("composite")) {
try {
return new CompositeDataSupport(compositeType, itemNames, itemValues);
} catch (OpenDataException e) {
throw new RuntimeException(e);
}
}
return null;
}
}
}