1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.constructs.blocking;
18
19 import net.sf.ehcache.Cache;
20 import net.sf.ehcache.CacheException;
21 import net.sf.ehcache.CacheTest;
22 import net.sf.ehcache.Ehcache;
23 import net.sf.ehcache.Element;
24 import net.sf.ehcache.Status;
25 import net.sf.ehcache.config.CacheConfiguration;
26 import net.sf.ehcache.statistics.LiveCacheStatistics;
27 import org.junit.After;
28 import org.junit.Before;
29 import org.junit.Test;
30
31 import java.io.Serializable;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.concurrent.BrokenBarrierException;
37 import java.util.concurrent.CyclicBarrier;
38
39 import static org.junit.Assert.assertEquals;
40 import static org.junit.Assert.assertNotNull;
41 import static org.junit.Assert.assertNull;
42 import static org.junit.Assert.assertTrue;
43 import static org.junit.Assert.fail;
44
45 /***
46 * Test cases for the {@link BlockingCache}.
47 *
48 * @author Adam Murdoch
49 * @author Greg Luck
50 * @version $Id: BlockingCacheTest.java 2539 2010-07-02 10:58:13Z alexsnaps $
51 */
52 public class BlockingCacheTest extends CacheTest {
53
54 private BlockingCache blockingCache;
55
56 /***
57 * Load up the test cache
58 */
59 @Override
60 @Before
61 public void setUp() throws Exception {
62 super.setUp();
63 Ehcache cache = manager.getCache("sampleIdlingExpiringCache");
64 blockingCache = new BlockingCache(cache);
65 }
66
67 /***
68 * teardown
69 */
70 @Override
71 @After
72 public void tearDown() throws Exception {
73 if (manager.getStatus() == Status.STATUS_ALIVE) {
74 blockingCache.removeAll();
75 }
76 super.tearDown();
77 }
78
79 @Test
80 public void testSupportsStatsCorrectly() {
81 blockingCache.setStatisticsEnabled(true);
82 LiveCacheStatistics statistics = blockingCache.getLiveCacheStatistics();
83 long cacheMisses = statistics.getCacheMissCount();
84 long cacheHits = statistics.getCacheHitCount();
85 String key = "123451234";
86 blockingCache.get(key);
87 assertEquals("Misses stat should have incremented by one", cacheMisses + 1, statistics.getCacheMissCount());
88 assertEquals("Hits stat should have remain the same", cacheHits, statistics.getCacheHitCount());
89 blockingCache.put(new Element(key, "value"));
90 assertEquals("Misses stat should have incremented by one", cacheMisses + 1, statistics.getCacheMissCount());
91 assertEquals("Hits stat should have remain the same", cacheHits, statistics.getCacheHitCount());
92 assertNotNull(blockingCache.get(key));
93 assertEquals("Hits stat should have incremented by one", cacheHits + 1, statistics.getCacheHitCount());
94 blockingCache.setStatisticsEnabled(false);
95 blockingCache.remove(key);
96 }
97
98 /***
99 * Tests adding and looking up an entry.
100 */
101 @Test
102 public void testAddEntry() throws Exception {
103
104 blockingCache.removeAll();
105
106 final String key = "key";
107 final String value = "value";
108 Element element = new Element(key, value);
109
110
111 assertEquals(0, blockingCache.getKeys().size());
112
113
114 blockingCache.put(new Element(key, value));
115
116
117 assertEquals(1, blockingCache.getKeys().size());
118 assertTrue(blockingCache.getKeys().contains(key));
119 final Element returnedElement = blockingCache.get(key);
120 assertEquals(element, returnedElement);
121
122 }
123
124 /***
125 * Tests that getting entries matches a list of known entries
126 */
127 @Test
128 public void testGetEntries() throws Exception {
129 Ehcache cache = blockingCache.getCache();
130 for (int i = 0; i < 100; i++) {
131 cache.put(new Element(Integer.valueOf(i), "value" + i));
132 }
133 List keys = blockingCache.getKeys();
134 List elements = new ArrayList();
135 for (int i = 0; i < keys.size(); i++) {
136 Object key = keys.get(i);
137 elements.add(blockingCache.get(key));
138 }
139 assertEquals(100, elements.size());
140 Map map = new HashMap();
141 for (int i = 0; i < elements.size(); i++) {
142 Element element = (Element)elements.get(i);
143 map.put(element.getObjectKey(), element.getObjectValue());
144 }
145 for (int i = 0; i < 100; i++) {
146 Serializable value = (Serializable)map.get(Integer.valueOf(i));
147 assertEquals("value" + i, value);
148 }
149 }
150
151 /***
152 * Tests looking up a missing entry, then adding it.
153 */
154 @Test
155 public void testAddMissingEntry() throws Exception {
156 Element element = new Element("key", "value");
157
158
159 assertNull(blockingCache.get("key"));
160
161
162 blockingCache.put(element);
163
164
165 assertEquals(1, blockingCache.getKeys().size());
166 assertEquals(element, blockingCache.get("key"));
167
168 }
169
170
171 /***
172 * Does a second tread block until the first thread puts the entry?
173 */
174 @Test
175 public void testSecondThreadActuallyBlocks() throws Exception {
176 Element element = new Element("key", "value");
177 final List threadResults = new ArrayList();
178
179
180 assertNull(blockingCache.get("key"));
181
182 Thread secondThread = new Thread() {
183 @Override
184 public void run() {
185 threadResults.add(blockingCache.get("key"));
186 }
187 };
188 secondThread.start();
189 assertEquals(0, threadResults.size());
190
191
192 blockingCache.put(element);
193 Thread.sleep(30);
194 assertEquals(1, threadResults.size());
195 assertEquals(element, threadResults.get(0));
196
197
198 assertEquals(1, blockingCache.getKeys().size());
199 assertEquals(element, blockingCache.get("key"));
200 }
201
202 /***
203 * Elements with null valuea are not stored in the blocking cache
204 */
205 @Test
206 public void testUnknownEntry() throws Exception {
207
208 assertNull(blockingCache.get("key"));
209
210 blockingCache.put(new Element("key", null));
211 assertEquals(0, blockingCache.getKeys().size());
212 }
213
214 /***
215 * Overwriting an Element with an element with a null value effectively removes it from the cache
216 */
217 @Test
218 public void testRemoveEntry() throws Exception {
219 Element element = new Element("key", "value");
220
221
222 blockingCache.put(element);
223 assertEquals(element, blockingCache.get("key"));
224
225
226 blockingCache.put(new Element("key", null));
227 assertEquals(0, blockingCache.getKeys().size());
228
229 }
230
231 /***
232 * Tests clearing the cache
233 */
234 @Test
235 public void testClear() throws Exception {
236 Ehcache cache = manager.getCache("sampleCacheNotEternalButNoIdleOrExpiry");
237 blockingCache = new BlockingCache(cache);
238
239 blockingCache.put(new Element("key1", "value1"));
240 blockingCache.put(new Element("key2", "value2"));
241 blockingCache.put(new Element("key3", "value2"));
242 assertEquals(3, blockingCache.getKeys().size());
243
244
245 blockingCache.removeAll();
246 assertEquals(0, blockingCache.getKeys().size());
247 }
248
249
250 /***
251 * Creates a blocking test cache
252 */
253 @Override
254 protected Ehcache createTestCache() {
255 Ehcache cache = super.createTestCache();
256 return new BlockingCache(cache);
257 }
258
259 /***
260 * Gets the sample cache 1
261 */
262 @Override
263 protected Ehcache getSampleCache1() {
264 Cache cache = manager.getCache("sampleCache1");
265 manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache));
266 return manager.getEhcache("sampleCache1");
267 }
268
269 /***
270 * Use to manually test super class tests
271 */
272 @Test
273 public void testInstrumented() throws Exception {
274 super.testSizes();
275 }
276
277 @Override
278 @Test
279 public void testGetWithLoader() {
280 super.testGetWithLoader();
281 }
282
283
284 @Override
285 @Test
286 public void testFlushWhenOverflowToDisk() throws Exception {
287 super.testFlushWhenOverflowToDisk();
288 }
289
290 @Override
291 @Test
292 public void testConcurrentPutsAreConsistentRepeatedly() throws InterruptedException {
293
294 }
295
296 @Override
297 @Test
298 public void testConcurrentPutsAreConsistent() throws InterruptedException {
299
300 }
301
302 @Test
303 public void testInlineEviction() throws InterruptedException {
304
305 final Serializable KEY = "DUH";
306 Cache cache = new Cache(new CacheConfiguration("fastExpiry", 1000).timeToIdleSeconds(2).timeToLiveSeconds(2));
307 manager.addCache(cache);
308 manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache));
309
310 Ehcache blockingCache = manager.getEhcache("fastExpiry");
311 blockingCache.put(new Element(KEY, "VALUE"));
312 assertNotNull(blockingCache.get(KEY));
313
314 Thread.sleep(3000);
315 assertNull(blockingCache.get(KEY));
316 }
317
318 @Test
319 public void testTimeout() throws BrokenBarrierException, InterruptedException {
320 final CyclicBarrier barrier = new CyclicBarrier(2);
321 final String KEY = "BLOCKING_KEY";
322 blockingCache.setTimeoutMillis(1000);
323 Thread thread = new Thread(new Runnable() {
324 public void run() {
325 assertNull(blockingCache.get(KEY));
326 try {
327 barrier.await();
328 Thread.sleep(5000);
329 } catch (Exception e) {
330 throw new RuntimeException(e);
331 }
332 blockingCache.put(new Element(KEY, "VALUE"));
333 }
334 });
335 thread.start();
336 barrier.await();
337 try {
338 blockingCache.get(KEY);
339 fail("BlockingCache.get should have not returned!");
340 } catch (CacheException e) {
341
342 }
343 }
344 }
345