package org.jolokia.history;
/*
* 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.util.*;
import javax.management.MalformedObjectNameException;
import org.jolokia.request.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.jolokia.util.RequestType.*;
import static org.testng.Assert.*;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
/**
* Unit test for history functionality
*
* @author roland
* @since Mar 9, 2010
*/
public class HistoryStoreTest {
// History store to test against
private HistoryStore store;
@BeforeMethod
public void initStore() {
store = new HistoryStore(10);
}
@Test
public void invalidHistoryKey() throws MalformedObjectNameException {
JmxReadRequest req = new JmxRequestBuilder(READ,"test:type=bla")
.attributes("bla","bla2")
.build();
try {
new HistoryKey(req);
fail("No multiple attributes allowed");
} catch (IllegalArgumentException exp) {}
}
@Test(groups = "java6")
public void invalidHistoryKeyWithPattern() throws MalformedObjectNameException {
JmxReadRequest req = new JmxRequestBuilder(READ,"test:type=*")
.attribute("bla")
.build();
try {
new HistoryKey(req);
fail("No pattern allowed");
} catch (IllegalArgumentException exp) {}
}
@Test
public void configure() throws MalformedObjectNameException {
JmxExecRequest req =
new JmxRequestBuilder(EXEC,"test:type=exec")
.operation("op")
.build();
store.configure(new HistoryKey(req), new HistoryLimit(2, 0L));
assertEquals("2 history entries",2,updateNTimesAsList(req,3).size());
store.configure(new HistoryKey(req), new HistoryLimit(4, 0L));
assertEquals("4 history entries",4,updateNTimesAsList(req,5).size());
store.configure(new HistoryKey(req), new HistoryLimit(12, 0L));
assertEquals("10 history entries (max. for store)",10,updateNTimesAsList(req,10).size());
store.setGlobalMaxEntries(20);
assertEquals("Read max entries",20,store.getGlobalMaxEntries());
assertEquals("20 history entries (max. for store)",20,updateNTimesAsList(req,30).size());
store.reset();
store.configure(new HistoryKey(req), new HistoryLimit(20, 0L));
/** 5 fresh updates yield 4 history entries returned (and 5 stored) */
assertEquals("4 history entries after reset",4,updateNTimesAsList(req,5).size());
store.configure(new HistoryKey(req), null);
assertEquals("History disabled",null,updateNTimesAsList(req,12));
}
@Test
public void reconfigure() throws MalformedObjectNameException {
JmxExecRequest req =
new JmxRequestBuilder(EXEC,"test:type=exec")
.operation("op")
.build();
store.configure(new HistoryKey(req), new HistoryLimit(2, 100L));
store.configure(new HistoryKey(req), new HistoryLimit(2, 100L));
}
@Test
public void durationBasedEvicting() throws MalformedObjectNameException {
JmxReadRequest req =
new JmxRequestBuilder(READ,"test:type=read")
.attribute("attr")
.build();
HistoryKey key = new HistoryKey(req);
store.configure(key,new HistoryLimit(0,1));
JSONArray hist = updateNTimesAsListWithSleep(req, 3, 2000);
assertEquals("1 History Entry", 1, hist.size());
}
@Test
public void singleAttributeRead() throws Exception {
JmxReadRequest req =
new JmxRequestBuilder(READ,"test:type=read")
.attribute("attr")
.build();
store.configure(new HistoryKey(req), new HistoryLimit(3, 0L));
/** 3 fresh updates yield 2 history entries returned (and 3 stored) */
assertEquals("2 history entries",2,updateNTimesAsList(req,3,"42").size());
}
@Test
public void singleAttributeWrite() throws Exception {
JmxWriteRequest req =
new JmxRequestBuilder(WRITE,"test:type=write")
.attribute("attr")
.value("val1")
.build();
store.configure(new HistoryKey(req), new HistoryLimit(5, 0L));
assertEquals("4 history entries",3,updateNTimesAsList(req,4).size());
}
@Test
public void singleAttributeAsListRead() throws Exception {
JmxReadRequest req =
new JmxRequestBuilder(READ,"test:type=read")
.attributes("attr")
.build();
store.configure(new HistoryKey(req), new HistoryLimit(5, 0L));
Map value = new HashMap();
value.put("attr","42");
JSONObject res = updateNTimesAsMap(req,4,value);
assertEquals("4 history entries",3,((List) res.get("attr")).size());
}
@Test
public void noAttributesRead() throws Exception {
String mbean = "test:type=read";
JmxReadRequest req =
new JmxRequestBuilder(READ,mbean)
.build();
store.configure(new HistoryKey(mbean,"attr1",null,null), new HistoryLimit(4, 0L));
store.configure(new HistoryKey(mbean,"attr2",null,null), new HistoryLimit(5, 0L));
Map value = new HashMap();
value.put("attr1","val1");
value.put("attr2","val2");
JSONObject history = updateNTimesAsMap(req,5,value);
assertEquals("Attr1 has 3 entries",4,((List) history.get("attr1")).size());
assertEquals("Attr2 has 4 entries",4,((List) history.get("attr2")).size());
}
@Test
public void multipleAttributeRead() throws Exception {
String mbean = "test:type=read";
JmxReadRequest req =
new JmxRequestBuilder(READ,mbean)
.attributes("attr1","attr2")
.build();
store.configure(new HistoryKey(mbean,"attr1",null,null), new HistoryLimit(3, 0L));
store.configure(new HistoryKey(mbean,"attr2",null,null), new HistoryLimit(5, 0L));
/** 5 fresh updates yield 2 history entries returned (and 3 stored) */
Map value = new HashMap();
value.put("attr1","val1");
value.put("attr2","val2");
JSONObject history = updateNTimesAsMap(req,5,value);
assertEquals("Attr1 has 3 entries",3,((List) history.get("attr1")).size());
assertEquals("Attr2 has 4 entries",4,((List) history.get("attr2")).size());
}
@Test
public void patternConfigure() throws MalformedObjectNameException {
store.configure(new HistoryKey("java.lang:type=Memory","HeapMemoryUsage",null,null), new HistoryLimit(10, 0L));
store.configure(new HistoryKey("java.lang:*", "HeapMemoryUsage", null, null), new HistoryLimit(3, 0L));
JmxReadRequest req =
new JmxRequestBuilder(READ,"java.lang:type=Memory")
.attribute("HeapMemoryUsage")
.build();
JSONArray history = updateNTimesAsList(req, 5, 4711);
assertEquals(history.size(), 3);
}
@Test
public void patternRemoveEntries() throws MalformedObjectNameException {
store.configure(new HistoryKey("java.lang:*", "HeapMemoryUsage", null, null), new HistoryLimit(3, 0L));
store.configure(new HistoryKey("java.lang:type=Memory","HeapMemoryUsage",null,null), new HistoryLimit(10, 0L));
store.configure(new HistoryKey("java.lang:*", "HeapMemoryUsage", null, null), null);
JmxReadRequest req =
new JmxRequestBuilder(READ,"java.lang:type=Memory")
.attribute("HeapMemoryUsage")
.build();
JSONArray history = updateNTimesAsList(req, 5, 4711);
assertNull(history);
}
@Test
public void patternGetEntries() throws MalformedObjectNameException {
store.configure(new HistoryKey("java.lang:*", "HeapMemoryUsage", null, null), new HistoryLimit(3, 0L));
JmxReadRequest req =
new JmxRequestBuilder(READ,"java.lang:type=Memory")
.attribute("HeapMemoryUsage")
.build();
JSONArray history = updateNTimesAsList(req, 5, 4711);
assertEquals(history.size(), 3);
}
@Test
public void size() throws Exception {
assertTrue(store.getSize() < 100);
singleAttributeRead();
assertTrue(store.getSize() > 100);
}
@Test(groups = "java6")
public void patternAttributeRead() throws Exception {
JmxReadRequest req =
new JmxRequestBuilder(READ,"test:type=*")
.build();
store.configure(new HistoryKey("test:type=read","attr1",null,null), new HistoryLimit(3, 0L));
store.configure(new HistoryKey("test:type=write","attr2",null,null), new HistoryLimit(5, 0L));
/** 5 fresh updates yield 2 history entries returned (and 3 stored) */
Map mBeanMap = new HashMap();
Map attr1Map = new HashMap();
mBeanMap.put("test:type=read",attr1Map);
attr1Map.put("attr1","val1");
Map attr2Map = new HashMap();
mBeanMap.put("test:type=write",attr2Map);
attr2Map.put("attr2","val2");
JSONObject history = updateNTimesAsMap(req,4,mBeanMap);
assertEquals("History has 2 entries",2,history.size());
assertEquals("bean1 has 1 entry",1,((Map) history.get("test:type=read")).size());
assertEquals("bean1 has 1 entry",1,((Map) history.get("test:type=write")).size());
assertEquals("attr1 has 3 history entries",3,((List) ((Map) history.get("test:type=read")).get("attr1")).size());
assertEquals("attr2 has 3 history entries",3,((List) ((Map) history.get("test:type=write")).get("attr2")).size());
}
private JSONArray updateNTimesAsListWithSleep(JmxReadRequest pReq, int pNr, long pSleep,Object ... pValue) {
return (JSONArray) updateNTimes(pReq,pNr,pSleep,pValue);
}
private JSONArray updateNTimesAsList(JmxRequest pReq, int pNr,Object ... pValue) {
return (JSONArray) updateNTimes(pReq, pNr,0L,pValue);
}
private JSONObject updateNTimesAsMap(JmxRequest pReq, int pNr,Object ... pValue) {
return (JSONObject) updateNTimes(pReq, pNr,0L,pValue);
}
private synchronized Object updateNTimes(JmxRequest pReq, int pNr,long pSleep, Object ... pValue) {
JSONObject res = new JSONObject();
if (pValue != null && pValue.length > 0) {
res.put("value",pValue[0]);
}
for (int i=0;i<pNr;i++) {
store.updateAndAdd(pReq,res);
if (pSleep != 0L) {
try {
wait(pSleep);
} catch (InterruptedException e) {
throw new IllegalArgumentException("Interrupted",e);
}
}
}
return res.get("history");
}
@Test(expectedExceptions = IllegalArgumentException.class,expectedExceptionsMessageRegExp = ".*maxEntries.*maxDuration.*")
public void invalidHistoryLimit() {
new HistoryLimit(0,0L);
}
@Test(expectedExceptions = IllegalArgumentException.class,expectedExceptionsMessageRegExp = ".*maxEntries.*")
public void invalidMaxEntriesHistoryLimit() {
new HistoryLimit(-1,0L);
}
@Test(expectedExceptions = IllegalArgumentException.class,expectedExceptionsMessageRegExp = ".*maxDuration.*")
public void invalidMaxDurationHistoryLimit() {
new HistoryLimit(0,-1L);
}
@Test
public void valueEntryTest() {
ValueEntry entry = new ValueEntry("Test",42L);
assertTrue(entry.toString().contains("42"));
assertTrue(entry.toString().contains("Test"));
}
@Test
public void historyEntryTest() {
HistoryEntry entry = new HistoryEntry(new HistoryLimit(10,20L));
entry.add("Blub",30L);
assertTrue(entry.toString().contains("10"));
assertTrue(entry.toString().contains("20"));
assertTrue(entry.toString().contains("Blub"));
}
}