View Javadoc

1   package com.atlassian.vcache.internal.test;
2   
3   import com.atlassian.vcache.DirectExternalCache;
4   import com.atlassian.vcache.PutPolicy;
5   import com.atlassian.vcache.TransactionalExternalCache;
6   import com.google.common.collect.Maps;
7   import org.junit.Rule;
8   import org.junit.Test;
9   import org.slf4j.Logger;
10  import org.slf4j.LoggerFactory;
11  
12  import java.util.Map;
13  import java.util.Optional;
14  import java.util.concurrent.CompletionStage;
15  import java.util.stream.Collectors;
16  
17  import static com.atlassian.vcache.VCacheUtils.unsafeJoin;
18  import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successful;
19  import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successfulWith;
20  import static org.hamcrest.Matchers.containsInAnyOrder;
21  import static org.hamcrest.Matchers.is;
22  import static org.hamcrest.Matchers.not;
23  import static org.junit.Assert.assertThat;
24  
25  /**
26   * Base test class for the {@link com.atlassian.vcache.TransactionalExternalCache}.
27   */
28  public abstract class AbstractTransactionalExternalCacheIT {
29      protected static final String CACHE_NAME = "fragileSting";
30      private static final Logger log = LoggerFactory.getLogger(AbstractStableReadExternalCacheIT.class);
31  
32      @Rule
33      public LoggingTestWatcher watcher = new LoggingTestWatcher(log);
34  
35      protected abstract TransactionalExternalCache<String> cache();
36  
37      protected abstract DirectExternalCache<String> directCache();
38  
39      protected abstract void directCacheRefresh();
40  
41      protected abstract void cacheTransactionSync();
42      protected abstract void cacheTransactionDiscard();
43  
44      @Test
45      public void put_get_sync_successful2() {
46          cache().put("claira", "dancing", PutPolicy.PUT_ALWAYS);
47  
48          final CompletionStage<Optional<String>> get1 = cache().get("claira");
49  
50          assertThat(get1, successfulWith(is(Optional.of("dancing"))));
51  
52          // Now use the directCache to verify no data has been written
53          directCacheRefresh();
54          final CompletionStage<Optional<String>> get2 = directCache().get("claira");
55  
56          assertThat(get2, successfulWith(is(Optional.empty())));
57  
58          // Now sync the changes
59          cacheTransactionSync();
60  
61          // And check the changes are now visible
62          directCacheRefresh();
63          final CompletionStage<Optional<String>> get3 = directCache().get("claira");
64  
65          assertThat(get3, successfulWith(is(Optional.of("dancing"))));
66  
67          // Now check another lookup will succeed with the transactional cache
68          final CompletionStage<Optional<String>> get4 = cache().get("claira");
69  
70          assertThat(get4, successfulWith(is(Optional.of("dancing"))));
71      }
72  
73      @Test
74      public void put_get_sync_unsuccessful2() throws Exception {
75          cache().put("claira", "dancing", PutPolicy.ADD_ONLY); // Must be ADD_ONLY
76  
77          final CompletionStage<Optional<String>> get1 = cache().get("claira");
78  
79          assertThat(get1, successfulWith(is(Optional.of("dancing"))));
80  
81          // Now use the directCache to verify no data has been written
82          directCacheRefresh();
83          final CompletionStage<Optional<String>> get2 = directCache().get("claira");
84  
85          assertThat(get2, successfulWith(is(Optional.empty())));
86  
87          // Now add values to the backing cache using the directCache
88          final CompletionStage<Map<String, String>> get3 =
89                  directCache().getBulk(keys -> Maps.asMap(keys, k -> k + "-1"), "claira", "josephine");
90  
91          assertThat(get3, successful());
92          assertThat(unsafeJoin(get3).keySet(), containsInAnyOrder("claira", "josephine"));
93          assertThat(unsafeJoin(get3).values(), containsInAnyOrder("claira-1", "josephine-1"));
94  
95          // Now sync the changes
96          cacheTransactionSync();
97  
98          // And check the cache is empty
99          directCacheRefresh();
100         final CompletionStage<Map<String, Optional<String>>> get4 = directCache().getBulk("claira", "josephine");
101 
102         assertThat(get4, successful());
103         assertThat(unsafeJoin(get4).keySet(), containsInAnyOrder("claira", "josephine"));
104         assertThat(unsafeJoin(get4).values(), containsInAnyOrder(Optional.empty(), Optional.empty()));
105     }
106 
107     @Test
108     public void getBulk_getBulkFunction_directPut_sync() throws Exception {
109         final CompletionStage<Boolean> put1 = directCache().put("claira", "dancing", PutPolicy.PUT_ALWAYS);
110 
111         assertThat(put1, successful());
112 
113         final CompletionStage<Map<String, Optional<String>>> get1 = cache().getBulk("claira", "josephine");
114 
115         assertThat(get1, successful());
116         assertThat(unsafeJoin(get1).keySet(), containsInAnyOrder("claira", "josephine"));
117         assertThat(unsafeJoin(get1).values(), containsInAnyOrder(Optional.of("dancing"), Optional.empty()));
118 
119         final CompletionStage<Map<String, String>> get2 =
120                 cache().getBulk(keys -> Maps.asMap(keys, k -> "football"), "claira", "josephine");
121 
122         assertThat(get2, successful());
123         assertThat(unsafeJoin(get2).keySet(), containsInAnyOrder("claira", "josephine"));
124         assertThat(unsafeJoin(get2).values(), containsInAnyOrder("dancing", "football"));
125 
126         // Now add an entry to the backend cache for "josephine" and verify one does not exist yet
127         directCacheRefresh();
128         final CompletionStage<Boolean> put2 = directCache().put("josephine", "soccer", PutPolicy.ADD_ONLY);
129 
130         assertThat(put2, successfulWith(is(true)));
131 
132         cacheTransactionSync();
133 
134         // Now verify nothing in the cache, due to panic when added josephine
135         directCacheRefresh();
136         final CompletionStage<Map<String, Optional<String>>> get3 = directCache().getBulk("claira", "josephine");
137 
138         assertThat(get3, successful());
139         assertThat(unsafeJoin(get3).keySet(), containsInAnyOrder("claira", "josephine"));
140         assertThat(unsafeJoin(get3).values(), containsInAnyOrder(Optional.empty(), Optional.empty()));
141     }
142 
143     @Test
144     public void put_get_remove_get() {
145         cache().put("nirvana", "shotgun", PutPolicy.PUT_ALWAYS);
146 
147         final CompletionStage<Optional<String>> get1 = cache().get("nirvana");
148 
149         assertThat(get1, successfulWith(is(Optional.of("shotgun"))));
150 
151         cache().remove("a", "b", "nirvana");
152 
153         final CompletionStage<Optional<String>> get2 = cache().get("nirvana");
154 
155         assertThat(get2, successfulWith(is(Optional.empty())));
156     }
157 
158     @Test
159     public void getSupplier_removeAll_get() {
160         final CompletionStage<String> get1 = cache().get("vienna", () -> "sandwiches");
161 
162         assertThat(get1, successfulWith(is("sandwiches")));
163 
164         cache().removeAll();
165 
166         final CompletionStage<Optional<String>> get2 = cache().get("vienna");
167 
168         assertThat(get2, successfulWith(is(Optional.empty())));
169     }
170 
171     @Test
172     public void getSupplier_removeAll_getSupplier_getSupplier() {
173         final CompletionStage<String> get1 = cache().get("vienna", () -> "sandwiches");
174 
175         assertThat(get1, successfulWith(is("sandwiches")));
176 
177         cache().removeAll();
178 
179         final CompletionStage<Optional<String>> get2 = cache().get("vienna");
180 
181         assertThat(get2, successfulWith(is(Optional.empty())));
182 
183         final CompletionStage<String> get3 = cache().get("vienna", () -> "new value");
184 
185         assertThat(get3, successfulWith(is("new value")));
186 
187         final CompletionStage<String> get4 = cache().get("vienna", () -> "not used");
188 
189         assertThat(get4, successfulWith(is("new value")));
190     }
191 
192     @Test
193     public void getSupplier_removeAll_getBulk_getBulk() {
194         final CompletionStage<String> get1 = cache().get("vienna", () -> "sandwiches");
195 
196         assertThat(get1, successfulWith(is("sandwiches")));
197 
198         cache().removeAll();
199 
200         final CompletionStage<Optional<String>> get2 = cache().get("vienna");
201 
202         assertThat(get2, successfulWith(is(Optional.empty())));
203 
204         final CompletionStage<Map<String, String>> get3 = cache().getBulk(keys -> Maps.asMap(keys, k -> k + "-1"), "vienna");
205 
206         assertThat(get3, successful());
207         assertThat(unsafeJoin(get3).keySet(), containsInAnyOrder("vienna"));
208         assertThat(unsafeJoin(get3).values(), containsInAnyOrder("vienna-1"));
209 
210         final CompletionStage<Map<String, String>> get4 = cache().getBulk(keys -> Maps.asMap(keys, k -> k + "-2"), "vienna");
211 
212         assertThat(get4, successful());
213         assertThat(unsafeJoin(get4).keySet(), containsInAnyOrder("vienna"));
214         assertThat(unsafeJoin(get4).values(), containsInAnyOrder("vienna-1"));
215     }
216 
217     @Test
218     public void put_get_discard() {
219         cache().put("josie", "surfing", PutPolicy.PUT_ALWAYS);
220 
221         final CompletionStage<Optional<String>> get1 = cache().get("josie");
222 
223         assertThat(get1, successfulWith(is(Optional.of("surfing"))));
224 
225         // Now use the directCache to verify no data has been written
226         directCacheRefresh();
227         final CompletionStage<Optional<String>> get2 = directCache().get("josie");
228 
229         assertThat(get2, successfulWith(is(Optional.empty())));
230 
231         // Now discard the changes
232         cacheTransactionDiscard();
233 
234         // And check the changes are not visible
235         directCacheRefresh();
236         final CompletionStage<Optional<String>> get3 = directCache().get("josie");
237 
238         assertThat(get3, successfulWith(is(Optional.empty())));
239     }
240 
241     @Test
242     public void existing_remove_get() {
243         directCache().put("key", "existing", PutPolicy.PUT_ALWAYS);
244 
245         final CompletionStage<Optional<String>> get1 = cache().get("key");
246 
247         assertThat(get1, successfulWith(is(Optional.of("existing"))));
248 
249         cache().remove("key");
250 
251         final CompletionStage<Optional<String>> get2 = cache().get("key");
252 
253         assertThat(get2, successfulWith(is(Optional.empty())));
254     }
255 
256     @Test
257     public void existing_remove_getSupplier() {
258         directCache().put("key", "existing", PutPolicy.PUT_ALWAYS);
259 
260         final CompletionStage<Optional<String>> get1 = cache().get("key");
261 
262         assertThat(get1, successfulWith(is(Optional.of("existing"))));
263 
264         cache().remove("key");
265 
266         final CompletionStage<String> get2 = cache().get("key", () -> "new");
267 
268         assertThat(get2, successfulWith(is("new")));
269     }
270 
271     @Test
272     public void existing_remove_getBulk() {
273         directCache().put("key", "existing", PutPolicy.PUT_ALWAYS);
274 
275         final CompletionStage<Optional<String>> get1 = cache().get("key");
276 
277         assertThat(get1, successfulWith(is(Optional.of("existing"))));
278 
279         cache().remove("key");
280 
281         final CompletionStage<Map<String, String>> get2 = cache().getBulk(
282                 strings -> strings.stream().collect(Collectors.toMap(k -> k, k -> k + "-new")),
283                 "key", "extra");
284 
285         assertThat(get2, successful());
286         assertThat(unsafeJoin(get2).keySet(), containsInAnyOrder("key", "extra"));
287         assertThat(unsafeJoin(get2).values(), containsInAnyOrder("key-new", "extra-new"));
288     }
289 
290     @Test
291     public void existing_removeAll_get() {
292         directCache().put("key", "existing", PutPolicy.PUT_ALWAYS);
293 
294         final CompletionStage<Optional<String>> get1 = cache().get("key");
295 
296         assertThat(get1, successfulWith(is(Optional.of("existing"))));
297 
298         cache().removeAll();
299 
300         final CompletionStage<Optional<String>> get2 = cache().get("key");
301 
302         assertThat(get2, successfulWith(is(Optional.empty())));
303     }
304 
305     @Test
306     public void existing_removeAll_getSupplier() {
307         directCache().put("key", "existing", PutPolicy.PUT_ALWAYS);
308 
309         final CompletionStage<Optional<String>> get1 = cache().get("key");
310 
311         assertThat(get1, successfulWith(is(Optional.of("existing"))));
312 
313         cache().removeAll();
314 
315         final CompletionStage<String> get2 = cache().get("key", () -> "new");
316 
317         assertThat(get2, successfulWith(is("new")));
318     }
319 
320     @Test
321     public void existing_removeAll_getBulk() {
322         directCache().put("key", "existing", PutPolicy.PUT_ALWAYS);
323 
324         final CompletionStage<Optional<String>> get1 = cache().get("key");
325 
326         assertThat(get1, successfulWith(is(Optional.of("existing"))));
327 
328         cache().removeAll();
329 
330         final CompletionStage<Map<String, String>> get2 = cache().getBulk(
331                 strings -> strings.stream().collect(Collectors.toMap(k -> k, k -> k + "-new")),
332                 "key");
333 
334         assertThat(get2, successful());
335         assertThat(unsafeJoin(get2).keySet(), containsInAnyOrder("key"));
336         assertThat(unsafeJoin(get2).values(), containsInAnyOrder("key-new"));
337     }
338 
339     @Test
340     public void check_get_null_detection() {
341         assertThat(cache().get("kenny", () -> null), not(successful()));
342         assertThat(cache().getBulk(
343                 strings -> strings.stream().collect(Collectors.toMap(k -> k, k -> null)),
344                 "extra"),
345                 not(successful()));
346     }
347 
348     @SuppressWarnings("ConstantConditions")
349     @Test(expected = NullPointerException.class)
350     public void check_put_null_detection() {
351         cache().put("key", null, PutPolicy.ADD_ONLY);
352     }
353 }
354