2 * Copyright 2005-2010 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.cache;
18 import static org.mockito.Matchers.*;
19 import static org.mockito.Mockito.*;
21 import java.io.IOException;
23 import junit.framework.TestCase;
24 import net.sf.ehcache.CacheException;
26 import org.mockito.invocation.InvocationOnMock;
27 import org.mockito.stubbing.Answer;
28 import org.wamblee.io.TestResource;
29 import org.wamblee.test.TimingUtils;
34 * @author Erik Brakkee
36 public class CachedObjectTest extends TestCase {
37 private static final String EHCACHE_CONFIG = "ehcache.xml";
38 private static final int OBJECT_KEY = 10;
39 private CachedObject.Computation<Integer, Integer> computation;
40 private int ncomputations;
42 private synchronized void incrementComputations() {
46 private synchronized int getComputationCount() {
53 * @see junit.framework.TestCase#setUp()
56 protected void setUp() throws Exception {
58 computation = mock(CachedObject.Computation.class);
59 when(computation.getObject(anyInt())).thenAnswer(new Answer<Integer>() {
60 public Integer answer(
61 org.mockito.invocation.InvocationOnMock aInvocation)
64 return compute((Integer) aInvocation.getArguments()[0]);
70 private int compute(int aValue) {
74 private CachedObject<Integer, Integer> createCached(
75 Cache<Integer, Integer> aCache) {
76 return new CachedObject<Integer, Integer>(aCache, OBJECT_KEY,
81 * Verifies that upon first use, the cached object uses the computation to
82 * retrieve the object.
85 public void testComputation() {
86 CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
87 int value = cached.get();
88 assertEquals(compute(OBJECT_KEY), value);
89 assertEquals(1, ncomputations);
92 public void testInvalidateCache() {
93 CachedObject<Integer, Integer> cached = createCached(new ForeverCache<Integer, Integer>());
94 int value = cached.get();
95 assertEquals(compute(OBJECT_KEY), value);
96 assertEquals(1, ncomputations);
99 assertEquals(compute(OBJECT_KEY), value);
100 assertEquals(2, ncomputations);
103 public void testBehaviorEhCache() throws CacheException, IOException {
104 Cache<Integer, Integer> cache = new EhCache<Integer, Integer>(
105 new TestResource(CachedObjectTest.class, EHCACHE_CONFIG), "test");
106 CachedObject<Integer, Integer> cached = createCached(cache);
108 assertTrue(cache == cached.getCache());
110 int value = cached.get();
111 assertEquals(compute(OBJECT_KEY), value);
112 assertEquals(1, getComputationCount());
113 // The value must still be cached.
114 value = cached.get();
115 assertEquals(compute(OBJECT_KEY), value);
116 assertEquals(1, getComputationCount());
119 TimingUtils.sleep(6000);
120 value = cached.get();
121 assertEquals(compute(OBJECT_KEY), value);
122 assertEquals(2, getComputationCount());
124 // Should still be cached now.
125 value = cached.get();
126 assertEquals(compute(OBJECT_KEY), value);
127 assertEquals(2, getComputationCount());
129 // explicit invalidation.
131 value = cached.get();
132 assertEquals(compute(OBJECT_KEY), value);
133 assertEquals(3, getComputationCount());
136 public void testBehaviorEhCacheDefault() throws CacheException, IOException {
137 Cache<Integer, Integer> cache = new EhCache<Integer, Integer>(
138 new TestResource(CachedObjectTest.class, EHCACHE_CONFIG),
140 CachedObject<Integer, Integer> cached = createCached(cache);
142 assertTrue(cache == cached.getCache());
144 int value = cached.get();
145 assertEquals(compute(OBJECT_KEY), value);
146 assertEquals(1, getComputationCount());
147 // The value must still be cached.
148 value = cached.get();
149 assertEquals(compute(OBJECT_KEY), value);
150 assertEquals(1, getComputationCount());
153 TimingUtils.sleep(6000);
154 value = cached.get();
155 assertEquals(compute(OBJECT_KEY), value);
156 assertEquals(2, getComputationCount());
158 // Should still be cached now.
159 value = cached.get();
160 assertEquals(compute(OBJECT_KEY), value);
161 assertEquals(2, getComputationCount());
164 public void testBehaviorForeverCache() {
165 CachedObject<Integer, Integer> cached = createCached(new ForeverCache<Integer, Integer>());
166 int value = cached.get();
167 assertEquals(compute(OBJECT_KEY), value);
168 assertEquals(1, getComputationCount());
170 for (int ncomp = 2; ncomp <= 100; ncomp++) {
171 value = cached.get();
172 assertEquals(compute(OBJECT_KEY), value);
173 assertEquals(1, getComputationCount());
177 public void testBehaviorZeroCache() {
178 CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
179 int value = cached.get();
180 assertEquals(compute(OBJECT_KEY), value);
181 assertEquals(1, getComputationCount());
183 for (int ncomp = 2; ncomp <= 100; ncomp++) {
184 value = cached.get();
185 assertEquals(compute(OBJECT_KEY), value);
186 assertEquals(ncomp, getComputationCount());
190 value = cached.get();
191 assertEquals(compute(OBJECT_KEY), value);
192 assertEquals(101, getComputationCount());
195 public void testPreviousValueWhileComputationBeingDone() throws Exception {
196 final CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
198 when(computation.getObject(anyInt())).thenReturn(1).thenAnswer(
199 new Answer<Integer>() {
201 public Integer answer(InvocationOnMock aInvocation)
203 TimingUtils.sleep(1000);
208 assertEquals(1, cached.get().intValue());
209 Thread recompute = new Thread(new Runnable() {
213 // will sleep for 1 second.
214 assertEquals(2, cached.get().intValue());
218 // Now asking the value should not recompute but should return the old
220 TimingUtils.sleep(500);
221 assertEquals(1, cached.get().intValue());
225 public void testNullValueWhenComputationReturnsNull() throws Exception {
226 final CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
228 when(computation.getObject(anyInt())).thenReturn(1).thenReturn(null)
231 assertEquals(1, cached.get().intValue());
232 assertNull(cached.get());
233 assertEquals(2, cached.get().intValue());
236 public void testPreviousValueWhenComputationThrowsException()
238 final CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
240 when(computation.getObject(anyInt())).thenReturn(1).thenThrow(
241 new RuntimeException()).thenReturn(2);
243 assertEquals(1, cached.get().intValue());
244 assertEquals(1, cached.get().intValue());
245 assertEquals(2, cached.get().intValue());