CachingStateRepository implements StateRepository { @Override public FeatureState getFeatureState(Feature feature) { CacheEntry entry = cache.get(feature.name()); if (entry != null && !isExpired(entry)) { return entry.getState() != null ? entry.getState().copy() : null; } FeatureState featureState = delegate.getFeatureState(feature); cache.put(feature.name(), new CacheEntry(featureState != null ? featureState.copy() : null)); return featureState; } CachingStateRepository(StateRepository delegate);  CachingStateRepository(StateRepository delegate, long ttl);  CachingStateRepository(StateRepository delegate, long ttl, TimeUnit ttlTimeUnit); @Override FeatureState getFeatureState(Feature feature); @Override void setFeatureState(FeatureState featureState); void clear();  }
@Test void testCachingOfReadOperationsWithTimeToLife() throws InterruptedException { StateRepository repository = new CachingStateRepository(delegate, 10000); for (int i = 0; i < 10; i++) { assertTrue(repository.getFeatureState(DummyFeature.TEST).isEnabled()); Thread.sleep(10); } Mockito.verify(delegate).getFeatureState(DummyFeature.TEST); Mockito.verifyNoMoreInteractions(delegate); }
@Test void testCacheWithDifferentFeatureImplementations() throws InterruptedException { StateRepository repository = new CachingStateRepository(delegate, 0); for (int i = 0; i < 10; i++) { Feature feature = (i % 2 == 0) ? DummyFeature.TEST : new NamedFeature(DummyFeature.TEST.name()); assertTrue(repository.getFeatureState(feature).isEnabled()); Thread.sleep(10); } Mockito.verify(delegate).getFeatureState(DummyFeature.TEST); Mockito.verifyNoMoreInteractions(delegate); }
@Test void testCachingOfReadOperationsWithoutTimeToLife() throws InterruptedException { StateRepository repository = new CachingStateRepository(delegate, 0); for (int i = 0; i < 10; i++) { assertTrue(repository.getFeatureState(DummyFeature.TEST).isEnabled()); Thread.sleep(10); } Mockito.verify(delegate).getFeatureState(DummyFeature.TEST); Mockito.verifyNoMoreInteractions(delegate); }
@Test void testCacheExpiryBecauseOfTimeToLife() throws InterruptedException { long ttl = 5; StateRepository repository = new CachingStateRepository(delegate, ttl); for (int i = 0; i < 5; i++) { assertTrue(repository.getFeatureState(DummyFeature.TEST).isEnabled()); Thread.sleep(ttl + 30); } Mockito.verify(delegate, Mockito.times(5)).getFeatureState(DummyFeature.TEST); Mockito.verifyNoMoreInteractions(delegate); }