1 package org.onap.vid.aai.util;
3 import com.google.common.cache.CacheBuilder;
4 import com.google.common.collect.ImmutableList;
5 import org.apache.commons.lang3.RandomUtils;
6 import org.apache.commons.lang3.mutable.MutableInt;
7 import org.apache.commons.lang3.reflect.FieldUtils;
8 import org.apache.commons.lang3.tuple.Pair;
9 import org.onap.vid.exceptions.GenericUncheckedException;
10 import org.onap.vid.properties.Features;
11 import org.testng.Assert;
12 import org.testng.annotations.BeforeMethod;
13 import org.testng.annotations.DataProvider;
14 import org.testng.annotations.Test;
15 import org.togglz.core.manager.FeatureManager;
17 import java.util.concurrent.TimeUnit;
18 import java.util.function.Consumer;
19 import java.util.function.Function;
21 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
22 import static org.hamcrest.CoreMatchers.sameInstance;
23 import static org.hamcrest.MatcherAssert.assertThat;
24 import static org.hamcrest.Matchers.contains;
25 import static org.hamcrest.Matchers.*;
26 import static org.hamcrest.core.Is.is;
27 import static org.mockito.Mockito.any;
28 import static org.mockito.Mockito.*;
29 import static org.testng.AssertJUnit.assertEquals;
31 public class CacheProviderWithLoadingCacheTest {
32 private final FeatureManager featureManager = mock(FeatureManager.class);
33 private final CacheConfigProvider cacheConfigProvider = mock(CacheConfigProvider.class);
36 public void activateCacheFeatureFlag() {
37 reset(featureManager);
38 when(featureManager.isActive(Features.FLAG_1810_AAI_LOCAL_CACHE)).thenReturn(true);
39 when(cacheConfigProvider.getCacheConfig(any())).thenReturn(CacheConfig.Companion.getDefaultCacheConfig());
42 private CacheProviderWithLoadingCache createNewCacheProvider() {
43 return new CacheProviderWithLoadingCache(featureManager, cacheConfigProvider);
46 private String RAND() {
47 return randomAlphanumeric(5);
51 public void cacheProvider_requestingCache_CreatesNewCache() {
52 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
53 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(RAND(), (Integer i) -> i + 4);
55 assertThat(integerIntegerCache, notNullValue());
56 assertThat(integerIntegerCache.get(5), is(9));
60 public void cacheProvider_requestingCacheSameNameTwice_ReturnsFirstCacheInstance() {
61 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
62 final String name = RAND();
63 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(name, (Integer i) -> i + 4);
64 final CacheProvider.Cache<Integer, Integer> integerIntegerCache2 = provider.aaiClientCacheFor(name, (Integer i) -> i + 6);
66 assertThat(integerIntegerCache2, sameInstance(integerIntegerCache));
67 assertThat(integerIntegerCache.get(5), is(9)); // as the first one
71 public void cacheProvider_requestingCacheSameNameTwiceOutOfSeveral_ReturnsFirstCacheInstance() {
72 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
74 final String name = RAND();
75 provider.aaiClientCacheFor(RAND(), (Integer i) -> i + 2);
76 provider.aaiClientCacheFor(RAND(), (Integer i) -> i + 3);
77 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(name, (Integer i) -> i + 4);
78 provider.aaiClientCacheFor(RAND(), (Integer i) -> i + 5);
79 provider.aaiClientCacheFor(RAND(), (Integer i) -> i + 6);
80 final CacheProvider.Cache<Integer, Integer> integerIntegerCache2 = provider.aaiClientCacheFor(name, (Integer i) -> i + 4);
82 assertThat(integerIntegerCache2, sameInstance(integerIntegerCache));
86 public void cacheProvider_sameProviderSupportDifferentKV() {
87 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
89 assertThat(provider.aaiClientCacheFor(RAND(),
90 (Integer i) -> i + 2).get(0), is(2));
91 assertThat(provider.aaiClientCacheFor(RAND(),
92 (Integer i) -> i + 3).get(0), is(3));
93 assertThat(provider.aaiClientCacheFor(RAND(),
94 (String s) -> s + 5).get("0"), is("05"));
95 assertThat(provider.aaiClientCacheFor(RAND(),
96 (Integer i) -> "0" + i).get(0), is("00"));
97 assertThat(provider.aaiClientCacheFor(RAND(),
98 (Pair p) -> ImmutableList.of(p.getLeft(), p.getRight())).get(Pair.of(7, "B")), contains(7, "B"));
102 public void cache_callMultiTimesGetFromCahce_loaderCalledOncePairValue(){
103 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
104 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(RAND(), (Integer i) -> RandomUtils.nextInt());
105 int key = RandomUtils.nextInt();
106 Integer result1 = integerIntegerCache.get(key);
107 Integer result2 = integerIntegerCache.get(key + 1);
108 Integer result3 = integerIntegerCache.get(key);
110 Assert.assertNotEquals(result1,result2);
111 Assert.assertEquals(result1,result3);
115 public void cache_callMultiTimesGetFromCahce_loaderCalledOnce(){
116 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
117 final MutableInt counter = new MutableInt();
118 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(RAND(), (Integer i) -> {
123 int key = RandomUtils.nextInt();
124 Integer result1 = integerIntegerCache.get(key);
125 Integer result2 = integerIntegerCache.get(key);
126 Integer result3 = integerIntegerCache.get(key);
128 Assert.assertEquals(result1.intValue(),key);
129 Assert.assertEquals(result2.intValue(),key);
130 Assert.assertEquals(result3.intValue(),key);
131 Assert.assertEquals(counter.intValue(),1);
134 @Test(expectedExceptions = GenericUncheckedException.class, expectedExceptionsMessageRegExp ="boom" )
135 public void cache_inCaseLoaderMethodThrowsException_cacheThrowsSameException(){
136 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
137 final CacheProvider.Cache<String, Integer> stringIntegerCache = provider.aaiClientCacheFor(RAND(), (String s) -> { throw new GenericUncheckedException("boom");});
139 stringIntegerCache.get("Whatever");
143 public void cache_inCaseLoaderMethodThrowsException_nextCallUseLoaderMethod(){
144 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
145 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(RAND(), new Function<Integer, Integer>() {
146 private boolean firstTime = true;
148 public Integer apply(Integer i) {
151 throw new GenericUncheckedException("boom");
160 integerIntegerCache.get(1);
162 catch (GenericUncheckedException e) {}
164 assertEquals(new Integer(1), integerIntegerCache.get(1));
168 public void cache_getIsCalledMoreThanOnce_loaderNotCalledAgainForSameInputValue(){
169 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
170 final MutableInt counter = new MutableInt();
171 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(RAND(), (Integer i) -> { counter.increment(); return i; });
173 int key1 = RandomUtils.nextInt();
174 int key2 = RandomUtils.nextInt();
175 integerIntegerCache.get(key1);
176 Assert.assertEquals(counter.intValue(),1);
177 integerIntegerCache.get(key2);
178 Assert.assertEquals(counter.intValue(),2);
179 integerIntegerCache.get(key1);
180 Assert.assertEquals(counter.intValue(),2);
184 public void cache_getIsCalledMoreThanOnce_loaderIsCalledAgainAfterReset(){
185 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
186 final MutableInt counter = new MutableInt();
187 String cacheName = RAND();
189 int key1 = RandomUtils.nextInt();
190 provider.aaiClientCacheFor(cacheName, (Integer i) -> { counter.increment(); return i; }).get(key1);
191 Assert.assertEquals(counter.intValue(), 1);
192 provider.aaiClientCacheFor(cacheName, (Integer i) -> { counter.increment(); return i; }).get(key1);
193 Assert.assertEquals(counter.intValue(), 1);
195 provider.resetCache(cacheName);
196 provider.aaiClientCacheFor(cacheName, (Integer i) -> { counter.increment(); return i; }).get(key1);
197 Assert.assertEquals(counter.intValue(), 2);
202 public static class TestData {
203 public FeatureManager featureManager;
204 public String cacheName;
205 public CacheConfigProvider cacheConfigProvider;
207 public TestData(FeatureManager featureManager, String cacheName, CacheConfigProvider cacheConfigProvider) {
208 this.featureManager = featureManager;
209 this.cacheName = cacheName;
210 this.cacheConfigProvider = cacheConfigProvider;
216 public static Object[][] mockForCacheIsNotActive() {
218 Consumer<TestData> mockFeatureOff = (testData)->{
219 when(testData.featureManager.isActive(Features.FLAG_1810_AAI_LOCAL_CACHE)).thenReturn(false);
220 when(testData.cacheConfigProvider.getCacheConfig(testData.cacheName)).thenReturn(new CacheConfig(true, 10L, 10L));
222 Consumer<TestData> mockFeatureOnCacheOff = (testData)->{
223 when(testData.featureManager.isActive(Features.FLAG_1810_AAI_LOCAL_CACHE)).thenReturn(true);
224 when(testData.cacheConfigProvider.getCacheConfig(testData.cacheName)).thenReturn(new CacheConfig(false, 10L, 10L));
228 return new Object[][]{
230 {mockFeatureOnCacheOff}
235 @Test(dataProvider = "mockForCacheIsNotActive")
236 public void cache_featureFlagToggleIsOff_loaderIsCalledForEachGet(Consumer<TestData> mocker){
237 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
238 final MutableInt counter = new MutableInt();
239 String cacheName = RAND();
241 final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(cacheName, (Integer i) -> {
246 mocker.accept(new TestData(featureManager, cacheName, cacheConfigProvider));
248 int key = RandomUtils.nextInt();
249 integerIntegerCache.get(key);
250 integerIntegerCache.get(key);
252 Assert.assertEquals(counter.intValue(),2);
256 public void cache_loaderReturnsRandomValue_sameValueIsReturnedForSameKey() {
257 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
258 final String name = RAND();
259 final CacheProvider.Cache<Integer, String> integerRandomStringCache = provider.aaiClientCacheFor(name, (Integer i) -> RAND());
261 String firstGet = integerRandomStringCache.get(1);
262 String secondGet = integerRandomStringCache.get(1);
264 Assert.assertEquals(firstGet,secondGet);
267 @Test(dataProvider = "mockForCacheIsNotActive")
268 public void cache_toggleFlagOff_ResetCache(Consumer<TestData> mocker){
269 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
270 final String cacheName = RAND();
271 final CacheProvider.Cache<Integer, String> integerRandomStringCache = provider.aaiClientCacheFor(cacheName, (Integer i) -> RAND());
272 int key = RandomUtils.nextInt();
273 String result1 = integerRandomStringCache.get(key);
274 String result2 = integerRandomStringCache.get(key);
275 Assert.assertEquals(result1,result2);
277 mocker.accept(new TestData(featureManager, cacheName, cacheConfigProvider));
278 String result3 = integerRandomStringCache.get(key);
279 Assert.assertNotEquals(result1, result3);
283 public static Object[][] mockForCacheBuilderConfig() {
284 return new Object[][]{
286 {null, 10L, null, 24L} //null meaning use the default, which is 10L,24L
290 @Test(dataProvider = "mockForCacheBuilderConfig")
291 public void cacheBuilderConfiguredWithValues_andWithDefaults(
292 Long refreshAfterWriteSeconds,
293 long expectedRefreshAfterWriteSeconds,
294 Long expireAfterWriteHours,
295 long expectedExpireAfterWriteHours
296 ) throws IllegalAccessException {
297 final String cacheName = RAND();
298 when(cacheConfigProvider.getCacheConfig(cacheName)).thenReturn(new CacheConfig(true, expireAfterWriteHours, refreshAfterWriteSeconds));
299 final CacheProviderWithLoadingCache provider = createNewCacheProvider();
300 CacheBuilder<Object, Object> cacheBuilder = provider.createCacheBuilder(cacheName);
303 //Unfortunately CacheBuilder doesn't expose public getters
304 //Since it's only unit test I let myself do some fouls and use reflection
305 Long actualRefreshNanos = (Long)FieldUtils.readDeclaredField(cacheBuilder, "refreshNanos", true);
306 assertThat(actualRefreshNanos, equalTo(TimeUnit.NANOSECONDS.convert(expectedRefreshAfterWriteSeconds, TimeUnit.SECONDS)));
308 Long actualExpireAfterWriteNanos = (Long)FieldUtils.readDeclaredField(cacheBuilder, "expireAfterWriteNanos", true);
309 assertThat(actualExpireAfterWriteNanos, equalTo(TimeUnit.NANOSECONDS.convert(expectedExpireAfterWriteHours, TimeUnit.HOURS)));