View Javadoc

1   package com.atlassian.vcache.internal.memcached;
2   
3   import com.atlassian.marshalling.jdk.StringMarshalling;
4   import com.atlassian.vcache.DirectExternalCache;
5   import com.atlassian.vcache.ExternalCacheException;
6   import com.atlassian.vcache.ExternalCacheSettings;
7   import com.atlassian.vcache.ExternalCacheSettingsBuilder;
8   import com.atlassian.vcache.JvmCache;
9   import com.atlassian.vcache.JvmCacheSettings;
10  import com.atlassian.vcache.JvmCacheSettingsBuilder;
11  import com.atlassian.vcache.RequestCache;
12  import com.atlassian.vcache.StableReadExternalCache;
13  import com.atlassian.vcache.VCacheException;
14  import com.atlassian.vcache.internal.BegunTransactionalActivityHandler;
15  import com.atlassian.vcache.internal.ExternalCacheDetails;
16  import com.atlassian.vcache.internal.JvmCacheDetails;
17  import com.atlassian.vcache.internal.RequestCacheDetails;
18  import com.atlassian.vcache.internal.VCacheCreationHandler;
19  import com.atlassian.vcache.internal.VCacheSettingsDefaultsProvider;
20  import com.atlassian.vcache.internal.core.ExternalCacheKeyGenerator;
21  import com.atlassian.vcache.internal.core.ThreadLocalRequestContextSupplier;
22  import com.atlassian.vcache.internal.core.metrics.DefaultMetricsCollector;
23  import com.atlassian.vcache.internal.core.metrics.MetricsCollector;
24  import net.spy.memcached.MemcachedClientIF;
25  import org.junit.After;
26  import org.junit.Before;
27  import org.junit.Rule;
28  import org.junit.Test;
29  import org.junit.rules.ExpectedException;
30  import org.junit.runner.RunWith;
31  import org.mockito.ArgumentCaptor;
32  import org.mockito.Captor;
33  import org.mockito.Mock;
34  import org.mockito.runners.MockitoJUnitRunner;
35  
36  import java.io.File;
37  import java.time.Duration;
38  import java.util.Map;
39  import java.util.Optional;
40  
41  import static org.hamcrest.Matchers.containsInAnyOrder;
42  import static org.hamcrest.Matchers.is;
43  import static org.hamcrest.Matchers.notNullValue;
44  import static org.junit.Assert.assertThat;
45  import static org.mockito.Matchers.any;
46  import static org.mockito.Matchers.eq;
47  import static org.mockito.Mockito.doThrow;
48  import static org.mockito.Mockito.times;
49  import static org.mockito.Mockito.verify;
50  import static org.mockito.Mockito.verifyNoMoreInteractions;
51  import static org.mockito.Mockito.when;
52  
53  @RunWith(MockitoJUnitRunner.class)
54  public class MemcachedVCacheServiceTest {
55      @Rule
56      public ExpectedException thrown = ExpectedException.none();
57  
58      @Mock
59      private MemcachedClientIF client;
60      @Mock
61      private VCacheSettingsDefaultsProvider defaultsProvider;
62      @Mock
63      private VCacheCreationHandler creationHandler;
64      @Mock
65      private BegunTransactionalActivityHandler begunTransactionalActivityHandler;
66  
67      @Captor
68      private ArgumentCaptor<JvmCacheDetails> jvmCacheDetailsCaptor;
69      @Captor
70      private ArgumentCaptor<ExternalCacheDetails> externalCacheDetailsCaptor;
71  
72      private final ThreadLocalRequestContextSupplier requestContextSupplier = ThreadLocalRequestContextSupplier.strictSupplier();
73      private final MetricsCollector metricsCollector = new DefaultMetricsCollector(requestContextSupplier);
74  
75  
76      private MemcachedVCacheService service;
77  
78      @Before
79      public void initService() {
80          final MemcachedVCacheServiceSettings settings = new MemcachedVCacheServiceSettingsBuilder()
81                  .productIdentifier("confira")
82                  .clientSupplier(() -> client)
83                  .threadLocalContextSupplier(requestContextSupplier)
84                  .workContextContextSupplier(requestContextSupplier)
85                  .defaultsProvider(defaultsProvider)
86                  .creationHandler(creationHandler)
87                  .metricsCollector(metricsCollector)
88                  .begunTransactionalActivityHandler(begunTransactionalActivityHandler)
89                  .build();
90  
91          service = new MemcachedVCacheService(settings);
92      }
93  
94      @After
95      public void destroyService() {
96          verifyNoMoreInteractions(client);
97      }
98  
99      @Test
100     public void getJvmCache_normal() throws Exception {
101         final JvmCacheSettings initSettings = new JvmCacheSettingsBuilder()
102                 .defaultTtl(Duration.ofSeconds(10))
103                 .maxEntries(20)
104                 .build();
105         final JvmCacheSettings finalSettings = new JvmCacheSettingsBuilder()
106                 .defaultTtl(Duration.ofSeconds(5))
107                 .maxEntries(10)
108                 .build();
109 
110         when(defaultsProvider.getJvmDefaults(eq("fruit")))
111                 .thenReturn(new JvmCacheSettingsBuilder().build());
112         when(creationHandler.jvmCacheCreation(any()))
113                 .thenReturn(finalSettings);
114 
115         final JvmCache<String, Object> cache = service.getJvmCache("fruit", initSettings);
116 
117         verify(creationHandler).jvmCacheCreation(jvmCacheDetailsCaptor.capture());
118         assertThat(cache, notNullValue());
119         assertThat(cache.getName(), is("fruit"));
120 
121         final JvmCacheDetails details = jvmCacheDetailsCaptor.getValue();
122         assertThat(details, notNullValue());
123         assertThat(details.getSettings(), notNullValue());
124         assertThat(details.getName(), notNullValue());
125         assertThat(details.getName(), is("fruit"));
126         assertThat(details.getSettings().getDefaultTtl(), is(Optional.of(Duration.ofSeconds(10))));
127         assertThat(details.getSettings().getMaxEntries(), is(Optional.of(20)));
128 
129         final JvmCache<String, Object> cache2 = service.getJvmCache("fruit", initSettings);
130 
131         assertThat(cache2, notNullValue());
132         assertThat(cache2, is(cache));
133 
134         final Map<String, JvmCacheDetails> allJvmDetails = service.allJvmCacheDetails();
135 
136         assertThat(allJvmDetails, notNullValue());
137         assertThat(allJvmDetails.keySet(), containsInAnyOrder("fruit"));
138         assertThat(allJvmDetails.get("fruit").getName(), is("fruit"));
139         assertThat(allJvmDetails.get("fruit").getSettings(), is(finalSettings));
140         verify(begunTransactionalActivityHandler, times(0)).onRequest(any());
141     }
142 
143     @Test
144     public void getJvmCache_failure() {
145         final JvmCacheSettings initSettings = new JvmCacheSettingsBuilder()
146                 .defaultTtl(Duration.ofSeconds(10))
147                 .maxEntries(20)
148                 .build();
149 
150         when(defaultsProvider.getJvmDefaults(eq("bat")))
151                 .thenReturn(new JvmCacheSettingsBuilder().build());
152         when(creationHandler.jvmCacheCreation(any())).thenThrow(new VCacheException("not allowed"));
153 
154         thrown.expect(VCacheException.class);
155         thrown.expectMessage("not allowed");
156 
157         final JvmCache<String, File> cache = service.getJvmCache("bat", initSettings);
158         verify(begunTransactionalActivityHandler, times(0)).onRequest(any());
159     }
160 
161     @Test
162     public void getRequestCache_normal() throws Exception {
163         final RequestCache<File, String> cache = service.getRequestCache("threadlocal");
164 
165         final ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
166         verify(creationHandler, times(1)).requestCacheCreation(argument.capture());
167 
168         assertThat(cache, notNullValue());
169         assertThat(cache.getName(), is("threadlocal"));
170         assertThat(argument.getValue(), is("threadlocal"));
171 
172         final Map<String, RequestCacheDetails> allRequestDetails = service.allRequestCacheDetails();
173 
174         assertThat(allRequestDetails, notNullValue());
175         assertThat(allRequestDetails.keySet(), containsInAnyOrder("threadlocal"));
176         assertThat(allRequestDetails.get("threadlocal").getName(), is("threadlocal"));
177         verify(begunTransactionalActivityHandler, times(0)).onRequest(any());
178     }
179 
180     @Test
181     public void getRequestCache_failure() {
182         doThrow(new VCacheException("not allowed")).when(creationHandler).requestCacheCreation(eq("threadlocal"));
183 
184         thrown.expect(VCacheException.class);
185         thrown.expectMessage("not allowed");
186 
187         final RequestCache<File, String> cache = service.getRequestCache("threadlocal");
188         verify(begunTransactionalActivityHandler, times(0)).onRequest(any());
189     }
190 
191     @Test
192     public void getDirectExternalCache_normal() throws Exception {
193         final ExternalCacheSettings initSettings = new ExternalCacheSettingsBuilder()
194                 .defaultTtl(Duration.ofSeconds(10))
195                 .entryCountHint(10)
196                 .build();
197         final ExternalCacheSettings finalSettings = new ExternalCacheSettingsBuilder()
198                 .defaultTtl(Duration.ofSeconds(5))
199                 .entryCountHint(5)
200                 .build();
201 
202         when(defaultsProvider.getExternalDefaults(eq("fruit")))
203                 .thenReturn(new ExternalCacheSettingsBuilder().build());
204         when(creationHandler.externalCacheCreation(any()))
205                 .thenReturn(finalSettings);
206 
207         final DirectExternalCache<String> cache =
208                 service.getDirectExternalCache("fruit", StringMarshalling.pair(), initSettings);
209 
210         verify(creationHandler).externalCacheCreation(externalCacheDetailsCaptor.capture());
211         assertThat(cache, notNullValue());
212         assertThat(cache.getName(), is("fruit"));
213 
214         final ExternalCacheDetails details = externalCacheDetailsCaptor.getValue();
215         assertThat(details, notNullValue());
216         assertThat(details.getSettings(), notNullValue());
217         assertThat(details.getName(), notNullValue());
218         assertThat(details.getName(), is("fruit"));
219         assertThat(details.getSettings().getDefaultTtl(), is(Optional.of(Duration.ofSeconds(10))));
220 
221         final DirectExternalCache<String> cache2 =
222                 service.getDirectExternalCache("fruit", StringMarshalling.pair(), initSettings);
223 
224         assertThat(cache2, notNullValue());
225 
226         final Map<String, ExternalCacheDetails> allExternalDetails = service.allExternalCacheDetails();
227 
228         assertThat(allExternalDetails, notNullValue());
229         assertThat(allExternalDetails.keySet(), containsInAnyOrder("fruit"));
230         assertThat(allExternalDetails.get("fruit").getName(), is("fruit"));
231         assertThat(allExternalDetails.get("fruit").getSettings(), is(finalSettings));
232         verify(begunTransactionalActivityHandler, times(0)).onRequest(any());
233     }
234 
235     @Test
236     public void getStableReadExternalCache_normal() throws Exception {
237         final ExternalCacheSettings initSettings = new ExternalCacheSettingsBuilder()
238                 .defaultTtl(Duration.ofSeconds(10))
239                 .entryCountHint(10)
240                 .build();
241         final ExternalCacheSettings finalSettings = new ExternalCacheSettingsBuilder()
242                 .defaultTtl(Duration.ofSeconds(5))
243                 .entryCountHint(5)
244                 .build();
245 
246         when(defaultsProvider.getExternalDefaults(eq("fruit")))
247                 .thenReturn(new ExternalCacheSettingsBuilder().build());
248         when(creationHandler.externalCacheCreation(any()))
249                 .thenReturn(finalSettings);
250 
251         final StableReadExternalCache<String> cache =
252                 service.getStableReadExternalCache("fruit", StringMarshalling.pair(), initSettings);
253 
254         verify(creationHandler).externalCacheCreation(externalCacheDetailsCaptor.capture());
255         assertThat(cache, notNullValue());
256         assertThat(cache.getName(), is("fruit"));
257 
258         final ExternalCacheDetails details = externalCacheDetailsCaptor.getValue();
259         assertThat(details, notNullValue());
260         assertThat(details.getSettings(), notNullValue());
261         assertThat(details.getName(), notNullValue());
262         assertThat(details.getName(), is("fruit"));
263         assertThat(details.getSettings().getDefaultTtl(), is(Optional.of(Duration.ofSeconds(10))));
264 
265         final StableReadExternalCache<String> cache2 =
266                 service.getStableReadExternalCache("fruit", StringMarshalling.pair(), initSettings);
267 
268         assertThat(cache2, notNullValue());
269         verify(begunTransactionalActivityHandler, times(0)).onRequest(any());
270     }
271 
272     @Test
273     public void getDirectExternalCache_getStableReadExternalCache_failure() throws Exception {
274         final ExternalCacheSettings initSettings = new ExternalCacheSettingsBuilder()
275                 .defaultTtl(Duration.ofSeconds(10))
276                 .entryCountHint(10)
277                 .build();
278         final ExternalCacheSettings finalSettings = new ExternalCacheSettingsBuilder()
279                 .defaultTtl(Duration.ofSeconds(5))
280                 .entryCountHint(5)
281                 .build();
282 
283         when(defaultsProvider.getExternalDefaults(eq("fruit")))
284                 .thenReturn(new ExternalCacheSettingsBuilder().build());
285         when(creationHandler.externalCacheCreation(any()))
286                 .thenReturn(finalSettings);
287 
288         final DirectExternalCache<String> cache =
289                 service.getDirectExternalCache("fruit", StringMarshalling.pair(), initSettings);
290 
291         verify(creationHandler).externalCacheCreation(externalCacheDetailsCaptor.capture());
292         assertThat(cache, notNullValue());
293         assertThat(cache.getName(), is("fruit"));
294 
295         thrown.expect(ExternalCacheException.class);
296         thrown.expectMessage("Failed due to CREATION_FAILURE");
297 
298         final StableReadExternalCache<String> cache2 =
299                 service.getStableReadExternalCache("fruit", StringMarshalling.pair(), initSettings);
300     }
301 }