/**
*
*/
package com.socialize.test.unit;
import com.socialize.cache.ICacheableFactory;
import com.socialize.cache.ISuicidal;
import com.socialize.cache.Key;
import com.socialize.cache.TTLCache;
import com.socialize.cache.TTLObject;
import com.socialize.test.SocializeUnitTest;
import org.mockito.Mockito;
import java.util.Collection;
import java.util.TreeMap;
/**
* @author Jason
*/
public class TTLCacheTest extends SocializeUnitTest {
private TTLCache<String, StringCacheable> cache;
private CacheListenerTest listener;
protected void setUp() throws Exception {
super.setUp();
cache = new TTLCache<String, StringCacheable>(1, 2);
cache.setDebug(true);
cache.setMaxCapacityBytes(20);
cache.setHardByteLimit(false);
listener = new CacheListenerTest();
cache.setEventListener(listener);
}
@Override
protected void tearDown() throws Exception {
cache.clear();
super.tearDown();
}
/**
* Tests that an object put into cache can be retrieved.
*/
public void testSimpleCachePut() {
StringCacheable testObj = new StringCacheable("test");
cache.put("testKey", testObj);
StringCacheable fromCache = cache.get("testKey");
assertNotNull(fromCache);
assertEquals("test", fromCache.getValue());
}
public void testOnPutCalledOnPut() {
StringCacheable testObj = new StringCacheable("test");
cache.put("testKey", testObj);
assertEquals(1, testObj.getOnPutCount());
}
public void testOnGetCalledOnGet() {
StringCacheable testObj = new StringCacheable("test");
cache.put("testKey", testObj);
cache.get("testKey");
assertEquals(1, testObj.getOnGetCount());
}
/**
* Tests that the reaper was executed when expected.
*/
public void testManualCacheReap() {
assertTrue(cache.doReap());
assertEquals(1, listener.reapStarts);
assertEquals(1, listener.reapEnds);
}
public void testScheduledCacheReap() {
assertEquals(0, listener.reapStarts);
assertEquals(0, listener.reapEnds);
cache.setReapCycle(2000);
try {
Thread.sleep(2200);
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
assertEquals(1, listener.reapStarts);
assertEquals(1, listener.reapEnds);
}
/**
* Tests that the onRemove method is called when an object is replaced.
*/
public void testOnRemoveNOTCalledOnReplace() {
StringCacheable testObj = new StringCacheable("test");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey", testObj2);
assertEquals(0, testObj.getOnRemoveCount());
}
/**
* Tests that an object expires after its ttl.
*/
public void testObjectExpiry() {
StringCacheable testObj = new StringCacheable("test");
cache.put("testKey", testObj, 100);
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
assertTrue(cache.doReap());
assertFalse(cache.exists("testKey"));
assertNull(cache.get("testKey"));
}
/**
* Tests that the onRemove method is called when an object is reaped.
*/
public void testOnRemoveCalledOnReap() {
StringCacheable testObj = new StringCacheable("test");
cache.put("testKey", testObj, 100);
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
assertTrue(cache.doReap());
assertEquals(1, testObj.getOnRemoveCount());
}
/**
* Tests that the onRemove method is called when an object is manually removed.
*/
public void testOnRemoveCalledOnRemove() {
StringCacheable testObj = new StringCacheable("test");
cache.put("testKey", testObj);
assertTrue(cache.exists("testKey"));
cache.remove("testKey");
assertFalse(cache.exists("testKey"));
assertEquals(1, testObj.getOnRemoveCount());
}
/**
* Tests that the onRemove method is called when an object is manually removed.
*/
public void testOnRemoveCalledOnClear() {
StringCacheable testObj = new StringCacheable("test");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
assertEquals(2, cache.size());
cache.clear();
assertEquals(1, testObj.getOnRemoveCount());
assertEquals(1, testObj2.getOnRemoveCount());
assertEquals(0, cache.size());
}
public void testSizeInBytesIncreasedOnPut() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
assertEquals(10, cache.sizeInBytes());
}
public void testSizeInBytesCorrectOnReplace() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey", testObj2);
assertEquals(5, cache.sizeInBytes());
}
public void testSizeInBytesCorrectOnClear() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
cache.clear();
assertEquals(0, cache.sizeInBytes());
}
public void testSizeInBytesCorrectOnReap() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2, 100);
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
assertTrue(cache.doReap());
assertEquals(0, testObj.getOnRemoveCount());
assertEquals(1, testObj2.getOnRemoveCount());
assertEquals(5, cache.sizeInBytes());
}
public void testSizeInBytesCorrectOnRemove() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
cache.remove("testKey");
assertEquals(5, cache.sizeInBytes());
}
public void testTrimOnCountExceededAfterReap() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
StringCacheable testObj3 = new StringCacheable("test3");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
cache.put("testKey3", testObj3);
assertEquals(3, cache.size());
assertTrue(cache.doReap());
assertEquals(2, cache.size());
}
public void testTrimOnBytesExceededAfterReap() {
StringCacheable testObj = new StringCacheable("0000000000");
StringCacheable testObj2 = new StringCacheable("00000000000");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
assertEquals(2, cache.size());
assertTrue(cache.doReap());
assertEquals(1, cache.size());
}
public void testPutFailOnBytesExceededWithHardLimit() {
StringCacheable testObj = new StringCacheable("0000000000");
StringCacheable testObj2 = new StringCacheable("00000000000");
cache.setHardByteLimit(true);
cache.put("testKey", testObj);
assertFalse(cache.put("testKey2", testObj2));
assertEquals(1, cache.size());
}
public void testOldestRemoveOnReap() {
StringCacheable testObj = new StringCacheable("test1");
StringCacheable testObj2 = new StringCacheable("test2");
StringCacheable testObj3 = new StringCacheable("test3");
cache.put("testKey", testObj);
cache.put("testKey2", testObj2);
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
cache.put("testKey", testObj); // replace so we know it's not just first
cache.put("testKey3", testObj3);
assertEquals(3, cache.size());
assertTrue(cache.doReap());
assertEquals(2, cache.size());
assertTrue(cache.exists("testKey"));
assertFalse(cache.exists("testKey2"));
assertTrue(cache.exists("testKey3"));
}
public void testConstructorUsesDefaultCacheCount() {
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>(1);
assertEquals(TTLCache.DEFAULT_CACHE_COUNT, cache.getMaxCapacity());
}
public void testPauseCallsStopOnReaper() {
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>() {
@Override
protected synchronized void stopReaper() {
addResult(true);
}
};
cache.pause();
Boolean result = getNextResult();
assertNotNull(result);
assertTrue(result);
}
public void testResumeCallsStartOnReaper() {
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>() {
@Override
protected synchronized void startReaper() {
addResult(true);
}
};
cache.resume();
Boolean result = getNextResult();
assertNotNull(result);
assertTrue(result);
}
public void testPutCallPutWithDefaultTTL() {
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>() {
@Override
protected synchronized boolean put(String k, StringCacheable object, long ttl, boolean eternal) {
addResult(ttl);
return true;
}
};
cache.put("foobar", null);
Long result = getNextResult();
assertNotNull(result);
assertEquals(cache.getDefaultTTL(), result.longValue());
}
@SuppressWarnings("unchecked")
public void testGetRaw() {
final TTLObject<String, StringCacheable> object = Mockito.mock(TTLObject.class);
final StringCacheable cacheable = new StringCacheable();
Mockito.when(object.getObject()).thenReturn(cacheable);
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>() {
@Override
protected TTLObject<String, StringCacheable> getTTLObject(String strKey) {
return object;
}
@Override
public boolean isExpired(TTLObject<String, StringCacheable> object) {
return false;
}
};
assertSame(cacheable, cache.getRaw("foobar"));
}
@SuppressWarnings("unchecked")
public void testCreateOnEmptyGet() {
final String key = "foobar";
final TTLObject<String, StringCacheable> object = Mockito.mock(TTLObject.class);
final ICacheableFactory<String, StringCacheable> factory = Mockito.mock(ICacheableFactory.class);
final StringCacheable cacheable = new StringCacheable();
Mockito.when(object.getObject()).thenReturn(null);
Mockito.when(factory.create(key)).thenReturn(cacheable);
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>() {
@Override
protected TTLObject<String, StringCacheable> getTTLObject(String strKey) {
return object;
}
@Override
protected synchronized boolean put(String k, StringCacheable object, long ttl, boolean eternal) {
addResult(true);
return true;
}
};
cache.setObjectFactory(factory);
assertSame(cacheable, cache.get(key));
Boolean result = getNextResult();
assertNotNull(result);
assertTrue(result);
}
public void testValues() {
final int expiredCount = 5;
int totalCount = 10;
TTLCache<String, StringCacheable> cache = new TTLCache<String, StringCacheable>() {
@Override
public boolean isExpired(TTLObject<String, StringCacheable> object) {
Integer nextResult = getNextResult();
if(nextResult == null) {
addResult(1);
return true;
}
else if(nextResult >= expiredCount) {
addResult(++nextResult);
return false;
}
else {
addResult(++nextResult);
return true;
}
}
};
for (int i = 0; i < totalCount; i++) {
StringCacheable value = new StringCacheable(String.valueOf(i));
cache.put(String.valueOf(i), value);
}
Collection<StringCacheable> values = cache.values();
assertNotNull(values);
assertEquals((totalCount - expiredCount), values.size());
}
@SuppressWarnings("unchecked")
public void testNotExpired() {
TTLObject<String, StringCacheable> obj = Mockito.mock(TTLObject.class);
Mockito.when(obj.getObject()).thenReturn(null);
Mockito.when(obj.isEternal()).thenReturn(false);
Mockito.when(obj.getLifeExpectancy()).thenReturn(Long.MAX_VALUE);
assertFalse(cache.isExpired(obj));
}
@SuppressWarnings("unchecked")
public void testExpired() {
TTLObject<String, StringCacheable> obj = Mockito.mock(TTLObject.class);
Mockito.when(obj.getObject()).thenReturn(null);
Mockito.when(obj.isEternal()).thenReturn(false);
Mockito.when(obj.getLifeExpectancy()).thenReturn(0L);
assertTrue(cache.isExpired(obj));
}
@SuppressWarnings("unchecked")
public void testExpiredSuicical() {
TTLCache<String, ISuicidal<String>> cache = new TTLCache<String, ISuicidal<String>>();
TTLObject<String, ISuicidal<String>> obj = Mockito.mock(TTLObject.class);
ISuicidal<String> s = Mockito.mock(ISuicidal.class);
Mockito.when(obj.getObject()).thenReturn(s);
Mockito.when(s.isDead()).thenReturn(true);
assertTrue(cache.isExpired(obj));
}
public void testKey() {
Key<String> key1 = new Key<String>("foobar1", 0);
Key<String> key2 = new Key<String>("foobar1", 0);
Key<String> key3 = new Key<String>("foobar2", 0);
assertFalse(key1.equals(key3));
assertTrue(key1.equals(key2));
}
public void testKeyCompare() {
Key<String> key1 = new Key<String>("foobar1", 100);
Key<String> key2 = new Key<String>("foobar1", 200);
// key1 is oldest
TreeMap<Key<String>, String> sorted = new TreeMap<Key<String>, String>();
sorted.put(key1, "foo");
sorted.put(key2, "bar");
Key<String> firstKey = sorted.firstKey();
assertSame(key1, firstKey);
TreeMap<Key<String>, String> sorted2 = new TreeMap<Key<String>, String>();
sorted2.put(key2, "bar");
sorted2.put(key1, "foo");
Key<String> firstKey2 = sorted2.firstKey();
assertSame(key1, firstKey2);
}
}