package org.togglz.appengine.repository; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.togglz.core.Feature; import org.togglz.core.repository.FeatureState; import org.togglz.core.repository.StateRepository; import com.google.appengine.api.memcache.MemcacheService; import com.google.appengine.api.memcache.MemcacheServiceFactory; import com.google.appengine.tools.development.testing.LocalMemcacheServiceTestConfig; import com.google.appengine.tools.development.testing.LocalServiceTestHelper; /** * Unit Tests for MemcacheStateRepository * * @author Fábio Franco Uechi */ public class MemcacheStateRepositoryTest { private final LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalMemcacheServiceTestConfig()); private MemcacheService ms = MemcacheServiceFactory.getMemcacheService(); private StateRepository delegate; @Before public void setUp() { helper.setUp(); delegate = Mockito.mock(StateRepository.class); Mockito.when(delegate.getFeatureState(TestFeature.F1)) .thenReturn(new FeatureState(TestFeature.F1, true)); } @After public void tearDown() { ms.clearAll(); helper.tearDown(); delegate = null; } @Test public void testCachingOfReadOperationsWithTimeToLife() throws InterruptedException { MemcacheStateRepository repository = new MemcacheStateRepository(delegate); // do some lookups for (int i = 0; i < 10; i++) { assertTrue(repository.getFeatureState(TestFeature.F1).isEnabled()); Thread.sleep(10); } // delegate only called once Mockito.verify(delegate).getFeatureState(TestFeature.F1); Mockito.verifyNoMoreInteractions(delegate); assertTrue(ms.contains(repository.key(TestFeature.F1.name()))); } @Test public void testStateModifyExpiresCache() throws InterruptedException { MemcacheStateRepository repository = new MemcacheStateRepository(delegate); // do some lookups for (int i = 0; i < 5; i++) { assertTrue(repository.getFeatureState(TestFeature.F1).isEnabled()); Thread.sleep(10); } assertTrue(ms.contains(repository.key(TestFeature.F1.name()))); // now modify the feature state repository.setFeatureState(new FeatureState(TestFeature.F1, true)); assertFalse(ms.contains(repository.key(TestFeature.F1.name()))); // do some lookups for (int i = 0; i < 5; i++) { assertTrue(repository.getFeatureState(TestFeature.F1).isEnabled()); Thread.sleep(10); } assertTrue(ms.contains(repository.key(TestFeature.F1.name()))); // Check for the correct number of invocations Mockito.verify(delegate, Mockito.times(2)).getFeatureState(TestFeature.F1); Mockito.verify(delegate).setFeatureState(Mockito.any(FeatureState.class)); Mockito.verifyNoMoreInteractions(delegate); } @Test public void testCacheExpiryBecauseOfTimeToLife() throws InterruptedException { int ttl = 5; MemcacheStateRepository repository = new MemcacheStateRepository(delegate, ttl); // do some lookups for (int i = 0; i < 5; i++) { assertTrue(repository.getFeatureState(TestFeature.F1).isEnabled()); Thread.sleep(ttl + 10); // wait some minimal amount of time to let the cache expire } // delegate called 5 times Mockito.verify(delegate, Mockito.times(5)).getFeatureState(TestFeature.F1); Mockito.verifyNoMoreInteractions(delegate); } @Test public void testNullCaching() throws InterruptedException { MemcacheStateRepository repository = new MemcacheStateRepository(delegate); // do some lookups for (int i = 0; i < 10; i++) { assertNull(repository.getFeatureState(TestFeature.F2)); Thread.sleep(10); } // delegate only called once Mockito.verify(delegate).getFeatureState(TestFeature.F2); Mockito.verifyNoMoreInteractions(delegate); assertTrue(ms.contains(repository.key(TestFeature.F2.name()))); } private enum TestFeature implements Feature { F1, F2 } }