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