1 package com.atlassian.vcache.internal.test;
2
3 import com.atlassian.vcache.ChangeRate;
4 import com.atlassian.vcache.DirectExternalCache;
5 import com.atlassian.vcache.ExternalCacheSettings;
6 import com.atlassian.vcache.ExternalCacheSettingsBuilder;
7 import com.atlassian.vcache.IdentifiedValue;
8 import com.atlassian.vcache.PutPolicy;
9 import com.atlassian.vcache.internal.LongMetric;
10 import com.atlassian.vcache.internal.MetricLabel;
11 import com.atlassian.vcache.internal.RequestMetrics;
12 import org.junit.Before;
13 import org.junit.Test;
14
15 import java.time.Duration;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.concurrent.CompletionStage;
19 import java.util.concurrent.ExecutionException;
20 import java.util.stream.Collectors;
21
22 import static com.atlassian.vcache.VCacheUtils.unsafeJoin;
23 import static com.atlassian.vcache.internal.test.CacheMetricsMatcher.hasMetric;
24 import static com.atlassian.vcache.internal.test.CacheMetricsMatcher.hasSize;
25 import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successful;
26 import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successfulWith;
27 import static org.hamcrest.MatcherAssert.assertThat;
28 import static org.hamcrest.Matchers.containsInAnyOrder;
29 import static org.hamcrest.Matchers.equalTo;
30 import static org.hamcrest.Matchers.greaterThan;
31 import static org.hamcrest.Matchers.is;
32 import static org.hamcrest.Matchers.isOneOf;
33 import static org.hamcrest.Matchers.not;
34 import static org.hamcrest.Matchers.notNullValue;
35 import static org.hamcrest.Matchers.nullValue;
36
37
38
39
40 @SuppressWarnings("OptionalGetWithoutIsPresent")
41 public abstract class AbstractDirectExternalCacheIT {
42 private static final String CACHE_NAME = "olympics";
43 private DirectExternalCache<String> cache;
44
45 protected abstract DirectExternalCache<String> createCache(String name, ExternalCacheSettings settings);
46 protected abstract RequestMetrics requestMetrics();
47
48 @Before
49 public void ensureCache() {
50 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
51 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
52 .entryCountHint(5)
53 .defaultTtl(Duration.ofMinutes(5))
54 .dataChangeRateHint(ChangeRate.HIGH_CHANGE)
55 .build();
56 cache = createCache(CACHE_NAME, settings);
57 final CompletionStage<Void> rm = cache.removeAll();
58 assertThat(rm, successful());
59 }
60
61 @Test
62 public void simple_get_set() throws ExecutionException, InterruptedException {
63 final CompletionStage<Optional<String>> eldestGet = cache.get("claira");
64
65 assertThat(eldestGet, successfulWith(is(Optional.empty())));
66
67 final CompletionStage<Boolean> eldestAdd = cache.put("claira", "dancing", PutPolicy.PUT_ALWAYS);
68
69 assertThat(eldestAdd, successfulWith(is(true)));
70
71 final CompletionStage<Optional<String>> eldestGet2 = cache.get("claira");
72
73 assertThat(eldestGet2, successfulWith(is(Optional.of("dancing"))));
74
75 final CompletionStage<Boolean> eldestAdd2 = cache.put("claira", "singing", PutPolicy.PUT_ALWAYS);
76
77 assertThat(eldestAdd2, successfulWith(is(true)));
78
79 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
80 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
81 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
82 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
83 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
84 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
85 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
86 assertThat(cacheMetrics, hasSize(is(5)));
87 }
88
89 @Test
90 public void simple_get_add() throws ExecutionException, InterruptedException {
91 final CompletionStage<Optional<String>> eldestGet = cache.get("claira");
92
93 assertThat(eldestGet, successfulWith(is(Optional.empty())));
94
95 final CompletionStage<Boolean> eldestAdd = cache.put("claira", "dancing", PutPolicy.ADD_ONLY);
96
97 assertThat(eldestAdd, successfulWith(is(true)));
98
99 final CompletionStage<Optional<String>> eldestGet2 = cache.get("claira");
100
101 assertThat(eldestGet2, successfulWith(is(Optional.of("dancing"))));
102
103 final CompletionStage<Boolean> eldestAdd2 = cache.put("claira", "singing", PutPolicy.ADD_ONLY);
104
105 assertThat(eldestAdd2, successfulWith(is(false)));
106
107 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
108 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
109 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
110 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
111 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
112 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
113 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
114 assertThat(cacheMetrics, hasSize(is(5)));
115 }
116
117 @Test
118 public void simple_get_with_supplier() throws ExecutionException, InterruptedException {
119 final CompletionStage<Optional<String>> eldestGet1 = cache.get("josephine");
120
121 assertThat(eldestGet1, successfulWith(is(Optional.empty())));
122
123 final CompletionStage<String> eldestGet2 = cache.get("josephine", () -> "football");
124
125 assertThat(eldestGet2, successfulWith(is("football")));
126
127 final CompletionStage<Optional<String>> eldestGet3 = cache.get("josephine");
128
129 assertThat(eldestGet3, successfulWith(is(Optional.of("football"))));
130
131 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
132 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
133 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(3L), greaterThan(0L)));
134 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
135 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_SUPPLIER_CALL, is(1L), greaterThan(0L)));
136 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
137 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(2L), is(2L)));
138 assertThat(cacheMetrics, hasSize(is(5)));
139 }
140
141 @Test
142 public void put_with_huge_key() throws ExecutionException, InterruptedException {
143 final String key = "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
144 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
145 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
146 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
147 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
148 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
149 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
150 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
151 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
152 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
153 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
154 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
155 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
156 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
157 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
158 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
159 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
160 + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss";
161
162 final CompletionStage<Boolean> hugeAdd = cache.put(key, "dancing", PutPolicy.ADD_ONLY);
163
164 assertThat(hugeAdd, successfulWith(is(true)));
165
166 final CompletionStage<Optional<String>> hugeGet = cache.get(key);
167
168 assertThat(hugeGet, successfulWith(is(Optional.of("dancing"))));
169
170 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
171 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
172 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(1L), greaterThan(0L)));
173 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
174 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
175 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
176 assertThat(cacheMetrics, hasSize(is(4)));
177 }
178
179 @Test
180 public void simple_getBulkIdentified() throws ExecutionException, InterruptedException {
181 final CompletionStage<Boolean> put1 = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
182
183 assertThat(put1, successfulWith(is(true)));
184
185 final CompletionStage<Optional<IdentifiedValue<String>>> get1 = cache.getIdentified("josie");
186
187 assertThat(get1, successful());
188 final IdentifiedValue<String> iv1 = unsafeJoin(get1).get();
189 assertThat(iv1.identifier(), notNullValue());
190 assertThat(iv1.value(), is("football"));
191
192 final CompletionStage<Map<String, Optional<IdentifiedValue<String>>>> get2 =
193 cache.getBulkIdentified("claira", "josie", "jasmin");
194
195 assertThat(get2, successful());
196 final Map<String, Optional<IdentifiedValue<String>>> ivMap1 = unsafeJoin(get2);
197 assertThat(ivMap1.keySet(), containsInAnyOrder("jasmin", "claira", "josie"));
198 assertThat(ivMap1.get("claira"), is(Optional.empty()));
199 assertThat(ivMap1.get("jasmin"), is(Optional.empty()));
200 final IdentifiedValue<String> iv2 = ivMap1.get("josie").get();
201 assertThat(iv2.identifier(), notNullValue());
202 assertThat(iv2.identifier(), equalTo(iv1.identifier()));
203 assertThat(iv2.value(), is("football"));
204
205 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
206 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
207 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(2L), greaterThan(0L)));
208 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
209 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
210 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(2L), is(2L)));
211 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(2L)));
212 assertThat(cacheMetrics, hasSize(is(5)));
213 }
214
215 @Test
216 public void simple_getIdentified_removeIf() throws ExecutionException, InterruptedException {
217 final CompletionStage<Optional<IdentifiedValue<String>>> get1 = cache.getIdentified("josie");
218
219 assertThat(get1, successfulWith(is(Optional.empty())));
220
221 final CompletionStage<Boolean> put1 = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
222
223 assertThat(put1, successfulWith(is(true)));
224
225 final CompletionStage<Optional<IdentifiedValue<String>>> get2 = cache.getIdentified("josie");
226
227 assertThat(get2, successful());
228 final IdentifiedValue<String> iv2 = unsafeJoin(get2).get();
229 assertThat(iv2.identifier(), notNullValue());
230 assertThat(iv2.value(), is("football"));
231
232 final CompletionStage<Boolean> rm1 = cache.removeIf("josie", iv2.identifier());
233
234 assertThat(rm1, successfulWith(is(true)));
235
236 final CompletionStage<Boolean> put2 = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
237
238 assertThat(put2, successfulWith(is(true)));
239
240 final CompletionStage<Optional<IdentifiedValue<String>>> get3 = cache.getIdentified("josie");
241
242 assertThat(get3, successful());
243 final IdentifiedValue<String> iv3 = unsafeJoin(get3).get();
244 assertThat(iv3.identifier(), notNullValue());
245 assertThat(iv3.value(), is("football"));
246
247 final CompletionStage<Boolean> rm3 = cache.removeIf("josie", iv3.identifier());
248
249 assertThat(rm3, successfulWith(is(true)));
250
251 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
252 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
253 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(3L), greaterThan(0L)));
254 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REMOVE_CALL, is(2L), greaterThan(0L)));
255 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
256 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
257 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(2L), is(2L)));
258 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
259 assertThat(cacheMetrics, hasSize(is(6)));
260 }
261
262 @Test
263 public void simple_getIdentifiedSupplier_removeIf() throws ExecutionException, InterruptedException {
264 final CompletionStage<IdentifiedValue<String>> get1 = cache.getIdentified("josie", () -> "football");
265
266 assertThat(get1, successful());
267 final IdentifiedValue<String> iv1 = unsafeJoin(get1);
268 assertThat(iv1.identifier(), notNullValue());
269 assertThat(iv1.value(), is("football"));
270
271 final CompletionStage<Boolean> rm1 = cache.removeIf("josie", iv1.identifier());
272
273 assertThat(rm1, successfulWith(is(true)));
274
275 final CompletionStage<Boolean> put1 = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
276
277 assertThat(put1, successfulWith(is(true)));
278
279 final CompletionStage<IdentifiedValue<String>> get2 = cache.getIdentified("josie", () -> "swimming");
280
281 assertThat(get2, successful());
282 final IdentifiedValue<String> iv2 = unsafeJoin(get2);
283 assertThat(iv2.identifier(), notNullValue());
284 assertThat(iv2.value(), is("football"));
285
286 final CompletionStage<Boolean> rm2 = cache.removeIf("josie", iv2.identifier());
287
288 assertThat(rm2, successfulWith(is(true)));
289
290 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
291 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
292 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(2L), greaterThan(0L)));
293 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REMOVE_CALL, is(2L), greaterThan(0L)));
294 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
295 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
296 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_SUPPLIER_CALL, is(1L), greaterThan(0L)));
297 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
298 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
299 assertThat(cacheMetrics, hasSize(is(7)));
300 }
301
302
303
304
305 @Test
306 public void exact_getIdentified_removeIf() throws ExecutionException, InterruptedException {
307 final CompletionStage<Boolean> putFirst = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
308
309 assertThat(putFirst, successfulWith(is(true)));
310
311 final CompletionStage<Optional<IdentifiedValue<String>>> getFirst = cache.getIdentified("josie");
312
313 assertThat(getFirst, successful());
314 final IdentifiedValue<String> ivFirst = unsafeJoin(getFirst).get();
315 assertThat(ivFirst.identifier(), notNullValue());
316 assertThat(ivFirst.value(), is("football"));
317
318 final CompletionStage<Boolean> putSecond = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
319
320 assertThat(putSecond, successfulWith(is(true)));
321
322 final CompletionStage<Boolean> rm1 = cache.removeIf("josie", ivFirst.identifier());
323
324 assertThat(rm1, successfulWith(is(false)));
325
326 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
327 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
328 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(1L), greaterThan(0L)));
329 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REMOVE_CALL, is(1L), greaterThan(0L)));
330 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
331 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
332 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
333 assertThat(cacheMetrics, hasSize(is(5)));
334 }
335
336 @Test
337 public void simple_getIdentified_replaceIf() throws ExecutionException, InterruptedException {
338 final CompletionStage<Boolean> put1 = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
339
340 assertThat(put1, successfulWith(is(true)));
341
342 final CompletionStage<Optional<IdentifiedValue<String>>> get1 = cache.getIdentified("josie");
343
344 assertThat(get1, successful());
345 final IdentifiedValue<String> iv1 = unsafeJoin(get1).get();
346 assertThat(iv1.identifier(), notNullValue());
347 assertThat(iv1.value(), is("football"));
348
349 final CompletionStage<Boolean> rm1 = cache.replaceIf("josie", iv1.identifier(), "soccer");
350
351 assertThat(rm1, successfulWith(is(true)));
352
353 final CompletionStage<Boolean> put2 = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
354
355 assertThat(put2, successfulWith(is(true)));
356
357 final CompletionStage<Optional<IdentifiedValue<String>>> get3 = cache.getIdentified("josie");
358
359 assertThat(get3, successful());
360 final IdentifiedValue<String> iv3 = unsafeJoin(get3).get();
361 assertThat(iv3.identifier(), notNullValue());
362 assertThat(iv3.value(), is("football"));
363
364 final CompletionStage<Boolean> rm3 = cache.removeIf("josie", iv3.identifier());
365
366 assertThat(rm3, successfulWith(is(true)));
367
368 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
369 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
370 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(2L), greaterThan(0L)));
371 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REPLACE_CALL, is(1L), greaterThan(0L)));
372 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REMOVE_CALL, is(1L), greaterThan(0L)));
373 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
374 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
375 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(2L), is(2L)));
376 assertThat(cacheMetrics, hasSize(is(6)));
377 }
378
379
380
381
382 @Test
383 public void exact_getIdentified_replaceIf() throws ExecutionException, InterruptedException {
384 final CompletionStage<Boolean> putFirst = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
385
386 assertThat(putFirst, successfulWith(is(true)));
387
388 final CompletionStage<Optional<IdentifiedValue<String>>> getFirst = cache.getIdentified("josie");
389
390 assertThat(getFirst, successful());
391 final IdentifiedValue<String> ivFirst = unsafeJoin(getFirst).get();
392 assertThat(ivFirst.identifier(), notNullValue());
393 assertThat(ivFirst.value(), is("football"));
394
395 final CompletionStage<Boolean> putSecond = cache.put("josie", "football", PutPolicy.PUT_ALWAYS);
396
397 assertThat(putSecond, successfulWith(is(true)));
398
399 final CompletionStage<Boolean> rm1 = cache.replaceIf("josie", ivFirst.identifier(), "afl");
400
401 assertThat(rm1, successfulWith(is(false)));
402
403 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
404 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
405 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(1L), greaterThan(0L)));
406 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REPLACE_CALL, is(1L), greaterThan(0L)));
407 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
408 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
409 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
410 assertThat(cacheMetrics, hasSize(is(5)));
411 }
412
413 @Test
414 public void simple_put_remove() throws ExecutionException, InterruptedException {
415 final CompletionStage<Void> rm1 = cache.remove("claira");
416
417 assertThat(rm1, successful());
418 assertThat(unsafeJoin(rm1), nullValue());
419
420 final CompletionStage<Boolean> put1 = cache.put("claira", "dancing", PutPolicy.PUT_ALWAYS);
421
422 assertThat(put1, successfulWith(is(true)));
423
424 final CompletionStage<Void> rm2 = cache.remove("claira");
425
426 assertThat(rm2, successful());
427
428 final CompletionStage<Boolean> put2 = cache.put("claira", "dancing", PutPolicy.PUT_ALWAYS);
429
430 assertThat(put2, successfulWith(is(true)));
431
432 final CompletionStage<Optional<String>> get1 = cache.get("claira");
433
434 assertThat(get1, successfulWith(is(Optional.of("dancing"))));
435
436 final CompletionStage<Void> rm3 = cache.remove("josie", "claira", "jasmin");
437
438 assertThat(rm3, successful());
439
440 final CompletionStage<Optional<String>> get2 = cache.get("claira");
441
442 assertThat(get2, successfulWith(is(Optional.empty())));
443
444 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
445 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
446 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
447 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(2L), greaterThan(0L)));
448 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_CALL, is(3L), greaterThan(0L)));
449 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
450 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
451 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
452 assertThat(cacheMetrics, hasSize(is(6)));
453 }
454
455 @Test
456 public void simple_removeAll() throws ExecutionException, InterruptedException {
457 final CompletionStage<Boolean> put1 = cache.put("claira", "", PutPolicy.PUT_ALWAYS);
458
459 assertThat(put1, successfulWith(is(true)));
460
461 final CompletionStage<Optional<String>> get1 = cache.get("claira");
462
463 assertThat(get1, successfulWith(is(Optional.of(""))));
464
465 final CompletionStage<Void> rm1 = cache.removeAll();
466
467 assertThat(rm1, successful());
468
469 final CompletionStage<Optional<String>> get2 = cache.get("claira");
470
471 assertThat(get2, successfulWith(is(Optional.empty())));
472
473 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
474 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
475 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
476 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
477 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(2L), greaterThan(0L)));
478 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
479 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
480 assertThat(cacheMetrics, hasSize(is(5)));
481 }
482
483 @SuppressWarnings("unchecked")
484 @Test
485 public void simple_getBulk() throws ExecutionException, InterruptedException {
486 final CompletionStage<Map<String, Optional<String>>> get1 = cache.getBulk("claira", "jasmin", "josie", "josie");
487
488 assertThat(get1, successful());
489 assertThat(unsafeJoin(get1).keySet(), containsInAnyOrder("claira", "jasmin", "josie"));
490 assertThat(unsafeJoin(get1).values(), containsInAnyOrder(Optional.empty(), Optional.empty(), Optional.empty()));
491
492 final CompletionStage<Boolean> put1 = cache.put("claira", "youtube", PutPolicy.PUT_ALWAYS);
493
494 assertThat(put1, successfulWith(is(true)));
495
496 final CompletionStage<Map<String, Optional<String>>> get2 = cache.getBulk("jasmin", "claira", "josie", "claira");
497
498 assertThat(get2, successful());
499 assertThat(unsafeJoin(get2).keySet(), containsInAnyOrder("claira", "jasmin", "josie"));
500 assertThat(unsafeJoin(get2).values(), containsInAnyOrder(Optional.of("youtube"), Optional.empty(), Optional.empty()));
501
502 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
503 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
504 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
505 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
506 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
507 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(1L)));
508 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(2L), is(5L)));
509 assertThat(cacheMetrics, hasSize(is(5)));
510 }
511
512 @Test
513 public void simple_getBulkFactory() throws ExecutionException, InterruptedException {
514 final CompletionStage<Map<String, String>> get1 =
515 cache.getBulk(
516 strings -> strings.stream().collect(Collectors.toMap(k -> k, k -> k + "-1")),
517 "claira", "josie", "josie");
518
519 assertThat(get1, successful());
520 assertThat(unsafeJoin(get1).keySet(), containsInAnyOrder("claira", "josie"));
521 assertThat(unsafeJoin(get1).values(), containsInAnyOrder("claira-1", "josie-1"));
522
523 final CompletionStage<Map<String, String>> get2 =
524 cache.getBulk(
525 strings -> strings.stream().collect(Collectors.toMap(k -> k, k -> k + "-2")),
526 "claira", "josie", "jasmin");
527
528 assertThat(get2, successful());
529 assertThat(unsafeJoin(get2).keySet(), containsInAnyOrder("claira", "josie", "jasmin"));
530 assertThat(unsafeJoin(get2).values(), containsInAnyOrder("claira-1", "josie-1", "jasmin-2"));
531
532 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
533 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
534 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
535 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_FACTORY_CALL, is(2L), greaterThan(0L)));
536 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
537 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FACTORY_KEYS, is(2L), is(3L)));
538 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_HITS, is(1L), is(2L)));
539 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(2L), is(3L)));
540 assertThat(cacheMetrics, hasSize(is(6)));
541 }
542
543 @SuppressWarnings("ConstantConditions")
544 @Test
545 public void check_null_detection() {
546 assertThat(cache.get("kenny", () -> null), not(successful()));
547 assertThat(cache.getIdentified("norway", () -> null), not(successful()));
548 assertThat(cache.put("key", null, PutPolicy.ADD_ONLY), not(successful()));
549 assertThat(cache.getBulk(
550 strings -> strings.stream().collect(Collectors.toMap(k -> k, k -> null)),
551 "extra"),
552 not(successful()));
553
554 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
555 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
556 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_FACTORY_CALL, is(1L), greaterThan(0L)));
557 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_GET_CALL, is(2L), greaterThan(0L)));
558 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(1L), greaterThan(0L)));
559 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
560 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
561
562 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_SUPPLIER_CALL, isOneOf(1L, 2L), greaterThan(0L)));
563 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FACTORY_KEYS, is(1L), is(1L)));
564 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FAILED_GET, is(2L), is(2L)));
565 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FAILED_IDENTIFIED_GET, is(1L), is(1L)));
566 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FAILED_PUT, is(1L), is(1L)));
567 assertThat(cacheMetrics, hasSize(is(10)));
568 }
569
570 @SuppressWarnings("ConstantConditions")
571 @Test
572 public void check_null_detection_with_cas() {
573 final CompletionStage<IdentifiedValue<String>> geti = cache.getIdentified("temp", () -> "value");
574 assertThat(geti, successful());
575 assertThat(cache.replaceIf("temp", unsafeJoin(geti).identifier(), null), not(successful()));
576
577 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
578 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
579 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_GET_CALL, is(1L), greaterThan(0L)));
580 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_IDENTIFIED_REPLACE_CALL, is(1L), greaterThan(0L)));
581 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_SUPPLIER_CALL, is(1L), greaterThan(0L)));
582 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
583 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FAILED_IDENTIFIED_REPLACE, is(1L), is(1L)));
584 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_MISSES, is(1L), is(1L)));
585 assertThat(cacheMetrics, hasSize(is(6)));
586 }
587
588 @SuppressWarnings("ConstantConditions")
589 @Test
590 public void check_null_key() {
591 final CompletionStage<Boolean> put1 = cache.put(null, "value", PutPolicy.PUT_ALWAYS);
592 assertThat(put1, not(successful()));
593
594 final Map<MetricLabel, ? extends LongMetric> cacheMetrics =
595 requestMetrics().allExternalCacheLongMetrics().get(CACHE_NAME);
596 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_PUT_CALL, is(1L), greaterThan(0L)));
597 assertThat(cacheMetrics, hasMetric(MetricLabel.TIMED_REMOVE_ALL_CALL, is(1L), greaterThan(0L)));
598 assertThat(cacheMetrics, hasMetric(MetricLabel.NUMBER_OF_FAILED_PUT, is(1L), is(1L)));
599 assertThat(cacheMetrics, hasSize(is(3)));
600 }
601
602 @Test
603 public void potential_deadlock() {
604 final CompletionStage<String> get = cache.get("lockType", () -> {
605
606 final CompletionStage<Void> rm = cache.remove("lockType");
607 assertThat(rm, successful());
608
609 return "lockwood";
610 });
611 assertThat(get, successfulWith(is("lockwood")));
612 }
613 }