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
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 }