/* * 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. * 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.wamblee.cache; import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.wamblee.cache.ComputedValue.Computation; public class ComputedValueTest extends TestCase { private Computation computation; private ComputedValue guard; @Override protected void setUp() throws Exception { computation = mock(Computation.class); } public void testComputeOutOfDate() { initGuard(); } private void initGuard() { guard = new ComputedValue(this, computation); assertNull(guard.getCached()); when(computation.isOutOfDate()).thenReturn(true); when(computation.compute()).thenReturn(10); int value = guard.get(); assertEquals(10, value); verify(computation).compute(); reset(computation); } public void testGetCached() { initGuard(); assertEquals(10, (int) guard.getCached()); verifyNoMoreInteractions(computation); } public void testNoComputationWhenNotOutOfDate() { initGuard(); when(computation.isOutOfDate()).thenReturn(false); assertEquals(10, (int) guard.get()); verify(computation, never()).compute(); } public void testOnlyOneConcurrentComputation() throws Exception { initGuard(); final int computeTime = 500; when(computation.isOutOfDate()).thenReturn(true); when(computation.compute()).thenAnswer(new Answer() { @Override public Integer answer(InvocationOnMock aInvocation) throws Throwable { Thread.sleep(computeTime); return 100; } }); final List results = new ArrayList(); Runnable task = new Runnable() { @Override public void run() { int res = guard.get(); results.add(res); } }; // concurrent computation in two threads. Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); Thread.sleep(computeTime / 2); // second task will return old value 10 because first one is still busy. t2.start(); t1.join(); t2.join(); assertEquals(2, results.size()); assertEquals(10, (int) results.get(0)); assertEquals(100, (int) results.get(1)); verify(computation, times(2)).isOutOfDate(); } public void testExceptionWhileComputing() { initGuard(); when(computation.isOutOfDate()).thenReturn(true); when(computation.compute()).thenThrow(new RuntimeException("xx")); try { guard.get(); fail(); } catch (RuntimeException e) { assertEquals("xx", e.getMessage()); } } public void testExceptionWhileCheckingOutOfDate() { initGuard(); when(computation.isOutOfDate()).thenThrow(new RuntimeException("xx")); try { guard.get(); fail(); } catch (RuntimeException e) { assertEquals("xx", e.getMessage()); } } }