SGF-459 - Add support for the get(key:Object, valueLoader:Callable) method in Spring Framework 4.3's Cache interface.
(cherry picked from commit 1b11b912f53b90df7b18fc40e070155096d3648e) Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -16,22 +16,26 @@
|
||||
|
||||
package org.springframework.data.gemfire.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* Test for native cache implementations.
|
||||
* Abstract base test class for native cache implementations.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author John Blum
|
||||
* @see org.springframework.cache.Cache
|
||||
*/
|
||||
public abstract class AbstractNativeCacheTest<T> {
|
||||
|
||||
protected static final String CACHE_NAME = "testCache";
|
||||
protected static final String CACHE_NAME = "Example";
|
||||
|
||||
private T nativeCache;
|
||||
private Cache cache;
|
||||
@@ -43,54 +47,65 @@ public abstract class AbstractNativeCacheTest<T> {
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
protected abstract T createNativeCache() throws Exception;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <C extends Cache> C createCache() throws Exception {
|
||||
return (C) createCache(createNativeCache());
|
||||
}
|
||||
|
||||
protected abstract Cache createCache(T nativeCache);
|
||||
|
||||
protected abstract T createNativeCache() throws Exception;
|
||||
|
||||
@Test
|
||||
public void testCacheName() throws Exception {
|
||||
assertEquals(CACHE_NAME, cache.getName());
|
||||
public void cacheNameIsEqualToExpected() throws Exception {
|
||||
assertThat(cache.getName(), is(equalTo(CACHE_NAME)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNativeCache() throws Exception {
|
||||
assertSame(nativeCache, cache.getNativeCache());
|
||||
@SuppressWarnings("unchecked")
|
||||
public void nativeCacheIsSameAsExpected() throws Exception {
|
||||
assertThat((T) cache.getNativeCache(), is(sameInstance(nativeCache)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCachePut() throws Exception {
|
||||
Object key = "enescu";
|
||||
Object value = "george";
|
||||
|
||||
assertNull(cache.get(key));
|
||||
cache.put(key, value);
|
||||
assertEquals(value, cache.get(key).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheClear() throws Exception {
|
||||
assertNull(cache.get("enescu"));
|
||||
public void cachePutIsSuccessful() throws Exception {
|
||||
assertThat(cache.get("enescu"), is(nullValue()));
|
||||
cache.put("enescu", "george");
|
||||
assertNull(cache.get("vlaicu"));
|
||||
cache.put("vlaicu", "aurel");
|
||||
cache.clear();
|
||||
assertNull(cache.get("vlaicu"));
|
||||
assertNull(cache.get("enescu"));
|
||||
assertThat(String.valueOf(cache.get("enescu").get()), is(equalTo("george")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheGetForClassType() {
|
||||
public void cacheGetForClassTypeIsSuccessful() {
|
||||
cache.put("one", Boolean.TRUE);
|
||||
cache.put("two", 'X');
|
||||
cache.put("three", 101);
|
||||
cache.put("four", Math.PI);
|
||||
cache.put("five", "TEST");
|
||||
|
||||
assertEquals(Boolean.TRUE, cache.get("one", Boolean.class));
|
||||
assertEquals(new Character('X'), cache.get("two", Character.class));
|
||||
assertEquals(new Integer(101), cache.get("three", Integer.class));
|
||||
assertEquals(new Double(Math.PI), cache.get("four", Double.class));
|
||||
assertEquals("TEST", cache.get("five", String.class));
|
||||
assertThat(cache.get("one", Boolean.class), is(equalTo(Boolean.TRUE)));
|
||||
assertThat(cache.get("two", Character.class), is(equalTo('X')));
|
||||
assertThat(cache.get("three", Integer.class), is(equalTo(101)));
|
||||
assertThat(cache.get("four", Double.class), is(equalTo(Math.PI)));
|
||||
assertThat(cache.get("five", String.class), is(equalTo("TEST")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheClearIsSuccessful() throws Exception {
|
||||
assertThat(cache.get("enescu"), is(nullValue()));
|
||||
|
||||
cache.put("enescu", "george");
|
||||
|
||||
assertThat(cache.get("vlaicu"), is(nullValue()));
|
||||
|
||||
cache.put("vlaicu", "aurel");
|
||||
|
||||
assertThat(cache.get("enescu", String.class), is(equalTo("george")));
|
||||
assertThat(cache.get("vlaicu", String.class), is(equalTo("aurel")));
|
||||
|
||||
cache.clear();
|
||||
|
||||
assertThat(cache.get("vlaicu"), is(nullValue()));
|
||||
assertThat(cache.get("enescu"), is(nullValue()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.isA;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import com.gemstone.gemfire.cache.CacheLoader;
|
||||
import com.gemstone.gemfire.cache.LoaderHelper;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* Tests the adaption of the {@link java.util.concurrent.Callable} in to GemFire's {@link com.gemstone.gemfire.cache.CacheLoader} interface.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Rule
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.rules.ExpectedException
|
||||
* @see org.junit.runner.RunWith
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.runners.MockitoJUnitRunner
|
||||
* @see java.util.concurrent.Callable
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
* @see com.gemstone.gemfire.cache.LoaderHelper
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CallableCacheLoaderAdapterTest {
|
||||
|
||||
@Mock
|
||||
private CacheLoader<String, Object> mockCacheLoader;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
private LoaderHelper<String, Object> mockLoaderHelper;
|
||||
|
||||
@Mock
|
||||
private Region<String, Object> mockRegion;
|
||||
|
||||
@Test
|
||||
public void constructCallableCacheLoaderAdapterWithArgumentKeyAndRegion() {
|
||||
CallableCacheLoaderAdapter<String, Object> instance = new CallableCacheLoaderAdapter<String, Object>(
|
||||
mockCacheLoader, "key", mockRegion, "test");
|
||||
|
||||
assertThat(instance, is(notNullValue()));
|
||||
assertThat(instance.getCacheLoader(), is(sameInstance(mockCacheLoader)));
|
||||
assertThat(instance.getKey(), is(equalTo("key")));
|
||||
assertThat(instance.getRegion(), is(sameInstance(mockRegion)));
|
||||
assertThat(String.valueOf(instance.getArgument()), is(equalTo("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructCallableCacheLoaderAdapterWithKeyRegionAndNoArgument() {
|
||||
CallableCacheLoaderAdapter<String, Object> instance = new CallableCacheLoaderAdapter<String, Object>(
|
||||
mockCacheLoader, "key", mockRegion);
|
||||
|
||||
assertThat(instance, is(notNullValue()));
|
||||
assertThat(instance.getCacheLoader(), is(sameInstance(mockCacheLoader)));
|
||||
assertThat(instance.getKey(), is(equalTo("key")));
|
||||
assertThat(instance.getRegion(), is(sameInstance(mockRegion)));
|
||||
assertThat(instance.getArgument(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructCallableCacheLoaderAdapterWithNoArgumentKeyOrRegion() {
|
||||
CallableCacheLoaderAdapter<String, Object> instance =
|
||||
new CallableCacheLoaderAdapter<String, Object>(mockCacheLoader);
|
||||
|
||||
assertThat(instance, is(notNullValue()));
|
||||
assertThat(instance.getCacheLoader(), is(sameInstance(mockCacheLoader)));
|
||||
assertThat(instance.getKey(), is(nullValue()));
|
||||
assertThat(instance.getRegion(), is(nullValue()));
|
||||
assertThat(instance.getArgument(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructCallableCacheLoaderAdapterWithNullCacheLoader() {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("CacheLoader must not be null");
|
||||
|
||||
new CallableCacheLoaderAdapter<Object, Object>(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void callDelegatesToLoad() throws Exception {
|
||||
CallableCacheLoaderAdapter<String, Object> instance = new CallableCacheLoaderAdapter<String, Object>(
|
||||
mockCacheLoader, "key", mockRegion, "test");
|
||||
|
||||
when(mockCacheLoader.load(any(LoaderHelper.class))).thenAnswer(new Answer<String>() {
|
||||
public String answer(final InvocationOnMock invocation) throws Throwable {
|
||||
LoaderHelper<String, Object> loaderHelper = invocation.getArgumentAt(0, LoaderHelper.class);
|
||||
|
||||
assertThat(loaderHelper, is(notNullValue()));
|
||||
assertThat((String) loaderHelper.getArgument(), is(equalTo("test")));
|
||||
assertThat(loaderHelper.getKey(), is(equalTo("key")));
|
||||
assertThat(loaderHelper.getRegion(), is(sameInstance(mockRegion)));
|
||||
|
||||
return "mockValue";
|
||||
}
|
||||
});
|
||||
|
||||
assertThat((String) instance.call(), is(equalTo("mockValue")));
|
||||
|
||||
verify(mockCacheLoader, times(1)).load(isA(LoaderHelper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callThrowsIllegalStateExceptionForNullKey() throws Exception {
|
||||
CallableCacheLoaderAdapter<String, Object> instance = new CallableCacheLoaderAdapter<String, Object>(
|
||||
mockCacheLoader, null, mockRegion);
|
||||
|
||||
assertThat(instance.getKey(), is(nullValue()));
|
||||
assertThat(instance.getRegion(), is(sameInstance(mockRegion)));
|
||||
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("The key for which the value is loaded for cannot be null");
|
||||
|
||||
instance.call();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callThrowsIllegalStateExceptionForNullRegion() throws Exception {
|
||||
CallableCacheLoaderAdapter<String, Object> instance = new CallableCacheLoaderAdapter<String, Object>(
|
||||
mockCacheLoader, "key", null);
|
||||
|
||||
assertThat(instance.getKey(), is(equalTo("key")));
|
||||
assertThat(instance.getRegion(), is(nullValue()));
|
||||
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("The Region to load cannot be null");
|
||||
|
||||
instance.call();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closeDelegatesToCacheLoaderClose() {
|
||||
new CallableCacheLoaderAdapter<String, Object>(mockCacheLoader).close();
|
||||
verify(mockCacheLoader, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadDelegatesToCacheLoaderLoad() {
|
||||
CallableCacheLoaderAdapter<String, Object> instance =
|
||||
new CallableCacheLoaderAdapter<String, Object>(mockCacheLoader);
|
||||
|
||||
when(mockCacheLoader.load(eq(mockLoaderHelper))).thenReturn("test");
|
||||
|
||||
assertThat((String) instance.load(mockLoaderHelper), is(equalTo("test")));
|
||||
|
||||
verify(mockCacheLoader, times(1)).load(eq(mockLoaderHelper));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,30 +16,44 @@
|
||||
|
||||
package org.springframework.data.gemfire.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.data.gemfire.GemfireUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.CacheFactory;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.distributed.DistributedSystem;
|
||||
|
||||
import edu.umd.cs.mtc.MultithreadedTestCase;
|
||||
import edu.umd.cs.mtc.TestFramework;
|
||||
|
||||
/**
|
||||
* Tests the interaction between the Spring Framework Cache Abstraction and GemFire as a provider
|
||||
* using Spring Data GemFire's extension.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author John Blum
|
||||
* @author Oliver Gierke
|
||||
* @see org.junit.Rule
|
||||
* @see org.junit.Test
|
||||
* @see edu.umd.cs.mtc.MultithreadedTestCase
|
||||
* @see edu.umd.cs.mtc.TestFramework
|
||||
* @see org.springframework.cache.Cache
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
// TODO avoid using actual GemFire Cache and Region instances, thereby creating a distributed system, for this test!
|
||||
// TODO Use Mocks!
|
||||
public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Object>> {
|
||||
|
||||
@Rule public ExpectedException exception = ExpectedException.none();
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Override
|
||||
protected Cache createCache(Region<Object, Object> nativeCache) {
|
||||
@@ -47,67 +61,206 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||
protected Region<Object, Object> createNativeCache() throws Exception {
|
||||
com.gemstone.gemfire.cache.Cache instance = null;
|
||||
Properties gemfireProperties = new Properties();
|
||||
|
||||
try {
|
||||
instance = CacheFactory.getAnyInstance();
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
gemfireProperties.setProperty("name", GemfireCacheTest.class.getName());
|
||||
gemfireProperties.setProperty("mcast-port", "0");
|
||||
gemfireProperties.setProperty("log-level", "warning");
|
||||
|
||||
if (instance == null) {
|
||||
DistributedSystem ds = DistributedSystem.connect(new Properties());
|
||||
instance = CacheFactory.create(ds);
|
||||
}
|
||||
com.gemstone.gemfire.cache.Cache cache = GemfireUtils.getCache();
|
||||
|
||||
Region region = instance.getRegion(CACHE_NAME);
|
||||
cache = (cache != null ? cache : new CacheFactory(gemfireProperties).create());
|
||||
|
||||
if (region == null) {
|
||||
region = instance.createRegion(CACHE_NAME, new com.gemstone.gemfire.cache.AttributesFactory().create());
|
||||
}
|
||||
Region<Object, Object> region = cache.getRegion(CACHE_NAME);
|
||||
|
||||
region = (region != null ? region : cache.createRegionFactory().create(CACHE_NAME));
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SGF-317
|
||||
* @see <a href="https://jira.spring.io/browse/SGF-317">Improve GemfireCache implementation to be able to build on Spring 4.1</a>
|
||||
*/
|
||||
@Test
|
||||
public void findsTypedValue() throws Exception {
|
||||
Cache cache = createCache();
|
||||
|
||||
GemfireCache cache = new GemfireCache(createNativeCache());
|
||||
cache.put("key", "value");
|
||||
|
||||
assertThat(cache.get("key", String.class), is("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SGF-317
|
||||
* @see <a href="https://jira.spring.io/browse/SGF-317">Improve GemfireCache implementation to be able to build on Spring 4.1</a>
|
||||
*/
|
||||
@Test
|
||||
public void skipTypeChecksIfTargetTypeIsNull() throws Exception {
|
||||
Cache cache = createCache();
|
||||
|
||||
GemfireCache cache = new GemfireCache(createNativeCache());
|
||||
cache.put("key", "value");
|
||||
|
||||
assertThat(cache.get("key", null), is((Object) "value"));
|
||||
assertThat(cache.get("key", (Class<String>) null), is("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SGF-317
|
||||
* @see <a href="https://jira.spring.io/browse/SGF-317">Improve GemfireCache implementation to be able to build on Spring 4.1</a>
|
||||
*/
|
||||
@Test
|
||||
public void throwsIllegalStateExceptionIfTypedAccessDoesntFindMatchingType() throws Exception {
|
||||
public void throwsIllegalStateExceptionIfTypedAccessDoesNotFindMatchingType() throws Exception {
|
||||
Cache cache = createCache();
|
||||
|
||||
GemfireCache cache = new GemfireCache(createNativeCache());
|
||||
cache.put("key", "value");
|
||||
|
||||
exception.expect(IllegalStateException.class);
|
||||
exception.expectMessage(Integer.class.getName());
|
||||
exception.expectMessage("value");
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectMessage(Integer.class.getName());
|
||||
expectedException.expectMessage("value");
|
||||
|
||||
cache.get("key", Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheGetWithValueLoaderFindsValue() throws Exception {
|
||||
GemfireCache cache = createCache();
|
||||
|
||||
cache.put("key", "value");
|
||||
|
||||
assertThat(String.valueOf(cache.get("key", TestCacheLoader.NULL_VALUE)), is(equalTo("value")));
|
||||
assertThat(TestCacheLoader.NULL_VALUE.wasCalled(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void cacheGetWithValueLoaderUsesValueLoader() throws Exception {
|
||||
GemfireCache cache = createCache();
|
||||
|
||||
TestCacheLoader<String> cacheLoader = new TestCacheLoader<String>("test");
|
||||
|
||||
assertThat(cache.get("key", cacheLoader), is(equalTo("test")));
|
||||
assertThat(cacheLoader.wasCalled(), is(true));
|
||||
assertThat(((Region<Object, String>) cache.getNativeCache()).get("key"), is(equalTo("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void cacheGetWithValueLoaderUsesValueLoaderReturningNull() throws Exception {
|
||||
GemfireCache cache = createCache();
|
||||
|
||||
assertThat(cache.get("key", TestCacheLoader.NULL_VALUE), is(nullValue()));
|
||||
assertThat(TestCacheLoader.NULL_VALUE.wasCalled(), is(true));
|
||||
assertThat(cache.getNativeCache().containsKey("key"), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("all")
|
||||
public void cacheGetWithValueLoaderUsesValueLoaderThrowingException() throws Exception {
|
||||
GemfireCache cache = createCache();
|
||||
|
||||
TestCacheLoader<Exception> exceptionThrowingCacheLoader = new TestCacheLoader<Exception>(
|
||||
new IllegalStateException("test"));
|
||||
|
||||
expectedException.expect(RuntimeException.class);
|
||||
expectedException.expectCause(is(nullValue(IllegalStateException.class)));
|
||||
expectedException.expectMessage(String.format("Failed to load value for key [key] using valueLoader [%1$s]",
|
||||
exceptionThrowingCacheLoader.getClass().getName()));
|
||||
|
||||
cache.get("key", exceptionThrowingCacheLoader);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheGetWithValueLoaderIsThreadSafe() throws Throwable {
|
||||
TestFramework.runOnce(new CacheGetWithValueLoaderIsThreadSafe());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected class CacheGetWithValueLoaderIsThreadSafe extends MultithreadedTestCase {
|
||||
|
||||
private GemfireCache cache;
|
||||
|
||||
private TestCacheLoader<String> cacheLoader;
|
||||
|
||||
@Override
|
||||
public void initialize(){
|
||||
super.initialize();
|
||||
|
||||
cache = createCacheHandlesCheckedException();
|
||||
|
||||
cacheLoader = new TestCacheLoader<String>("test") {
|
||||
@Override public String call() throws Exception {
|
||||
waitForTick(2);
|
||||
return super.call();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
<T extends Cache> T createCacheHandlesCheckedException() {
|
||||
try {
|
||||
return createCache();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("failed to create Cache", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void thread1() {
|
||||
assertTick(0);
|
||||
|
||||
Thread.currentThread().setName("Cache Loader Thread");
|
||||
|
||||
String value = cache.get("key", cacheLoader);
|
||||
|
||||
assertTick(2);
|
||||
assertThat(value, is(equalTo("test")));
|
||||
assertThat(cacheLoader.wasCalled(), is(true));
|
||||
}
|
||||
|
||||
public void thread2() {
|
||||
waitForTick(1);
|
||||
|
||||
Thread.currentThread().setName("Cache Reader Thread");
|
||||
|
||||
TestCacheLoader<String> illegalCacheLoader = new TestCacheLoader<String>("illegal");
|
||||
|
||||
String value = cache.get("key", illegalCacheLoader);
|
||||
|
||||
assertTick(2);
|
||||
assertThat(value, is(equalTo("test")));
|
||||
assertThat(illegalCacheLoader.wasCalled(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
protected static class TestCacheLoader<T> implements Callable<T> {
|
||||
|
||||
protected static final TestCacheLoader<Object> NULL_VALUE = new TestCacheLoader<Object>();
|
||||
|
||||
private volatile boolean called;
|
||||
|
||||
private final T value;
|
||||
|
||||
public TestCacheLoader() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public TestCacheLoader(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
protected boolean wasCalled() {
|
||||
boolean called = this.called;
|
||||
this.called = false;
|
||||
return called;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
called = true;
|
||||
|
||||
if (value instanceof Exception) {
|
||||
throw (Exception) value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user