/*
* Copyright (c) 2008-2009 Nelson Carpentier
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.google.code.ssm.aop;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.google.code.ssm.aop.support.AnnotationData;
import com.google.code.ssm.aop.support.PertinentNegativeNull;
import com.google.code.ssm.api.ReadThroughMultiCache;
/**
*
* @author Nelson Carpentier
*
*/
public class ReadThroughMultiCacheTest {
private static ReadThroughMultiCacheAdvice cut;
private ReadThroughMultiCacheAdvice.MultiCacheCoordinator coord;
@BeforeClass
public static void beforeClass() {
cut = new ReadThroughMultiCacheAdvice();
cut.setCacheBase(new CacheBase());
}
@Before
public void beforeMethod() {
coord = new ReadThroughMultiCacheAdvice.MultiCacheCoordinator(null, null);
}
@Test
public void testConvertIdObject() throws Exception {
final AnnotationData data = new AnnotationData();
data.setNamespace(RandomStringUtils.randomAlphanumeric(6));
final Map<String, Object> expectedString2Object = new HashMap<String, Object>();
final Map<Object, String> expectedObject2String = new HashMap<Object, String>();
final List<Object> idObjects = new ArrayList<Object>();
final int length = 10;
for (int ix = 0; ix < length; ix++) {
final String object = RandomStringUtils.randomAlphanumeric(2 + ix);
final String key = cut.getCacheBase().getCacheKeyBuilder().getCacheKey(object, data.getNamespace());
idObjects.add(object);
expectedObject2String.put(object, key);
expectedString2Object.put(key, object);
}
/*
* final List<Object> exceptionObjects = new ArrayList<Object>(idObjects); Object[] objs = new Object[] {
* exceptionObjects }; exceptionObjects.add(null); try { cut.convertIdObjectsToKeyMap(exceptionObjects, objs, 0,
* data); fail("Expected Exception"); } catch (InvalidParameterException ex) { }
*
* for (int ix = 0; ix < length; ix++) { if (ix % 2 == 0) { idObjects.add(idObjects.get(ix)); } }
* assertTrue(idObjects.size() > length);
*
* final ReadThroughMultiCacheAdvice.MapHolder holder = cut.convertIdObjectsToKeyMap(idObjects, new Object[] {
* idObjects }, 0, data);
*
* assertEquals(length, holder.getKey2Obj().size()); assertEquals(length, holder.getObj2Key().size());
*
* assertEquals(expectedObject2String, holder.getObj2Key()); assertEquals(expectedString2Object,
* holder.getKey2Obj());
*
* coord.setHolder(holder);
*
* assertEquals(expectedObject2String, coord.getObj2Key()); assertEquals(expectedString2Object,
* coord.getKey2Obj());
*/
}
@Test
public void testInitialKey2Result() {
final AnnotationData annotation = new AnnotationData();
annotation.setNamespace(RandomStringUtils.randomAlphanumeric(6));
final Map<String, Object> expectedString2Object = new HashMap<String, Object>();
final Map<String, Object> key2Result = new HashMap<String, Object>();
final Set<Object> missObjects = new HashSet<Object>();
final int length = 15;
for (int ix = 0; ix < length; ix++) {
final String object = RandomStringUtils.randomAlphanumeric(2 + ix);
final String key = cut.getCacheBase().getCacheKeyBuilder().getCacheKey(object, annotation.getNamespace());
expectedString2Object.put(key, object);
// There are 3 possible outcomes when fetching by key from memcached:
// 0) You hit, and the key & result are in the map
// 1) You hit, but the result is null, which counts as a miss.
// 2) You miss, and the key doesn't even get into the result map.
final int option = RandomUtils.nextInt(3);
if (option == 0) {
key2Result.put(key, key + RandomStringUtils.randomNumeric(5));
}
if (option == 1) {
key2Result.put(key, null);
missObjects.add(object);
}
if (option == 2) {
missObjects.add(object);
}
}
try {
coord.setInitialKey2Result(null);
fail("Expected Exception.");
} catch (RuntimeException ex) {
}
coord.getKey2Obj().putAll(expectedString2Object);
coord.setInitialKey2Result(key2Result);
assertTrue(coord.getMissedObjects().containsAll(missObjects));
assertTrue(missObjects.containsAll(coord.getMissedObjects()));
}
@Test
public void testGenerateResultsException() {
final List<Object> keyObjects = new ArrayList<Object>();
final Map<Object, String> obj2key = new HashMap<Object, String>();
final String keyObject = RandomStringUtils.randomAlphanumeric(8);
final String key = keyObject + "-" + RandomStringUtils.randomAlphanumeric(4);
keyObjects.add(keyObject);
obj2key.put(keyObject, key);
AnnotationData data = new AnnotationData();
data.setListIndexInKeys(0);
coord = new ReadThroughMultiCacheAdvice.MultiCacheCoordinator(null, data);
coord.setListKeyObjects(keyObjects);
coord.getObj2Key().putAll(obj2key);
try {
coord.generateResultList();
fail("Expected Exception");
} catch (RuntimeException ex) {
}
}
@Test
public void testGenerateResults() {
final List<Object> keyObjects = new ArrayList<Object>();
final Map<Object, String> obj2key = new HashMap<Object, String>();
final Map<String, Object> key2result = new HashMap<String, Object>();
final List<Object> expectedResults = new ArrayList<Object>();
final int length = 10;
for (int ix = 0; ix < length; ix++) {
final String keyObject = RandomStringUtils.randomAlphanumeric(8);
final String key = keyObject + "-" + RandomStringUtils.randomAlphanumeric(4);
keyObjects.add(keyObject);
obj2key.put(keyObject, key);
if (RandomUtils.nextBoolean()) {
final String result = RandomStringUtils.randomAlphanumeric(15);
key2result.put(key, result);
expectedResults.add(result);
} else {
key2result.put(key, new PertinentNegativeNull());
expectedResults.add(null);
}
}
AnnotationData data = new AnnotationData();
data.setListIndexInKeys(0);
coord = new ReadThroughMultiCacheAdvice.MultiCacheCoordinator(null, data);
coord.setListKeyObjects(keyObjects);
coord.getObj2Key().putAll(obj2key);
coord.getKey2Result().putAll(key2result);
final List<Object> results = coord.generateResultList();
assertEquals(length, results.size());
assertEquals(expectedResults, results);
}
@SuppressWarnings("unused")
private static class AnnotationValidator {
@ReadThroughMultiCache(namespace = "bubba")
public String cacheMe1() {
return null;
}
@ReadThroughMultiCache(namespace = "")
public String cacheMe2() {
return null;
}
@ReadThroughMultiCache()
public String cacheMe3() {
return null;
}
@ReadThroughMultiCache(namespace = "bubba", expiration = -1)
public String cacheMe4() {
return null;
}
}
}