/*
* 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.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.startsWith;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.google.code.ssm.Cache;
import com.google.code.ssm.CacheProperties;
import com.google.code.ssm.aop.support.AnnotationData;
import com.google.code.ssm.aop.support.InvalidAnnotationException;
import com.google.code.ssm.api.CacheKeyMethod;
import com.google.code.ssm.api.ReadThroughMultiCache;
import com.google.code.ssm.api.format.Serialization;
import com.google.code.ssm.api.format.SerializationType;
import com.google.code.ssm.providers.CacheException;
/**
*
* @author Nelson Carpentier
*
*/
public class CacheBaseTest {
private CacheBase cut;
@Before
public void setUp() {
cut = new CacheBase();
}
/*
* @Test public void testKeyMethodArgs() throws Exception { try { cut.getKeyMethod(new KeyObject01());
* fail("Expected exception."); } catch (InvalidAnnotationException ex) {
* assertTrue(ex.getMessage().indexOf("0 arguments") != -1); System.out.println(ex.getMessage()); }
*
* try { cut.getKeyMethod(new KeyObject02()); fail("Expected exception."); } catch (InvalidAnnotationException ex) {
* assertTrue(ex.getMessage().indexOf("String") != -1); System.out.println(ex.getMessage()); }
*
* try { cut.getKeyMethod(new KeyObject03()); fail("Expected exception."); } catch (InvalidAnnotationException ex) {
* assertTrue(ex.getMessage().indexOf("String") != -1); System.out.println(ex.getMessage()); }
*
* try { cut.getKeyMethod(new KeyObject04()); fail("Expected exception."); } catch (InvalidAnnotationException ex) {
* assertTrue(ex.getMessage().indexOf("only one method") != -1); System.out.println(ex.getMessage()); }
*
* assertEquals("doIt", cut.getKeyMethod(new KeyObject05()).getName()); assertEquals("toString",
* cut.getKeyMethod(new KeyObject06(null)).getName()); }
*/
/*
* @Test public void testGenerateCacheKey() throws Exception { final Method method =
* KeyObject.class.getMethod("toString", (Class<?>[]) null);
*
* try { cut.generateObjectId(method, new KeyObject(null)); fail("Expected Exception."); } catch (RuntimeException
* ex) { assertTrue(ex.getMessage().indexOf("empty key value") != -1); }
*
* try { cut.generateObjectId(method, new KeyObject("")); fail("Expected Exception."); } catch (RuntimeException ex)
* { assertTrue(ex.getMessage().indexOf("empty key value") != -1); }
*
* final String result = "momma"; assertEquals(result, cut.generateObjectId(method, new KeyObject(result))); }
*/
@Test
public void testReturnTypeChecking() throws Exception {
Method method = null;
method = ReturnTypeCheck.class.getMethod("checkA", (Class<?>[]) null);
cut.verifyReturnTypeIsList(method, CacheKeyMethod.class);
method = ReturnTypeCheck.class.getMethod("checkB", (Class<?>[]) null);
cut.verifyReturnTypeIsList(method, CacheKeyMethod.class);
method = ReturnTypeCheck.class.getMethod("checkC", (Class<?>[]) null);
cut.verifyReturnTypeIsList(method, CacheKeyMethod.class);
method = ReturnTypeCheck.class.getMethod("checkD", (Class<?>[]) null);
cut.verifyReturnTypeIsList(method, CacheKeyMethod.class);
try {
method = ReturnTypeCheck.class.getMethod("checkE", (Class<?>[]) null);
cut.verifyReturnTypeIsList(method, CacheKeyMethod.class);
fail("Expected Exception.");
} catch (InvalidAnnotationException ex) {
assertTrue(ex.getMessage().indexOf("requirement") != -1);
}
}
@Test
public void getSerializationType() throws Exception {
Method method = null;
SerializationType serializationType = null;
method = SerializationTypeTestObject.class.getMethod("methodA", (Class<?>[]) null);
serializationType = cut.getSerializationType(method);
assertEquals(SerializationType.JAVA, serializationType);
method = SerializationTypeTestObject.class.getMethod("methodB", (Class<?>[]) null);
serializationType = cut.getSerializationType(method);
assertEquals(SerializationType.JSON, serializationType);
}
@Test
public void addAndGetCacheNoPrefixed() {
String cacheName = "cache1";
Cache cache = Mockito.mock(Cache.class);
Mockito.when(cache.getName()).thenReturn(cacheName);
Mockito.when(cache.getAliases()).thenReturn(Arrays.asList("cacheA1", "cacheB1"));
Mockito.when(cache.getProperties()).thenReturn(new CacheProperties());
cut.addCache(cache);
AnnotationData annotationData = new AnnotationData();
annotationData.setCacheName(cacheName);
assertSame(cache, cut.getCache(annotationData));
annotationData.setCacheName("cacheA1");
assertSame(cache, cut.getCache(annotationData));
annotationData.setCacheName("cacheB1");
assertSame(cache, cut.getCache(annotationData));
}
@Test
public void addAndGetCachePrefixed() throws TimeoutException, CacheException {
String cacheName = "cache1";
Cache cache = Mockito.mock(Cache.class);
Mockito.when(cache.getName()).thenReturn(cacheName);
Mockito.when(cache.getAliases()).thenReturn(Arrays.asList("cacheA1", "cacheB1"));
Mockito.when(cache.getProperties()).thenReturn(new CacheProperties(true, "#"));
cut.addCache(cache);
AnnotationData annotationData = new AnnotationData();
annotationData.setCacheName(cacheName);
assertNotSame(cache, cut.getCache(annotationData));
annotationData.setCacheName("cacheA1");
assertNotSame(cache, cut.getCache(annotationData));
annotationData.setCacheName("cacheB1");
assertNotSame(cache, cut.getCache(annotationData));
String keyPrefix = "cacheB1#";
String key = "testKey";
cut.getCache(annotationData).get(key, SerializationType.PROVIDER);
Mockito.verify(cache).get(startsWith(keyPrefix), eq(SerializationType.PROVIDER));
cut.getCache(annotationData).getCounter(key);
Mockito.verify(cache).getCounter(startsWith(keyPrefix));
cut.getCache(annotationData).add(key, 100, "foo", SerializationType.PROVIDER);
Mockito.verify(cache).add(startsWith(keyPrefix), eq(100), eq("foo"), eq(SerializationType.PROVIDER));
cut.getCache(annotationData).addSilently(key, 50, "foo", SerializationType.PROVIDER);
Mockito.verify(cache).addSilently(startsWith(keyPrefix), eq(50), eq("foo"), eq(SerializationType.PROVIDER));
cut.getCache(annotationData).decr(key, 5);
Mockito.verify(cache).decr(startsWith(keyPrefix), eq(5));
Collection<String> keys = Arrays.asList("testKey1", "testKey2", "testKesy3");
cut.getCache(annotationData).delete(keys);
Mockito.verify(cache).delete(Mockito.argThat(new StringCollectionMatcher(keyPrefix)));
cut.getCache(annotationData).delete(key);
Mockito.verify(cache).delete(startsWith(keyPrefix));
cut.getCache(annotationData).getBulk(keys, SerializationType.PROVIDER);
Mockito.verify(cache).getBulk(Mockito.argThat(new StringCollectionMatcher(keyPrefix)), eq(SerializationType.PROVIDER));
cut.getCache(annotationData).incr(key, 5, 1);
Mockito.verify(cache).incr(startsWith(keyPrefix), eq(5), eq(1L));
cut.getCache(annotationData).incr(key, 5, 1, 100);
Mockito.verify(cache).incr(startsWith(keyPrefix), eq(5), eq(1L), eq(100));
cut.getCache(annotationData).set(key, 300, "foo", SerializationType.PROVIDER);
Mockito.verify(cache).set(startsWith(keyPrefix), eq(300), eq("foo"), eq(SerializationType.PROVIDER));
cut.getCache(annotationData).setCounter(key, 300, 15);
Mockito.verify(cache).setCounter(startsWith(keyPrefix), eq(300), eq(15L));
cut.getCache(annotationData).setSilently(key, 300, "foo", SerializationType.PROVIDER);
Mockito.verify(cache).setSilently(startsWith(keyPrefix), eq(300), eq("foo"), eq(SerializationType.PROVIDER));
}
@Test(expected = IllegalStateException.class)
public void invalidAddCacheDuplicateName() {
String cacheName = "cache1";
Cache cache1 = Mockito.mock(Cache.class);
Cache cache2 = Mockito.mock(Cache.class);
Mockito.when(cache1.getName()).thenReturn(cacheName);
Mockito.when(cache2.getName()).thenReturn(cacheName);
cut.addCache(cache1);
cut.addCache(cache2);
}
@Test(expected = IllegalStateException.class)
public void invalidAddCacheDuplicateAlias() {
Cache cache1 = Mockito.mock(Cache.class);
Cache cache2 = Mockito.mock(Cache.class);
Mockito.when(cache1.getName()).thenReturn("cache1");
Mockito.when(cache2.getName()).thenReturn("cache2");
Mockito.when(cache2.getAliases()).thenReturn(Arrays.asList("cache1"));
cut.addCache(cache1);
cut.addCache(cache2);
}
@Test
public void verifyTypeIsList() {
assertTrue(cut.verifyTypeIsList(List.class));
assertTrue(cut.verifyTypeIsList(ArrayList.class));
assertTrue(cut.verifyTypeIsList(LinkedList.class));
assertTrue(cut.verifyTypeIsList(ArrayList.class));
assertFalse(cut.verifyTypeIsList(Integer.class));
assertFalse(cut.verifyTypeIsList(Collection.class));
assertFalse(cut.verifyTypeIsList(Map.class));
assertFalse(cut.verifyTypeIsList(Set.class));
}
@Test
public void getUpdateData() throws Exception {
AnnotationData annotationData = new AnnotationData();
annotationData.setDataIndex(-1);
Object entity = new Object();
Object result = cut.getUpdateData(annotationData, null, null, entity);
assertSame(entity, result);
annotationData = new AnnotationData();
annotationData.setReturnDataIndex(true);
result = cut.getUpdateData(annotationData, null, null, entity);
assertSame(entity, result);
annotationData = new AnnotationData();
annotationData.setDataIndex(1);
Method method = UpdateData.class.getMethod("update", new Class[] { int.class, Object.class });
result = cut.getUpdateData(annotationData, method, new Object[] { 144, entity }, entity);
assertSame(entity, result);
}
@SuppressWarnings("unused")
@Serialization(SerializationType.JAVA)
private static class SerializationTypeTestObject {
public int methodA() {
return 1;
}
@Serialization(SerializationType.JSON)
public int methodB() {
return 1;
}
}
@SuppressWarnings("unused")
private static class UpdateData {
public void update(final int id, final Object entity) {
}
}
private static class ReturnTypeCheck {
@ReadThroughMultiCache(namespace = "bubba", expiration = 10)
public List<?> checkA() {
return null;
}
@ReadThroughMultiCache(namespace = "bubba", expiration = 10)
public List<String> checkB() {
return null;
}
@ReadThroughMultiCache(namespace = "bubba", expiration = 10)
public ArrayList<?> checkC() {
return null;
}
@ReadThroughMultiCache(namespace = "bubba", expiration = 10)
public ArrayList<String> checkD() {
return null;
}
@ReadThroughMultiCache(namespace = "bubba", expiration = 10)
public String checkE() {
return null;
}
}
@SuppressWarnings("unused")
private static class KeyObject {
private final String result;
private KeyObject(final String result) {
this.result = result;
}
@Override
public String toString() {
return result;
}
}
@SuppressWarnings("unused")
private static class KeyObject01 {
@CacheKeyMethod
public void doIt(final String nonsense) {
}
}
@SuppressWarnings("unused")
private static class KeyObject02 {
@CacheKeyMethod
public void doIt() {
}
}
@SuppressWarnings("unused")
private static class KeyObject03 {
@CacheKeyMethod
public Long doIt() {
return null;
}
}
@SuppressWarnings("unused")
private static class KeyObject04 {
@CacheKeyMethod
public String doIt() {
return null;
}
@CacheKeyMethod
public String doItAgain() {
return null;
}
}
@SuppressWarnings("unused")
private static class KeyObject05 {
public static final String result = "shrimp";
@CacheKeyMethod
public String doIt() {
return result;
}
}
@SuppressWarnings("unused")
private static class KeyObject06 {
private final String result;
private KeyObject06(final String result) {
this.result = result;
}
@Override
public String toString() {
return result;
}
}
public static class StringCollectionMatcher extends BaseMatcher<Collection<String>> {
private final String prefix;
public StringCollectionMatcher(final String prefix) {
this.prefix = prefix;
}
@Override
public void describeTo(final Description arg0) {
}
@Override
public boolean matches(final Object arg0) {
if (!(arg0 instanceof Collection)) {
return false;
}
@SuppressWarnings("unchecked")
Collection<String> args = (Collection<String>) arg0;
for (String arg : args) {
if (!arg.startsWith(prefix)) {
return false;
}
}
return true;
}
}
}