Merge from ECOMP's repository
[vid.git] / vid-app-common / src / test / java / org / onap / vid / aai / util / CacheProviderWithLoadingCacheTest.java
1 package org.onap.vid.aai.util;
2
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;
16
17 import java.util.concurrent.TimeUnit;
18 import java.util.function.Consumer;
19 import java.util.function.Function;
20
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;
30
31 public class CacheProviderWithLoadingCacheTest {
32     private final FeatureManager featureManager = mock(FeatureManager.class);
33     private final CacheConfigProvider cacheConfigProvider = mock(CacheConfigProvider.class);
34
35     @BeforeMethod
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());
40     }
41
42     private CacheProviderWithLoadingCache createNewCacheProvider() {
43         return new CacheProviderWithLoadingCache(featureManager, cacheConfigProvider);
44     }
45
46     private String RAND() {
47         return randomAlphanumeric(5);
48     }
49
50     @Test
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);
54
55         assertThat(integerIntegerCache, notNullValue());
56         assertThat(integerIntegerCache.get(5), is(9));
57     }
58
59     @Test
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);
65
66         assertThat(integerIntegerCache2, sameInstance(integerIntegerCache));
67         assertThat(integerIntegerCache.get(5), is(9)); // as the first one
68     }
69
70     @Test
71     public void cacheProvider_requestingCacheSameNameTwiceOutOfSeveral_ReturnsFirstCacheInstance() {
72         final CacheProviderWithLoadingCache provider = createNewCacheProvider();
73
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);
81
82         assertThat(integerIntegerCache2, sameInstance(integerIntegerCache));
83     }
84
85     @Test
86     public void cacheProvider_sameProviderSupportDifferentKV() {
87         final CacheProviderWithLoadingCache provider = createNewCacheProvider();
88
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"));
99     }
100
101     @Test
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);
109
110         Assert.assertNotEquals(result1,result2);
111         Assert.assertEquals(result1,result3);
112     }
113
114     @Test
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) -> {
119             counter.increment();
120             return i;
121         });
122
123         int key = RandomUtils.nextInt();
124         Integer result1 = integerIntegerCache.get(key);
125         Integer result2 = integerIntegerCache.get(key);
126         Integer result3 = integerIntegerCache.get(key);
127
128         Assert.assertEquals(result1.intValue(),key);
129         Assert.assertEquals(result2.intValue(),key);
130         Assert.assertEquals(result3.intValue(),key);
131         Assert.assertEquals(counter.intValue(),1);
132     }
133
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");});
138
139         stringIntegerCache.get("Whatever");
140     }
141
142     @Test
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;
147             @Override
148             public Integer apply(Integer i) {
149                 if (firstTime) {
150                     firstTime = false;
151                     throw new GenericUncheckedException("boom");
152                 }
153                 else {
154                     return i;
155                 }
156             }
157         });
158       
159         try {
160             integerIntegerCache.get(1);
161         }
162         catch (GenericUncheckedException e) {}
163
164         assertEquals(new Integer(1), integerIntegerCache.get(1));
165     }
166
167     @Test
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; });
172
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);
181     }
182
183     @Test
184     public void cache_getIsCalledMoreThanOnce_loaderIsCalledAgainAfterReset(){
185         final CacheProviderWithLoadingCache provider = createNewCacheProvider();
186         final MutableInt counter = new MutableInt();
187         String cacheName = RAND();
188
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);
194
195         provider.resetCache(cacheName);
196         provider.aaiClientCacheFor(cacheName, (Integer i) -> { counter.increment(); return i; }).get(key1);
197         Assert.assertEquals(counter.intValue(), 2);
198
199     }
200
201
202     public static class TestData {
203         public FeatureManager featureManager;
204         public String cacheName;
205         public CacheConfigProvider cacheConfigProvider;
206
207         public TestData(FeatureManager featureManager, String cacheName, CacheConfigProvider cacheConfigProvider) {
208             this.featureManager = featureManager;
209             this.cacheName = cacheName;
210             this.cacheConfigProvider = cacheConfigProvider;
211         }
212     }
213
214
215     @DataProvider
216     public static Object[][] mockForCacheIsNotActive() {
217
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));
221         };
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));
225         };
226
227
228         return new Object[][]{
229                 {mockFeatureOff},
230                 {mockFeatureOnCacheOff}
231         };
232     }
233
234
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();
240
241         final CacheProvider.Cache<Integer, Integer> integerIntegerCache = provider.aaiClientCacheFor(cacheName, (Integer i) -> {
242             counter.increment();
243             return i;
244         });
245
246         mocker.accept(new TestData(featureManager, cacheName, cacheConfigProvider));
247         counter.setValue(0);
248         int key = RandomUtils.nextInt();
249         integerIntegerCache.get(key);
250         integerIntegerCache.get(key);
251
252         Assert.assertEquals(counter.intValue(),2);
253     }
254
255     @Test
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());
260
261         String firstGet = integerRandomStringCache.get(1);
262         String secondGet = integerRandomStringCache.get(1);
263
264         Assert.assertEquals(firstGet,secondGet);
265     }
266
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);
276
277         mocker.accept(new TestData(featureManager, cacheName, cacheConfigProvider));
278         String result3 = integerRandomStringCache.get(key);
279         Assert.assertNotEquals(result1, result3);
280     }
281
282     @DataProvider
283     public static Object[][] mockForCacheBuilderConfig() {
284         return new Object[][]{
285                 {2L, 2L, 3L, 3L},
286                 {null, 10L, null, 24L} //null meaning use the default, which is 10L,24L
287         };
288     }
289
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);
301
302
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)));
307
308         Long actualExpireAfterWriteNanos = (Long)FieldUtils.readDeclaredField(cacheBuilder, "expireAfterWriteNanos", true);
309         assertThat(actualExpireAfterWriteNanos, equalTo(TimeUnit.NANOSECONDS.convert(expectedExpireAfterWriteHours, TimeUnit.HOURS)));
310
311     }
312 }
313