(no commit message)
[utils] / support / general / src / test / java / org / wamblee / cache / CachedObjectTest.java
index da6e1be6575a98cfb1652b933382126136bc505e..da7d8d47bcf6e4b9301475400f07d2e4e52fe147 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005 the original author or authors.
+ * Copyright 2005-2010 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.
  * 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 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;
 
 /**
- * Cached object test. 
- *
+ * Cached object test.
+ * 
  * @author Erik Brakkee
  */
 public class CachedObjectTest extends TestCase {
-    
-    /**
-     * 
-     */
     private static final String EHCACHE_CONFIG = "ehcache.xml";
+    private static final int OBJECT_KEY = 10;
+    private CachedObject.Computation<Integer, Integer> computation;
+    private int ncomputations;
 
-    private static final int OBJECT_KEY = 10; 
-    
-    private CachedObject.Computation<Integer,Integer> _computation;
-    private int _ncomputations; 
-    
-    /* (non-Javadoc)
+    private synchronized void incrementComputations() {
+        ncomputations++;
+    }
+
+    private synchronized int getComputationCount() {
+        return ncomputations;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
      * @see junit.framework.TestCase#setUp()
      */
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        _computation = new CachedObject.Computation<Integer,Integer>() { 
-            public Integer getObject(Integer aObjectKey) {
-                _ncomputations++;
-                return compute(aObjectKey);
-            };
-        };
-        _ncomputations = 0; 
+        computation = mock(CachedObject.Computation.class);
+        when(computation.getObject(anyInt())).thenAnswer(new Answer<Integer>() {
+            public Integer answer(
+                org.mockito.invocation.InvocationOnMock aInvocation)
+                throws Throwable {
+                ncomputations++;
+                return compute((Integer) aInvocation.getArguments()[0]);
+            }
+        });
+        ncomputations = 0;
     }
-    
-    private int compute(int aValue) { 
+
+    private int compute(int aValue) {
         return aValue + 10;
     }
-    
-    private CachedObject<Integer, Integer> createCached(Cache<Integer,Integer> aCache) { 
-        return new CachedObject<Integer, Integer>(aCache, OBJECT_KEY, _computation);
+
+    private CachedObject<Integer, Integer> createCached(
+        Cache<Integer, Integer> aCache) {
+        return new CachedObject<Integer, Integer>(aCache, OBJECT_KEY,
+            computation);
     }
 
     /**
-     * Verifies that upon first use, the cached object uses the computation to 
-     * retrieve the object.  
-     *
+     * Verifies that upon first use, the cached object uses the computation to
+     * retrieve the object.
+     * 
      */
-    public void testComputation() { 
-        CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer,Integer>());
+    public void testComputation() {
+        CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
         int value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations); 
+        assertEquals(1, ncomputations);
     }
-    
-    public void testInvalidateCache() { 
-        CachedObject<Integer, Integer> cached = createCached(new ForeverCache<Integer,Integer>());
+
+    public void testInvalidateCache() {
+        CachedObject<Integer, Integer> cached = createCached(new ForeverCache<Integer, Integer>());
         int value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations);
-        cached.invalidate(); 
+        assertEquals(1, ncomputations);
+        cached.invalidate();
         value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(2, _ncomputations);
+        assertEquals(2, ncomputations);
     }
-    
+
     public void testBehaviorEhCache() throws CacheException, IOException {
-        Cache<Integer,Integer> cache = new EhCache<Integer,Integer>(new TestResource(CachedObjectTest.class, EHCACHE_CONFIG), "test");
+        Cache<Integer, Integer> cache = new EhCache<Integer, Integer>(
+            new TestResource(CachedObjectTest.class, EHCACHE_CONFIG), "test");
         CachedObject<Integer, Integer> cached = createCached(cache);
-        
-        assertTrue( cache == cached.getCache());
+
+        assertTrue(cache == cached.getCache());
+
         int value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations);
-        // The value must still be cached. 
-        value = cached.get(); 
+        assertEquals(1, getComputationCount());
+        // The value must still be cached.
+        value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations);
-        
-        // Cache expiry. 
-        TimingUtils.sleep(6000); 
-        value = cached.get(); 
+        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(); 
+        value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(2, _ncomputations);
-        
+        assertEquals(2, getComputationCount());
+
         // explicit invalidation.
-        cached.invalidate(); 
-        value = cached.get(); 
+        cached.invalidate();
+        value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(3, _ncomputations);
-        
+        assertEquals(3, getComputationCount());
     }
-    
+
     public void testBehaviorEhCacheDefault() throws CacheException, IOException {
-        Cache<Integer,Integer> cache = new EhCache<Integer,Integer>(new TestResource(CachedObjectTest.class, EHCACHE_CONFIG), "undefined");
+        Cache<Integer, Integer> cache = new EhCache<Integer, Integer>(
+            new TestResource(CachedObjectTest.class, EHCACHE_CONFIG),
+            "undefined");
         CachedObject<Integer, Integer> cached = createCached(cache);
-        
-        assertTrue( cache == cached.getCache());
+
+        assertTrue(cache == cached.getCache());
+
         int value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations);
-        // The value must still be cached. 
-        value = cached.get(); 
+        assertEquals(1, getComputationCount());
+        // The value must still be cached.
+        value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations);
-        
-        // Cache expiry. 
-        TimingUtils.sleep(6000); 
-        value = cached.get(); 
+        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(); 
+        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>());
+
+    public void testBehaviorForeverCache() {
+        CachedObject<Integer, Integer> cached = createCached(new ForeverCache<Integer, Integer>());
         int value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations); 
-        for (int ncomp = 2; ncomp <= 100; ncomp++) { 
-            value = cached.get(); 
+        assertEquals(1, getComputationCount());
+
+        for (int ncomp = 2; ncomp <= 100; ncomp++) {
+            value = cached.get();
             assertEquals(compute(OBJECT_KEY), value);
-            assertEquals(1, _ncomputations);
+            assertEquals(1, getComputationCount());
         }
     }
-    
-    public void testBehaviorZeroCache() { 
-        CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer,Integer>());
+
+    public void testBehaviorZeroCache() {
+        CachedObject<Integer, Integer> cached = createCached(new ZeroCache<Integer, Integer>());
         int value = cached.get();
         assertEquals(compute(OBJECT_KEY), value);
-        assertEquals(1, _ncomputations); 
-        for (int ncomp = 2; ncomp <= 100; ncomp++) { 
-            value = cached.get(); 
+        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(); 
+
+        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());
     }
 }