* 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.wamblee.cache;
-import junit.framework.TestCase;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import java.io.IOException;
+import junit.framework.TestCase;
import net.sf.ehcache.CacheException;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import org.wamblee.io.TestResource;
-
import org.wamblee.test.TimingUtils;
-import java.io.IOException;
-
/**
* Cached object test.
*
private CachedObject.Computation<Integer, Integer> computation;
private int ncomputations;
+ private synchronized void incrementComputations() {
+ ncomputations++;
+ }
+
+ private synchronized int getComputationCount() {
+ return ncomputations;
+ }
+
/*
* (non-Javadoc)
*
@Override
protected void setUp() throws Exception {
super.setUp();
- computation = new CachedObject.Computation<Integer, Integer>() {
- public Integer getObject(Integer aObjectKey) {
+ computation = mock(CachedObject.Computation.class);
+ when(computation.getObject(anyInt())).thenAnswer(new Answer<Integer>() {
+ public Integer answer(
+ org.mockito.invocation.InvocationOnMock invocation)
+ throws Throwable {
ncomputations++;
-
- return compute(aObjectKey);
- };
- };
+ return compute((Integer) invocation.getArguments()[0]);
+ }
+ });
ncomputations = 0;
}
int value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
// The value must still be cached.
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
// Cache expiry.
TimingUtils.sleep(6000);
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(2, ncomputations);
+ assertEquals(2, getComputationCount());
// Should still be cached now.
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(2, ncomputations);
+ assertEquals(2, getComputationCount());
// explicit invalidation.
cached.invalidate();
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(3, ncomputations);
+ assertEquals(3, getComputationCount());
}
public void testBehaviorEhCacheDefault() throws CacheException, IOException {
int value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
// The value must still be cached.
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
// Cache expiry.
TimingUtils.sleep(6000);
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(2, ncomputations);
+ assertEquals(2, getComputationCount());
// Should still be cached now.
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(2, ncomputations);
+ assertEquals(2, getComputationCount());
}
public void testBehaviorForeverCache() {
CachedObject<Integer, Integer> cached = createCached(new ForeverCache<Integer, Integer>());
int value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
for (int ncomp = 2; ncomp <= 100; ncomp++) {
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
}
}
CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
int value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(1, ncomputations);
+ assertEquals(1, getComputationCount());
for (int ncomp = 2; ncomp <= 100; ncomp++) {
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(ncomp, ncomputations);
+ assertEquals(ncomp, getComputationCount());
}
cached.invalidate();
value = cached.get();
assertEquals(compute(OBJECT_KEY), value);
- assertEquals(101, ncomputations);
+ assertEquals(101, getComputationCount());
+ }
+
+ public void testPreviousValueWhileComputationBeingDone() throws Exception {
+ final CachedObject<Integer,Integer> cached = createCached(new ZeroCache<Integer, Integer>());
+ reset(computation);
+ when(computation.getObject(anyInt())).thenReturn(1).thenAnswer(
+ new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock aInvocation)
+ throws Throwable {
+ TimingUtils.sleep(1000);
+ return 2;
+ }
+ }
+ ).thenReturn(3);
+
+ assertEquals(1, cached.get().intValue());
+ Thread recompute = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ // will sleep for 1 second.
+ assertEquals(2, cached.get().intValue());
+ }
+ });
+ recompute.start();
+ // Now asking the value should not recompute but should return the old value.
+ TimingUtils.sleep(500);
+ assertEquals(1, cached.get().intValue());
+ recompute.join();
+ }
+
+ public void testNullValueWhenComputationReturnsNull() throws Exception {
+ final CachedObject<Integer,Integer> cached = createCached(new ZeroCache<Integer, Integer>());
+ reset(computation);
+ when(computation.getObject(anyInt())).thenReturn(1).thenReturn(null).thenReturn(2);
+
+ assertEquals(1, cached.get().intValue());
+ assertNull(cached.get());
+ assertEquals(2, cached.get().intValue());
+ }
+
+ public void testPreviousValueWhenComputationThrowsException() throws Exception {
+ final CachedObject<Integer,Integer> cached = createCached(new ZeroCache<Integer, Integer>());
+ reset(computation);
+ when(computation.getObject(anyInt())).thenReturn(1).thenThrow(new RuntimeException()).thenReturn(2);
+
+ assertEquals(1, cached.get().intValue());
+ assertEquals(1, cached.get().intValue());
+ assertEquals(2, cached.get().intValue());
}
}