/*
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.richfaces.cache;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jboss.test.faces.AbstractFacesTest;
import org.junit.Assert;
import org.richfaces.application.CoreConfiguration;
/**
* @author Nick Belaevski
* @since 4.0
*/
public abstract class BaseCacheTest extends AbstractFacesTest {
private int sizeLimit;
private CacheManager cacheManager;
private Cache cache;
private String cacheManagerFactoryClassName;
public BaseCacheTest(String cacheManagerFactoryClassName) {
super();
this.cacheManagerFactoryClassName = cacheManagerFactoryClassName;
}
@Override
protected void setupJsfInitParameters() {
super.setupJsfInitParameters();
this.facesServer.addInitParameter(CacheManager.CACHE_MANAGER_FACTORY_CLASS, cacheManagerFactoryClassName);
this.facesServer.addInitParameter(CoreConfiguration.RESOURCES_CACHE_SIZE_PARAM_NAME, Integer.toString(sizeLimit));
}
protected Cache getCache() {
return cache;
}
@Override
public void setUp() throws Exception {
sizeLimit = 64;
super.setUp();
setupFacesRequest();
cacheManager = new CacheManager();
Map<?, ?> initParameterMap = facesContext.getExternalContext().getInitParameterMap();
this.cache = cacheManager.createCache(facesContext, "test-cache", initParameterMap);
}
@Override
public void tearDown() throws Exception {
super.tearDown();
cacheManager.destroy();
}
public void testBasic() throws Exception {
assertNull(cache.get("a"));
cache.put("a", "value-a", null);
assertEquals("value-a", cache.get("a"));
}
public void testExpiration() throws Exception {
assertNull(cache.get("a"));
long sleepTime = 0;
long expirationTime = System.currentTimeMillis() + 3000;
cache.put("a", "value-a", new Date(expirationTime));
assertEquals("value-a", cache.get("a"));
cache.put("b", "value-b", new Date(expirationTime));
assertEquals("value-b", cache.get("b"));
// interval to reach 1 second before expiration time
sleepTime = expirationTime - 1000 - System.currentTimeMillis();
assertTrue(sleepTime > 0);
Thread.sleep(sleepTime);
assertEquals("value-a", cache.get("a"));
// interval to reach 1 second after expiration time
sleepTime = expirationTime + 1000 - System.currentTimeMillis();
assertTrue(sleepTime > 0);
Thread.sleep(sleepTime);
assertNull(cache.get("a"));
}
public void testMaxSize() throws Exception {
Date expirationDate = new Date(System.currentTimeMillis() + 3600000 /* one hour - this should be enough for our test */);
Map<String, String> data = new LinkedHashMap<String, String>();
for (int i = 0; i < sizeLimit; i++) {
String key = UUID.randomUUID().toString();
String value = UUID.randomUUID().toString();
data.put(key, value);
cache.put(key, value, expirationDate);
}
for (Map.Entry<String, String> entry : data.entrySet()) {
String key = entry.getKey();
Object cacheValue = cache.get(key);
assertEquals(entry.getValue(), cacheValue);
}
String extraEntryKey = UUID.randomUUID().toString();
String extraEntryValue = UUID.randomUUID().toString();
data.put(extraEntryKey, extraEntryValue);
cache.put(extraEntryKey, extraEntryValue, expirationDate);
// give cache time to evict
Thread.sleep(2000);
int nullCounter = 0;
for (Map.Entry<String, String> entry : data.entrySet()) {
String key = entry.getKey();
Object cacheValue = cache.get(key);
if (cacheValue == null) {
nullCounter++;
} else {
assertEquals(entry.getValue(), cacheValue);
}
}
assertTrue(nullCounter == 1);
}
public void testThreads() throws Exception {
final AtomicBoolean failure = new AtomicBoolean();
Thread[] writerThreads = new Thread[10];
for (int i = 0; i < writerThreads.length; i++) {
writerThreads[i] = new Thread() {
public void run() {
final String key = UUID.randomUUID().toString();
final String value = UUID.randomUUID().toString();
cache.put(key, value, null);
Thread[] threads = new Thread[25];
for (int j = 0; j < threads.length; j++) {
threads[j] = new Thread() {
@Override
public void run() {
int retries = 1000;
for (int k = 0; k < retries; k++) {
if (!value.equals(cache.get(key))) {
failure.set(true);
return;
}
}
}
};
}
for (Thread thread : threads) {
thread.start();
}
int retries = 1000;
for (int k = 0; k < retries; k++) {
if (!value.equals(cache.get(key))) {
failure.set(true);
}
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
failure.set(true);
}
}
}
;
};
}
for (Thread thread : writerThreads) {
thread.start();
}
for (Thread thread : writerThreads) {
thread.join();
}
Assert.assertFalse(failure.get());
}
}