View Javadoc

1   package com.atlassian.vcache.internal.test;
2   
3   import com.atlassian.marshalling.api.MarshallingPair;
4   import com.atlassian.marshalling.jdk.StringMarshalling;
5   import com.atlassian.vcache.ChangeRate;
6   import com.atlassian.vcache.DirectExternalCache;
7   import com.atlassian.vcache.ExternalCacheException;
8   import com.atlassian.vcache.ExternalCacheSettings;
9   import com.atlassian.vcache.ExternalCacheSettingsBuilder;
10  import com.atlassian.vcache.JvmCache;
11  import com.atlassian.vcache.JvmCacheSettings;
12  import com.atlassian.vcache.JvmCacheSettingsBuilder;
13  import com.atlassian.vcache.RequestCache;
14  import com.atlassian.vcache.StableReadExternalCache;
15  import com.atlassian.vcache.TransactionalExternalCache;
16  import com.atlassian.vcache.VCacheFactory;
17  import com.atlassian.vcache.VCacheUtils;
18  import com.atlassian.vcache.internal.BegunTransactionalActivityHandler;
19  import com.atlassian.vcache.internal.ExternalCacheDetails;
20  import com.atlassian.vcache.internal.JvmCacheDetails;
21  import com.atlassian.vcache.internal.LongMetric;
22  import com.atlassian.vcache.internal.MetricLabel;
23  import com.atlassian.vcache.internal.RequestCacheDetails;
24  import com.atlassian.vcache.internal.RequestContext;
25  import com.atlassian.vcache.internal.RequestMetrics;
26  import com.atlassian.vcache.internal.VCacheLifecycleManager;
27  import com.atlassian.vcache.internal.VCacheManagement;
28  import com.atlassian.vcache.marshallers.MarshallerFactory;
29  import org.junit.Rule;
30  import org.junit.Test;
31  import org.junit.rules.ExpectedException;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  import java.time.Duration;
36  import java.util.Map;
37  import java.util.Optional;
38  import java.util.concurrent.CompletionStage;
39  
40  import static com.atlassian.vcache.PutPolicy.PUT_ALWAYS;
41  import static com.atlassian.vcache.VCacheUtils.unsafeJoin;
42  import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successful;
43  import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successfulWith;
44  import static org.hamcrest.Matchers.containsInAnyOrder;
45  import static org.hamcrest.Matchers.greaterThan;
46  import static org.hamcrest.Matchers.is;
47  import static org.hamcrest.Matchers.notNullValue;
48  import static org.junit.Assert.assertThat;
49  
50  /**
51   * Base test class for the VCacheService.
52   */
53  @SuppressWarnings("OptionalGetWithoutIsPresent")
54  public abstract class AbstractVCacheServiceIT {
55      protected static final int MAX_ENTRIES = 100;
56      protected static final Duration MAX_TTL = Duration.ofSeconds(60);
57  
58      private static final Logger log = LoggerFactory.getLogger(AbstractVCacheServiceIT.class);
59  
60      @Rule
61      public ExpectedException thrown = ExpectedException.none();
62  
63      @Rule
64      public LoggingTestWatcher watcher = new LoggingTestWatcher(log);
65  
66      @SuppressWarnings("WeakerAccess")
67      protected int invocationsOfBegunTxns;
68      protected final BegunTransactionalActivityHandler begunTxnActivityHandler = c -> invocationsOfBegunTxns++;
69  
70      protected abstract VCacheFactory vCacheFactory();
71  
72      protected abstract VCacheManagement vCacheManagement();
73  
74      protected abstract VCacheLifecycleManager vCacheLifecycleManager();
75  
76      protected abstract RequestContext currentRequestContext();
77  
78      protected abstract void forceNewRequestContext();
79  
80      @Test
81      public void jvmCache_normal() {
82          final JvmCacheSettings settings = new JvmCacheSettingsBuilder()
83                  .defaultTtl(MAX_TTL.plusSeconds(1))
84                  .maxEntries(MAX_ENTRIES + 1)
85                  .build();
86  
87          final JvmCache<String, Long> cache = vCacheFactory().getJvmCache("my-jvm-cache", settings);
88  
89          assertThat(cache, notNullValue());
90          assertThat(cache.getName(), is("my-jvm-cache"));
91  
92          cache.put("key", 666L);
93  
94          final RequestMetrics metrics = vCacheLifecycleManager().metrics(currentRequestContext());
95  
96          assertThat(metrics, notNullValue());
97          assertThat(metrics.allJvmCacheLongMetrics(), notNullValue());
98  
99          final Map<MetricLabel, ? extends LongMetric> myCacheMetrics =
100                 metrics.allJvmCacheLongMetrics().get("my-jvm-cache");
101 
102         assertThat(myCacheMetrics, notNullValue());
103         final LongMetric timedPuts = myCacheMetrics.get(MetricLabel.TIMED_PUT_CALL);
104         assertThat(timedPuts, notNullValue());
105         assertThat(timedPuts.getSampleCount(), is(1L));
106         assertThat(timedPuts.getSamplesTotal(), greaterThan(0L));
107         assertThat(vCacheManagement().allExternalCacheDetails().size(), is(0));
108         assertThat(vCacheManagement().allRequestCacheDetails().size(), is(0));
109 
110         final Map<String, JvmCacheDetails> allCacheDetails = vCacheManagement().allJvmCacheDetails();
111 
112         assertThat(allCacheDetails, notNullValue());
113         assertThat(allCacheDetails.keySet(), containsInAnyOrder("my-jvm-cache"));
114 
115         final JvmCacheDetails cacheDetails = allCacheDetails.get("my-jvm-cache");
116 
117         assertThat(cacheDetails.getName(), is("my-jvm-cache"));
118         assertThat(cacheDetails.getSettings().getDefaultTtl(), is(Optional.of(MAX_TTL)));
119         assertThat(cacheDetails.getSettings().getMaxEntries(), is(Optional.of(MAX_ENTRIES)));
120 
121         assertThat(invocationsOfBegunTxns, is(0));
122     }
123 
124     @Test
125     public void requestCache_normal() {
126         final RequestCache<String, String> cache = vCacheFactory().getRequestCache("my-request-cache");
127 
128         assertThat(cache, notNullValue());
129         assertThat(cache.getName(), is("my-request-cache"));
130 
131         cache.removeAll();
132         cache.put("one", "eine");
133 
134         final Optional<String> get1 = cache.get("one");
135 
136         assertThat(get1, is(Optional.of("eine")));
137         assertThat(vCacheManagement().allJvmCacheDetails().size(), is(0));
138         assertThat(vCacheManagement().allExternalCacheDetails().size(), is(0));
139 
140         final Map<String, RequestCacheDetails> allCacheDetails = vCacheManagement().allRequestCacheDetails();
141 
142         assertThat(allCacheDetails, notNullValue());
143         assertThat(allCacheDetails.keySet(), containsInAnyOrder("my-request-cache"));
144 
145         final RequestCacheDetails cacheDetails = allCacheDetails.get("my-request-cache");
146 
147         assertThat(cacheDetails.getName(), is("my-request-cache"));
148         assertThat(invocationsOfBegunTxns, is(0));
149     }
150 
151     @Test
152     public void directExternalCache_normal_marshalling() {
153         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
154                 .defaultTtl(Duration.ofSeconds(60))
155                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
156                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
157                 .entryCountHint(100)
158                 .build();
159 
160         final DirectExternalCache<String> cache = vCacheFactory().getDirectExternalCache(
161                 "my-direct-cache", StringMarshalling.pair(), settings);
162 
163         assertThat(cache, notNullValue());
164         assertThat(cache.getName(), is("my-direct-cache"));
165 
166         final CompletionStage<Void> rmall = cache.removeAll();
167 
168         assertThat(rmall, successful());
169 
170         final CompletionStage<Boolean> put1 = cache.put("one", "eine", PUT_ALWAYS);
171 
172         assertThat(put1, successfulWith(is(true)));
173 
174         final CompletionStage<Optional<String>> get1 = cache.get("one");
175 
176         assertThat(get1, successfulWith(is(Optional.of("eine"))));
177         assertThat(vCacheManagement().allJvmCacheDetails().size(), is(0));
178         assertThat(vCacheManagement().allRequestCacheDetails().size(), is(0));
179 
180         final Map<String, ExternalCacheDetails> allCacheDetails = vCacheManagement().allExternalCacheDetails();
181 
182         assertThat(allCacheDetails, notNullValue());
183         assertThat(allCacheDetails.keySet(), containsInAnyOrder("my-direct-cache"));
184 
185         final ExternalCacheDetails cacheDetails = allCacheDetails.get("my-direct-cache");
186 
187         assertThat(cacheDetails.getName(), is("my-direct-cache"));
188         assertThat(cacheDetails.getSettings().getDefaultTtl(), is(Optional.of(MAX_TTL)));
189         assertThat(cacheDetails.getSettings().getEntryCountHint(), is(Optional.of(MAX_ENTRIES)));
190         assertThat(invocationsOfBegunTxns, is(0));
191     }
192 
193     @Test
194     public void directExternalCache_normal_marshaller() {
195         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
196                 .defaultTtl(Duration.ofSeconds(60))
197                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
198                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
199                 .entryCountHint(100)
200                 .build();
201 
202         @SuppressWarnings("deprecation")
203         final DirectExternalCache<String> cache = vCacheFactory().getDirectExternalCache(
204                 "my-direct-cache", MarshallerFactory.stringMarshaller(), settings);
205 
206         assertThat(cache, notNullValue());
207         assertThat(cache.getName(), is("my-direct-cache"));
208 
209         final CompletionStage<Void> rmall = cache.removeAll();
210 
211         assertThat(rmall, successful());
212 
213         final CompletionStage<Boolean> put1 = cache.put("one1", "eine", PUT_ALWAYS);
214 
215         assertThat(put1, successfulWith(is(true)));
216 
217         final CompletionStage<Optional<String>> get1 = cache.get("one1");
218 
219         assertThat(get1, successfulWith(is(Optional.of("eine"))));
220         assertThat(vCacheManagement().allJvmCacheDetails().size(), is(0));
221         assertThat(vCacheManagement().allRequestCacheDetails().size(), is(0));
222     }
223 
224     @Test
225     public void stableReadExternalCache_normal_marshalling() {
226         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
227                 .defaultTtl(Duration.ofSeconds(60))
228                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
229                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
230                 .entryCountHint(100)
231                 .build();
232 
233         final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
234                 "my-stable-read-cache", StringMarshalling.pair(), settings);
235 
236         assertThat(cache, notNullValue());
237         assertThat(cache.getName(), is("my-stable-read-cache"));
238 
239         final CompletionStage<Void> rmall = cache.removeAll();
240 
241         assertThat(rmall, successful());
242 
243         final CompletionStage<Boolean> put1 = cache.put("three", "drei", PUT_ALWAYS);
244 
245         assertThat(put1, successfulWith(is(true)));
246 
247         final CompletionStage<Optional<String>> get1 = cache.get("three");
248 
249         assertThat(get1, successfulWith(is(Optional.of("drei"))));
250         assertThat(invocationsOfBegunTxns, is(0));
251     }
252 
253     @Test
254     public void stableReadExternalCache_normal_marshaller() {
255         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
256                 .defaultTtl(Duration.ofSeconds(60))
257                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
258                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
259                 .entryCountHint(100)
260                 .build();
261 
262         @SuppressWarnings("deprecation")
263         final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
264                 "my-stable-read-cache", MarshallerFactory.stringMarshaller(), settings);
265 
266         assertThat(cache, notNullValue());
267         assertThat(cache.getName(), is("my-stable-read-cache"));
268 
269         final CompletionStage<Void> rmall = cache.removeAll();
270 
271         assertThat(rmall, successful());
272 
273         final CompletionStage<Boolean> put1 = cache.put("three", "drei", PUT_ALWAYS);
274 
275         assertThat(put1, successfulWith(is(true)));
276 
277         final CompletionStage<Optional<String>> get1 = cache.get("three");
278 
279         assertThat(get1, successfulWith(is(Optional.of("drei"))));
280         assertThat(invocationsOfBegunTxns, is(0));
281     }
282 
283     @Test
284     public void transactionalExternalCache_normal_marshalling() {
285         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
286                 .defaultTtl(Duration.ofSeconds(60))
287                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
288                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
289                 .entryCountHint(100)
290                 .build();
291 
292         final TransactionalExternalCache<String> cache = vCacheFactory().getTransactionalExternalCache(
293                 "my-txn-cache", StringMarshalling.pair(), settings);
294 
295         assertThat(cache, notNullValue());
296         assertThat(cache.getName(), is("my-txn-cache"));
297         assertThat(invocationsOfBegunTxns, is(0));
298 
299         cache.removeAll();
300         assertThat(invocationsOfBegunTxns, is(1));
301 
302         cache.put("three", "drei", PUT_ALWAYS);
303 
304         final CompletionStage<Optional<String>> get1 = cache.get("three");
305 
306         assertThat(get1, successfulWith(is(Optional.of("drei"))));
307 
308         vCacheLifecycleManager().transactionSync(currentRequestContext());
309         assertThat(invocationsOfBegunTxns, is(1));
310 
311         forceNewRequestContext();
312         final CompletionStage<Optional<String>> get2 = cache.get("three");
313         assertThat(invocationsOfBegunTxns, is(2));
314         unsafeJoin(get2.toCompletableFuture()).get();
315         assertThat(get2, successfulWith(is(Optional.of("drei"))));
316         assertThat(invocationsOfBegunTxns, is(2));
317     }
318 
319     @Test
320     public void transactionalExternalCache_normal_marshaller() {
321         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
322                 .defaultTtl(Duration.ofSeconds(60))
323                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
324                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
325                 .entryCountHint(100)
326                 .build();
327 
328         @SuppressWarnings("deprecation")
329         final TransactionalExternalCache<String> cache = vCacheFactory().getTransactionalExternalCache(
330                 "my-txn-cache", MarshallerFactory.stringMarshaller(), settings);
331 
332         assertThat(cache, notNullValue());
333         assertThat(cache.getName(), is("my-txn-cache"));
334         assertThat(invocationsOfBegunTxns, is(0));
335 
336         cache.removeAll();
337         assertThat(invocationsOfBegunTxns, is(1));
338 
339         cache.put("three", "drei", PUT_ALWAYS);
340 
341         final CompletionStage<Optional<String>> get1 = cache.get("three");
342 
343         assertThat(get1, successfulWith(is(Optional.of("drei"))));
344 
345         vCacheLifecycleManager().transactionSync(currentRequestContext());
346         assertThat(invocationsOfBegunTxns, is(1));
347 
348         forceNewRequestContext();
349         final CompletionStage<Optional<String>> get2 = cache.get("three");
350         assertThat(invocationsOfBegunTxns, is(2));
351         unsafeJoin(get2.toCompletableFuture()).get();
352         assertThat(get2, successfulWith(is(Optional.of("drei"))));
353         assertThat(invocationsOfBegunTxns, is(2));
354     }
355 
356     @Test
357     public void verify_txns_sync_sync_sync() {
358         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
359                 .defaultTtl(Duration.ofSeconds(60))
360                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
361                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
362                 .entryCountHint(100)
363                 .build();
364 
365         final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
366                 "sync_sync_sync-1", StringMarshalling.pair(), settings);
367         assertThat(invocationsOfBegunTxns, is(0));
368 
369         cache1.put("updated-key", "first1", PUT_ALWAYS);
370         assertThat(invocationsOfBegunTxns, is(1));
371 
372         cache1.put("phase-1", "first", PUT_ALWAYS);
373         vCacheLifecycleManager().transactionSync(currentRequestContext());
374         assertThat(invocationsOfBegunTxns, is(1));
375 
376         final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
377                 "sync_sync_sync-2", StringMarshalling.pair(), settings);
378 
379         cache1.put("updated-key", "second1", PUT_ALWAYS);
380         assertThat(invocationsOfBegunTxns, is(2));
381 
382         cache2.put("updated-key", "second2", PUT_ALWAYS);
383         cache1.put("phase-2", "second", PUT_ALWAYS);
384         cache2.put("phase-2", "second", PUT_ALWAYS);
385 
386         vCacheLifecycleManager().transactionSync(currentRequestContext());
387         assertThat(invocationsOfBegunTxns, is(2));
388 
389         final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
390                 "sync_sync_sync-3", StringMarshalling.pair(), settings);
391 
392         cache1.put("updated-key", "third1", PUT_ALWAYS);
393         assertThat(invocationsOfBegunTxns, is(3));
394         cache2.put("updated-key", "third2", PUT_ALWAYS);
395         cache1.put("phase-3", "third", PUT_ALWAYS);
396         cache2.put("phase-3", "third", PUT_ALWAYS);
397         cache3.put("phase-3", "third", PUT_ALWAYS);
398 
399         vCacheLifecycleManager().transactionSync(currentRequestContext());
400         assertThat(invocationsOfBegunTxns, is(3));
401 
402         forceNewRequestContext();
403 
404         assertThat(cache1.get("updated-key"), successfulWith(is(Optional.of("third1"))));
405         assertThat(invocationsOfBegunTxns, is(4));
406         assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.of("third1")));
407         assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.of("first")));
408         assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.of("second")));
409         assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.of("third")));
410 
411         assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.of("third2")));
412         assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.of("second")));
413         assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.of("third")));
414 
415         assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.of("third")));
416         assertThat(invocationsOfBegunTxns, is(4));
417     }
418 
419     @Test
420     public void verify_txns_sync_discard_sync() {
421         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
422                 .defaultTtl(Duration.ofSeconds(60))
423                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
424                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
425                 .entryCountHint(100)
426                 .build();
427 
428         final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
429                 "sync_discard_sync-1", StringMarshalling.pair(), settings);
430         assertThat(invocationsOfBegunTxns, is(0));
431 
432         cache1.put("updated-key", "first1", PUT_ALWAYS);
433         assertThat(invocationsOfBegunTxns, is(1));
434         cache1.put("phase-1", "first", PUT_ALWAYS);
435 
436         vCacheLifecycleManager().transactionSync(currentRequestContext());
437 
438         final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
439                 "sync_discard_sync-2", StringMarshalling.pair(), settings);
440 
441         assertThat(invocationsOfBegunTxns, is(1));
442         cache1.put("updated-key", "second1", PUT_ALWAYS);
443         assertThat(invocationsOfBegunTxns, is(2));
444         cache2.put("updated-key", "second2", PUT_ALWAYS);
445         cache1.put("phase-2", "second", PUT_ALWAYS);
446         cache2.put("phase-2", "second", PUT_ALWAYS);
447 
448         vCacheLifecycleManager().transactionDiscard(currentRequestContext());
449 
450         final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
451                 "sync_discard_sync-3", StringMarshalling.pair(), settings);
452 
453         assertThat(invocationsOfBegunTxns, is(2));
454         cache1.put("updated-key", "third1", PUT_ALWAYS);
455         assertThat(invocationsOfBegunTxns, is(3));
456         cache2.put("updated-key", "third2", PUT_ALWAYS);
457         cache1.put("phase-3", "third", PUT_ALWAYS);
458         cache2.put("phase-3", "third", PUT_ALWAYS);
459         cache3.put("phase-3", "third", PUT_ALWAYS);
460 
461         vCacheLifecycleManager().transactionSync(currentRequestContext());
462 
463         forceNewRequestContext();
464 
465         assertThat(invocationsOfBegunTxns, is(3));
466         assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.of("third1")));
467         assertThat(invocationsOfBegunTxns, is(4));
468         assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.of("first")));
469         assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.empty()));
470         assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.of("third")));
471 
472         assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.of("third2")));
473         assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.empty()));
474         assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.of("third")));
475 
476         assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.of("third")));
477         assertThat(invocationsOfBegunTxns, is(4));
478     }
479 
480     @Test
481     public void verify_txns_discard_sync_discard() {
482         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
483                 .defaultTtl(Duration.ofSeconds(60))
484                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
485                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
486                 .entryCountHint(100)
487                 .build();
488 
489         final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
490                 "discard_sync_discard-1", StringMarshalling.pair(), settings);
491 
492         cache1.put("updated-key", "first1", PUT_ALWAYS);
493         cache1.put("phase-1", "first", PUT_ALWAYS);
494 
495         vCacheLifecycleManager().transactionDiscard(currentRequestContext());
496 
497         final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
498                 "discard_sync_discard-2", StringMarshalling.pair(), settings);
499 
500         cache1.put("updated-key", "second1", PUT_ALWAYS);
501         cache2.put("updated-key", "second2", PUT_ALWAYS);
502         cache1.put("phase-2", "second", PUT_ALWAYS);
503         cache2.put("phase-2", "second", PUT_ALWAYS);
504 
505         vCacheLifecycleManager().transactionSync(currentRequestContext());
506 
507         final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
508                 "discard_sync_discard-3", StringMarshalling.pair(), settings);
509 
510         cache1.put("updated-key", "third1", PUT_ALWAYS);
511         cache2.put("updated-key", "third2", PUT_ALWAYS);
512         cache1.put("phase-3", "third", PUT_ALWAYS);
513         cache2.put("phase-3", "third", PUT_ALWAYS);
514         cache3.put("phase-3", "third", PUT_ALWAYS);
515 
516 
517         vCacheLifecycleManager().transactionDiscard(currentRequestContext());
518 
519         forceNewRequestContext();
520 
521         assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.of("second1")));
522         assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.empty()));
523         assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.of("second")));
524         assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.empty()));
525 
526         assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.of("second2")));
527         assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.of("second")));
528         assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.empty()));
529 
530         assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.empty()));
531         assertThat(invocationsOfBegunTxns, is(4));
532     }
533 
534     @Test
535     public void verify_txns_discard_discard_discard() {
536         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
537                 .defaultTtl(Duration.ofSeconds(60))
538                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
539                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
540                 .entryCountHint(100)
541                 .build();
542 
543         final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
544                 "discard_discard_discard-1", StringMarshalling.pair(), settings);
545 
546         cache1.put("updated-key", "first1", PUT_ALWAYS);
547         cache1.put("phase-1", "first", PUT_ALWAYS);
548 
549         vCacheLifecycleManager().transactionDiscard(currentRequestContext());
550 
551         final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
552                 "discard_discard_discard-2", StringMarshalling.pair(), settings);
553 
554         cache1.put("updated-key", "second1", PUT_ALWAYS);
555         cache2.put("updated-key", "second2", PUT_ALWAYS);
556         cache1.put("phase-2", "second", PUT_ALWAYS);
557         cache2.put("phase-2", "second", PUT_ALWAYS);
558 
559         vCacheLifecycleManager().transactionDiscard(currentRequestContext());
560 
561         final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
562                 "discard_discard_discard-3", StringMarshalling.pair(), settings);
563 
564         cache1.put("updated-key", "third1", PUT_ALWAYS);
565         cache2.put("updated-key", "third2", PUT_ALWAYS);
566         cache1.put("phase-3", "third", PUT_ALWAYS);
567         cache2.put("phase-3", "third", PUT_ALWAYS);
568         cache3.put("phase-3", "third", PUT_ALWAYS);
569 
570         vCacheLifecycleManager().transactionDiscard(currentRequestContext());
571 
572         forceNewRequestContext();
573 
574         assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.empty()));
575         assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.empty()));
576         assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.empty()));
577         assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.empty()));
578 
579         assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.empty()));
580         assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.empty()));
581         assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.empty()));
582 
583         assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.empty()));
584         assertThat(invocationsOfBegunTxns, is(4));
585     }
586 
587     @Test
588     public void duplicate_names_different_policys() {
589         final DirectExternalCache<String> directCache =
590                 vCacheFactory().getDirectExternalCache(
591                         "duplicate", StringMarshalling.pair(), new ExternalCacheSettingsBuilder().build());
592 
593         thrown.expect(ExternalCacheException.class);
594         thrown.expectMessage("Failed due to CREATION_FAILURE");
595 
596         final StableReadExternalCache<String> stableCache =
597                 vCacheFactory().getStableReadExternalCache(
598                         "duplicate", StringMarshalling.pair(), new ExternalCacheSettingsBuilder().build());
599     }
600 
601     @Test
602     public void directexternalcache_duplicate_obtain() {
603         final DirectExternalCache<String> firstTime =
604                 vCacheFactory().getDirectExternalCache(
605                         "duplicate", dodgyPair("first"), new ExternalCacheSettingsBuilder().build());
606 
607         final CompletionStage<Boolean> put1 = firstTime.put("key", "ignored", PUT_ALWAYS);
608         assertThat(VCacheUtils.unsafeJoin(put1), is(true));
609 
610         final CompletionStage<Optional<String>> get1 = firstTime.get("key");
611         assertThat(VCacheUtils.unsafeJoin(get1), is(Optional.of("first")));
612 
613         final DirectExternalCache<String> secondTime =
614                 vCacheFactory().getDirectExternalCache(
615                         "duplicate", dodgyPair("second"), new ExternalCacheSettingsBuilder().build());
616 
617         final CompletionStage<Optional<String>> get2 = secondTime.get("key");
618         assertThat(VCacheUtils.unsafeJoin(get2), is(Optional.of("second")));
619     }
620 
621     @Test
622     public void stablereadexternalcache_duplicate_obtain() {
623         final StableReadExternalCache<String> firstTime =
624                 vCacheFactory().getStableReadExternalCache(
625                         "duplicate", dodgyPair("first"), new ExternalCacheSettingsBuilder().build());
626 
627         final CompletionStage<Boolean> put1 = firstTime.put("key", "ignored", PUT_ALWAYS);
628         assertThat(VCacheUtils.unsafeJoin(put1), is(true));
629 
630         forceNewRequestContext();
631         final CompletionStage<Optional<String>> get1 = firstTime.get("key");
632         assertThat(VCacheUtils.unsafeJoin(get1), is(Optional.of("first")));
633 
634         final StableReadExternalCache<String> secondTime =
635                 vCacheFactory().getStableReadExternalCache(
636                         "duplicate", dodgyPair("second"), new ExternalCacheSettingsBuilder().build());
637         forceNewRequestContext();
638 
639         final CompletionStage<Optional<String>> get2 = secondTime.get("key");
640         assertThat(VCacheUtils.unsafeJoin(get2), is(Optional.of("second")));
641     }
642 
643     @Test
644     public void txnexternalcache_duplicate_obtain() {
645         final TransactionalExternalCache<String> firstTime =
646                 vCacheFactory().getTransactionalExternalCache(
647                         "duplicate", dodgyPair("first"), new ExternalCacheSettingsBuilder().build());
648 
649         firstTime.put("key", "ignored", PUT_ALWAYS);
650         vCacheLifecycleManager().transactionSync(currentRequestContext());
651 
652         forceNewRequestContext();
653         final CompletionStage<Optional<String>> get1 = firstTime.get("key");
654         assertThat(VCacheUtils.unsafeJoin(get1), is(Optional.of("first")));
655 
656         final TransactionalExternalCache<String> secondTime =
657                 vCacheFactory().getTransactionalExternalCache(
658                         "duplicate", dodgyPair("second"), new ExternalCacheSettingsBuilder().build());
659 
660         forceNewRequestContext();
661         final CompletionStage<Optional<String>> get2 = secondTime.get("key");
662         assertThat(VCacheUtils.unsafeJoin(get2), is(Optional.of("second")));
663     }
664 
665     private static MarshallingPair<String> dodgyPair(String returning) {
666         return new MarshallingPair<>(String::getBytes, b -> returning);
667     }
668 
669     @Test
670     public void handle_legal_recursive_get_supplier() {
671         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
672                 .defaultTtl(Duration.ofSeconds(60))
673                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
674                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
675                 .entryCountHint(100)
676                 .build();
677 
678         final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
679                 "my-stable-read-cache", StringMarshalling.pair(), settings);
680 
681         final CompletionStage<String> get1 = cache.get("recursive", () ->
682                 "ignored-" + unsafeJoin(cache.get("recursive", () -> "2")));
683         assertThat(get1, successfulWith(is("2")));
684     }
685 
686     @Test
687     public void handle_legal_recursive_get_supplier2() {
688         final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
689                 .defaultTtl(Duration.ofSeconds(60))
690                 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
691                 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
692                 .entryCountHint(100)
693                 .build();
694 
695         final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
696                 "my-stable-read-cache", StringMarshalling.pair(), settings);
697 
698         final CompletionStage<String> get1 = cache.get("recursive", () ->
699                 unsafeJoin(cache.get("recursive2", () -> "pass")));
700         assertThat(get1, successfulWith(is("pass")));
701     }
702 }