View Javadoc
1   package com.atlassian.cache;
2   
3   import java.util.Map;
4   import java.util.concurrent.TimeUnit;
5   
6   import org.junit.Test;
7   import org.mockito.ArgumentCaptor;
8   
9   import javax.annotation.Nonnull;
10  
11  import static org.junit.Assert.assertEquals;
12  import static org.junit.Assert.assertNull;
13  import static org.mockito.ArgumentMatchers.eq;
14  import static org.mockito.Mockito.mock;
15  import static org.mockito.Mockito.timeout;
16  import static org.mockito.Mockito.verify;
17  import static org.mockito.Mockito.when;
18  
19  public abstract class AbstractCacheListenerTest
20  {
21      protected CacheFactory factory;
22  
23      @Test
24      public void testOnAdd() throws Exception
25      {
26          CacheLoader<String, String> cacheLoader = mock(CacheLoader.class);
27          when(cacheLoader.load("add")).thenReturn("ADD");
28  
29          Cache<String, String> cache = factory.getCache("ADD_CACHE", cacheLoader, settingsBuilder().build());
30  
31          CacheEntryListener listener = mock(CacheEntryListener.class);
32          cache.addListener(listener, true);
33  
34          cache.get("add");
35  
36          ArgumentCaptor<CacheEntryEvent> captor = ArgumentCaptor.forClass(CacheEntryEvent.class);
37          verify(listener, timeout(1000)).onAdd(captor.capture());
38  
39          CacheEntryEvent<String, String> event = captor.getValue();
40          assertEquals("add", event.getKey());
41          assertNull(event.getOldValue());
42          if (supportsAddValue())
43          {
44              assertEquals("ADD", event.getValue());
45          }
46          else
47          {
48              assertNull(event.getValue());
49          }
50      }
51  
52      @Test
53      public void testOnAddPut() throws Exception
54      {
55          Cache<String, String> cache = factory.getCache("PUT_CACHE");
56  
57          CacheEntryListener listener = mock(CacheEntryListener.class);
58          cache.addListener(listener, true);
59  
60          cache.put("put", "PUT");
61  
62          ArgumentCaptor<CacheEntryEvent> captor = ArgumentCaptor.forClass(CacheEntryEvent.class);
63          verify(listener, timeout(1000)).onAdd(captor.capture());
64  
65          CacheEntryEvent<String, String> event = captor.getValue();
66          assertEquals("put", event.getKey());
67          assertNull(event.getOldValue());
68          if (supportsPutValue())
69          {
70              assertEquals("PUT", event.getValue());
71          }
72          else
73          {
74              assertNull(event.getValue());
75          }
76      }
77  
78      @Test
79      public void testOnReplace() throws Exception
80      {
81          CacheLoader<String, String> cacheLoader = mock(CacheLoader.class);
82          when(cacheLoader.load("replace")).thenReturn("REPLACE");
83  
84          Cache<String, String> cache = factory.getCache("REPLACE_CACHE", cacheLoader, settingsBuilder().build());
85          CacheEntryListener listener = mock(CacheEntryListener.class);
86          cache.addListener(listener, true);
87  
88          cache.get("replace");
89          cache.replace("replace", "REPLACE", "REPLACED");
90  
91          ArgumentCaptor<CacheEntryEvent> captor = ArgumentCaptor.forClass(CacheEntryEvent.class);
92          verify(listener, timeout(1000)).onUpdate(captor.capture());
93  
94          CacheEntryEvent<String, String> event = captor.getValue();
95          assertEquals("replace", event.getKey());
96          if (supportsUpdateOldValue())
97          {
98              assertEquals("REPLACE", event.getOldValue());
99          }
100         else
101         {
102             assertNull(event.getOldValue());
103         }
104         if (supportsUpdateValue())
105         {
106             assertEquals("REPLACED", event.getValue());
107         }
108         else
109         {
110             assertNull(event.getValue());
111         }
112     }
113 
114     @Test
115     public void testOnUpdate() throws Exception
116     {
117         CacheLoader<String, String> cacheLoader = mock(CacheLoader.class);
118         when(cacheLoader.load("update")).thenReturn("UPDATE");
119 
120         Cache<String, String> cache = factory.getCache("UPDATE_CACHE", cacheLoader, settingsBuilder().build());
121         CacheEntryListener listener = mock(CacheEntryListener.class);
122         cache.addListener(listener, true);
123 
124         cache.get("update");
125         cache.put("update", "UPDATED");
126 
127         ArgumentCaptor<CacheEntryEvent> captor = ArgumentCaptor.forClass(CacheEntryEvent.class);
128         verify(listener, timeout(1000)).onUpdate(captor.capture());
129 
130         CacheEntryEvent<String, String> event = captor.getValue();
131         assertEquals("update", event.getKey());
132         if (supportsUpdateOldValue())
133         {
134             assertEquals("UPDATE", event.getOldValue());
135         }
136         else
137         {
138             assertNull(event.getOldValue());
139         }
140         if (supportsUpdateValue())
141         {
142             assertEquals("UPDATED", event.getValue());
143         }
144         else
145         {
146             assertNull(event.getValue());
147         }
148     }
149 
150     @Test
151     public void testOnRemove() throws Exception
152     {
153         CacheLoader<String, String> cacheLoader = mock(CacheLoader.class);
154         when(cacheLoader.load("remove")).thenReturn("REMOVE");
155 
156         Cache<String, String> cache = factory.getCache("REMOVE_CACHE", cacheLoader, settingsBuilder().build());
157         CacheEntryListener listener = mock(CacheEntryListener.class);
158         cache.addListener(listener, true);
159 
160         cache.get("remove");
161         cache.remove("remove");
162 
163         ArgumentCaptor<CacheEntryEvent> captor = ArgumentCaptor.forClass(CacheEntryEvent.class);
164         verify(listener, timeout(1000)).onRemove(captor.capture());
165 
166         CacheEntryEvent<String, String> event = captor.getValue();
167         assertEquals("remove", event.getKey());
168         if (supportsRemoveOldValue())
169         {
170             assertEquals("REMOVE", event.getOldValue());
171         }
172         else
173         {
174             assertNull(event.getOldValue());
175         }
176         assertNull(event.getValue());
177     }
178 
179     // This tests that CacheEntryListener methods can call Cache methods in a re-entrant fashion.
180     @Test
181     public void testOnRemoveCanGet() throws Exception
182     {
183         CacheLoader<String, String> cacheLoader = mock(CacheLoader.class);
184         when(cacheLoader.load("remove")).thenReturn("REMOVE");
185         Map<String, String> removedValues = mock(Map.class);
186 
187         Cache<String, String> cache = factory.getCache("REMOVE_CACHE", cacheLoader, settingsBuilder().build());
188         CacheEntryListener listener = new CacheEntryAdapter<String, String>() {
189             @Override
190             public void onRemove(@Nonnull CacheEntryEvent<String, String> event) {
191                 String key = event.getKey();
192                 removedValues.put(key, cache.get(key));
193             }
194         };
195         cache.addListener(listener, true);
196 
197         cache.get("remove");
198         cache.remove("remove");
199 
200         verify(removedValues, timeout(2000)).put(eq("remove"), eq("REMOVE"));
201     }
202 
203     @Test
204     public void testOnEvict() throws Exception
205     {
206         CacheLoader<String, String> cacheLoader = mock(CacheLoader.class);
207         when(cacheLoader.load("evict")).thenReturn("EVICT");
208 
209         Cache<String, String> cache = factory.getCache("EVICT_CACHE", cacheLoader,
210                 settingsBuilder().expireAfterAccess(1, TimeUnit.SECONDS).expireAfterWrite(1, TimeUnit.SECONDS).build());
211         CacheEntryListener<String,String> listener = mock(CacheEntryListener.class);
212         cache.addListener(listener, true);
213 
214         cache.get("evict");
215 
216         Thread.sleep(2000);
217 
218         cache.get("evict");
219 
220         ArgumentCaptor<CacheEntryEvent> captor = ArgumentCaptor.forClass(CacheEntryEvent.class);
221         verify(listener, timeout(2000).atLeastOnce()).onEvict(captor.capture());
222 
223         CacheEntryEvent<String, String> event = captor.getValue();
224         assertEquals("evict", event.getKey());
225         if (supportsEvictOldValue())
226         {
227             assertEquals("EVICT", event.getOldValue());
228         }
229         else
230         {
231             assertNull(event.getOldValue());
232         }
233         assertNull(event.getValue());
234     }
235 
236     protected CacheSettingsBuilder settingsBuilder()
237     {
238         return new CacheSettingsBuilder();
239     }
240 
241     protected boolean supportsAddValue()
242     {
243         return true;
244     }
245 
246     protected boolean supportsPutValue()
247     {
248         return true;
249     }
250 
251     protected boolean supportsUpdateOldValue()
252     {
253         return true;
254     }
255 
256     protected boolean supportsUpdateValue()
257     {
258         return true;
259     }
260 
261     protected boolean supportsRemoveOldValue()
262     {
263         return true;
264     }
265 
266     protected boolean supportsEvictOldValue()
267     {
268         return true;
269     }
270 }