1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.fulcrum.cache;
21
22
23 import java.util.ConcurrentModificationException;
24 import java.util.Date;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.avalon.framework.component.ComponentException;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.fulcrum.testcontainer.BaseUnitTest;
32 /***
33 * CacheTest
34 *
35 * @author <a href="paulsp@apache.org">Paul Spencer</a>
36 * @author <a href="epugh@upstate.com">Eric Pugh</a>
37 * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
38 * @version $Id: CacheTest.java 535465 2007-05-05 06:58:06Z tv $
39 */
40 public class CacheTest extends BaseUnitTest
41 {
42
43 private GlobalCacheService globalCache = null;
44 private static final String cacheKey = "CacheKey";
45 private static final String cacheKey_2 = "CacheKey_2";
46 public static final String SKIP_TESTS_KEY = "fulcrum.cache.skip.long.tests";
47 private static final Log LOG = LogFactory.getLog(CacheTest.class);
48
49
50 /***
51 * Defines the testcase name for JUnit.
52 *
53 * @param name the testcase's name.
54 */
55 public CacheTest(String name)
56 {
57 super(name);
58 }
59
60 protected void setUp() throws Exception
61 {
62 super.setUp();
63 try
64 {
65 globalCache = (GlobalCacheService) this.lookup(GlobalCacheService.ROLE);
66 }
67 catch (ComponentException e)
68 {
69 e.printStackTrace();
70 fail(e.getMessage());
71 }
72 }
73 /***
74 * Simple test that verify an object can be created and deleted.
75 * @throws Exception
76 */
77 public void testSimpleAddGetCacheObject() throws Exception
78 {
79 String testString = new String("This is a test");
80 Object retrievedObject = null;
81 CachedObject cacheObject1 = null;
82
83 cacheObject1 = new CachedObject(testString);
84 assertNotNull("Failed to create a cachable object 1", cacheObject1);
85
86 globalCache.addObject(cacheKey, cacheObject1);
87
88 retrievedObject = globalCache.getObject(cacheKey);
89 assertNotNull("Did not retrieved a cached object 1", retrievedObject);
90 assertTrue("Did not retrieved a correct, expected cached object 1", retrievedObject == cacheObject1);
91
92 globalCache.removeObject(cacheKey);
93
94 retrievedObject = null;
95 cacheObject1 = null;
96 try
97 {
98 retrievedObject = globalCache.getObject(cacheKey);
99 assertNull(
100 "Retrieved the deleted cached object 1 and did not get expected ObjectExpiredException",
101 retrievedObject);
102 assertNotNull("Did not get expected ObjectExpiredException retrieving a deleted object", retrievedObject);
103 }
104 catch (ObjectExpiredException e)
105 {
106 assertNull(
107 "Retrieved the deleted cached object 1, but caught expected ObjectExpiredException exception",
108 retrievedObject);
109 }
110 catch (Exception e)
111 {
112 throw e;
113 }
114
115 globalCache.removeObject(cacheKey);
116 }
117 /***
118 * Simple test that adds, retrieves, and deletes 2 object.
119 *
120 * @throws Exception
121 */
122 public void test2ObjectAddGetCachedObject() throws Exception
123 {
124 String testString = new String("This is a test");
125 Object retrievedObject = null;
126 CachedObject cacheObject1 = null;
127 CachedObject cacheObject2 = null;
128
129 cacheObject1 = new CachedObject(testString);
130 assertNotNull("Failed to create a cachable object 1", cacheObject1);
131 globalCache.addObject(cacheKey, cacheObject1);
132 retrievedObject = globalCache.getObject(cacheKey);
133 assertNotNull("Did not retrieved a cached object 1", retrievedObject);
134 assertEquals("Did not retrieved correct cached object", cacheObject1, retrievedObject);
135
136 cacheObject2 = new CachedObject(testString);
137 assertNotNull("Failed to create a cachable object 2", cacheObject2);
138 globalCache.addObject(cacheKey_2, cacheObject2);
139 retrievedObject = globalCache.getObject(cacheKey_2);
140 assertNotNull("Did not retrieved a cached object 2", retrievedObject);
141 assertEquals("Did not retrieved correct cached object 2", cacheObject2, retrievedObject);
142
143 retrievedObject = globalCache.getObject(cacheKey);
144 assertNotNull("Did not retrieved a cached object 1. Attempt #2", retrievedObject);
145 assertEquals("Did not retrieved correct cached object 1. Attempt #2", cacheObject1, retrievedObject);
146
147 retrievedObject = globalCache.getObject(cacheKey);
148 assertNotNull("Did not retrieved a cached object 1. Attempt #3", retrievedObject);
149 assertEquals("Did not retrieved correct cached object 1. Attempt #3", cacheObject1, retrievedObject);
150
151 retrievedObject = globalCache.getObject(cacheKey_2);
152 assertNotNull("Did not retrieved a cached object 2. Attempt #2", retrievedObject);
153 assertEquals("Did not retrieved correct cached object 2 Attempt #2", cacheObject2, retrievedObject);
154
155 globalCache.removeObject(cacheKey);
156 globalCache.removeObject(cacheKey_2);
157 }
158 /***
159 * Verify that an object will throw the ObjectExpiredException
160 * when it now longer exists in cache.
161 *
162 * @throws Exception
163 */
164 public void testObjectExpiration() throws Exception
165 {
166 String testString = new String("This is a test");
167 Object retrievedObject = null;
168 CachedObject cacheObject = null;
169
170 cacheObject = new CachedObject(testString, 1000);
171 assertNotNull("Failed to create a cachable object", cacheObject);
172 long addTime = System.currentTimeMillis();
173 globalCache.addObject(cacheKey, cacheObject);
174
175 try
176 {
177 retrievedObject = null;
178 retrievedObject = globalCache.getObject(cacheKey);
179 assertNotNull("Did not retrieved a cached object", retrievedObject);
180 assertEquals("Did not retrieved correct cached object", cacheObject, retrievedObject);
181 }
182 catch (ObjectExpiredException e)
183 {
184 assertTrue("Object expired early ( " + (System.currentTimeMillis() - addTime) + " millis)", false);
185 }
186 catch (Exception e)
187 {
188 throw e;
189 }
190
191 Thread.sleep(1500);
192
193 try
194 {
195 retrievedObject = null;
196 retrievedObject = globalCache.getObject(cacheKey);
197 assertNull(
198 "Retrieved the expired cached object and did not get expected ObjectExpiredException",
199 retrievedObject);
200 assertNotNull("Did not get expected ObjectExpiredException retrieving an expired object", retrievedObject);
201 }
202 catch (ObjectExpiredException e)
203 {
204 assertNull(
205 "Retrieved the expired cached object, but caught expected ObjectExpiredException exception",
206 retrievedObject);
207 }
208 catch (Exception e)
209 {
210 throw e;
211 }
212
213 globalCache.removeObject(cacheKey);
214 }
215 /***
216 * Verify the all object will be flushed from the cache.
217 *
218 * This test can take server minutes.
219 *
220 * @throws Exception
221 */
222 public void testCacheFlush() throws Exception
223 {
224 String testString = new String("This is a test");
225 CachedObject cacheObject = null;
226
227 cacheObject = new CachedObject(testString, (getCacheRefresh() * 5) + 1);
228 assertNotNull("Failed to create a cachable object", cacheObject);
229 globalCache.addObject(cacheKey, cacheObject);
230
231 Thread.sleep(getCacheRefresh() + 1);
232 assertTrue("No object in cache before flush", (0 < globalCache.getNumberOfObjects()));
233
234 globalCache.flushCache();
235
236 Thread.sleep((getCacheRefresh() * 2) + 1);
237 assertEquals("After refresh", 0, globalCache.getNumberOfObjects());
238
239 globalCache.removeObject(cacheKey);
240 }
241 /***
242 * Verify the Cache count is correct.
243 * @throws Exception
244 */
245 public void testObjectCount() throws Exception
246 {
247 assertNotNull("Could not retrive cache service.", globalCache);
248
249 long expireTime = getCacheRefresh() + getCacheRefresh() / 2;
250 CachedObject cacheObject = new CachedObject("This is a test", expireTime);
251 assertNotNull("Failed to create a cachable object", cacheObject);
252 globalCache.addObject(cacheKey, cacheObject);
253 assertEquals("After adding 1 Object", 1, globalCache.getNumberOfObjects());
254
255 Thread.sleep(getCacheRefresh() + getCacheRefresh() / 3);
256 assertEquals("After one refresh", 1, globalCache.getNumberOfObjects());
257
258 Thread.sleep((getCacheRefresh() * 2) + getCacheRefresh() / 3);
259 assertEquals("After three refreshes", 0, globalCache.getNumberOfObjects());
260 }
261 /***
262 * Verfy a refreshable object will refreshed in the following cases:
263 * o The object is retrieved via getObject an it is stale.
264 * o The object is determied to be stale during a cache
265 * refresh
266 *
267 * This test can take serveral minutes.
268 *
269 * @throws Exception
270 */
271 public void testRefreshableObject() throws Exception
272 {
273 Object retrievedObject = null;
274 RefreshableCachedObject cacheObject = null;
275
276 cacheObject = new RefreshableCachedObject(new RefreshableObject(), getTestExpireTime());
277 assertNotNull("Failed to create a cachable object", cacheObject);
278 long addTime = System.currentTimeMillis();
279 globalCache.addObject(cacheKey, cacheObject);
280
281 try
282 {
283 retrievedObject = null;
284 retrievedObject = globalCache.getObject(cacheKey);
285 assertNotNull("Did not retrieved a cached object", retrievedObject);
286 assertEquals("Did not retrieved correct cached object", cacheObject, retrievedObject);
287 }
288 catch (ObjectExpiredException e)
289 {
290 assertTrue("Object expired early ( " + (System.currentTimeMillis() - addTime) + " millis)", false);
291 }
292 catch (Exception e)
293 {
294 throw e;
295 }
296
297 Thread.sleep(getTestExpireTime() + 1000);
298
299 try
300 {
301 retrievedObject = null;
302 retrievedObject = globalCache.getObject(cacheKey);
303 assertNotNull("Did not retrieved a cached object, after sleep", retrievedObject);
304 assertNotNull(
305 "Cached object has no contents, after sleep.",
306 ((RefreshableCachedObject) retrievedObject).getContents());
307 assertTrue(
308 "Object did not refresh.",
309 (((RefreshableObject) ((RefreshableCachedObject) retrievedObject).getContents()).getRefreshCount()
310 > 0));
311 }
312 catch (ObjectExpiredException e)
313 {
314 assertTrue(
315 "Received unexpected ObjectExpiredException exception "
316 + "when retrieving refreshable object after ( "
317 + (System.currentTimeMillis() - addTime)
318 + " millis)",
319 false);
320 }
321 catch (Exception e)
322 {
323 throw e;
324 }
325
326 for (int i = 0; i < 100; i++)
327 {
328 Thread.sleep(1000);
329
330 try
331 {
332 retrievedObject = null;
333 retrievedObject = globalCache.getObject(cacheKey);
334 assertNotNull("Did not retrieved a cached object, after sleep", retrievedObject);
335 assertNotNull(
336 "Cached object has no contents, after sleep.",
337 ((RefreshableCachedObject) retrievedObject).getContents());
338 assertTrue(
339 "Object did not refresh.",
340 (((RefreshableObject) ((RefreshableCachedObject) retrievedObject).getContents()).getRefreshCount()
341 > 0));
342 }
343 catch (ObjectExpiredException e)
344 {
345 assertTrue(
346 "Received unexpected ObjectExpiredException exception "
347 + "when retrieving refreshable object after ( "
348 + (System.currentTimeMillis() - addTime)
349 + " millis)",
350 false);
351 }
352 catch (Exception e)
353 {
354 throw e;
355 }
356 }
357
358 globalCache.removeObject(cacheKey);
359 }
360 /***
361 * Verify a cached object will be delete after it has been
362 * untouched beyond it's TimeToLive.
363 *
364 * This test can take serveral minutes.
365 *
366 * @throws Exception
367 */
368 public void testRefreshableTimeToLive() throws Exception
369 {
370 String skipTestsProperty = System.getProperty(SKIP_TESTS_KEY,"false");
371 LOG.info("What is the value of the skipTestsProperty:" + skipTestsProperty);
372 if(Boolean.valueOf(skipTestsProperty).booleanValue()){
373 LOG.warn("Skipping testRefreshableTimeToLive test due to property " + SKIP_TESTS_KEY + " being true.");
374 return;
375 }
376 else {
377 LOG.warn("Running testRefreshableTimeToLive test due to property " + SKIP_TESTS_KEY + " being false.");
378 }
379
380 Object retrievedObject = null;
381 RefreshableCachedObject cacheObject = null;
382
383 cacheObject = new RefreshableCachedObject(new RefreshableObject(), getTestExpireTime());
384 assertNotNull("Failed to create a cachable object", cacheObject);
385 cacheObject.setTTL(getTestExpireTime());
386
387 assertEquals("Returned TimeToLive", getTestExpireTime(), cacheObject.getTTL());
388
389 long addTime = System.currentTimeMillis();
390 globalCache.addObject(cacheKey, cacheObject);
391
392 try
393 {
394 retrievedObject = null;
395 retrievedObject = globalCache.getObject(cacheKey);
396 assertNotNull("Did not retrieved a cached object", retrievedObject);
397 assertEquals("Did not retrieved correct cached object", cacheObject, retrievedObject);
398 }
399 catch (ObjectExpiredException e)
400 {
401 fail("Object expired early ( " + (System.currentTimeMillis() - addTime) + " millis)");
402 }
403 catch (Exception e)
404 {
405 throw e;
406 }
407
408 long timeout = getTestExpireTime() - 0000;
409 Thread.sleep(timeout);
410
411 try
412 {
413 retrievedObject = null;
414 retrievedObject = globalCache.getObject(cacheKey);
415 assertNotNull("Did not retrieve a cached object, after sleep", retrievedObject);
416 assertNotNull(
417 "Cached object has no contents, after sleep.",
418 ((RefreshableCachedObject) retrievedObject).getContents());
419
420
421
422
423
424
425
426
427 }
428 catch (ObjectExpiredException e)
429 {
430 assertTrue(
431 "Received unexpected ObjectExpiredException exception "
432 + "when retrieving refreshable object after ( "
433 + (System.currentTimeMillis() - addTime)
434 + " millis)",
435 false);
436 }
437 catch (Exception e)
438 {
439 throw e;
440 }
441
442 Thread.sleep(getTestExpireTime() + 5000);
443
444 try
445 {
446 retrievedObject = null;
447 retrievedObject = globalCache.getObject(cacheKey);
448 assertNull("Retrieved a cached object, after exceeding TimeToLive", retrievedObject);
449 }
450 catch (ObjectExpiredException e)
451 {
452 assertNull(
453 "Retrieved the expired cached object, but caught expected ObjectExpiredException exception",
454 retrievedObject);
455 }
456 catch (Exception e)
457 {
458 throw e;
459 }
460 }
461 /***
462 * Test that we can get a list of the keys in the cache
463 *
464 * @return
465 */
466 public void testCacheGetKeyList() {
467 globalCache.flushCache();
468 globalCache.addObject("date1", new CachedObject(new Date()));
469 globalCache.addObject("date2", new CachedObject(new Date()));
470 globalCache.addObject("date3", new CachedObject(new Date()));
471 assertTrue("Did not get key list back.", (globalCache.getKeys() != null));
472 List keys = globalCache.getKeys();
473 for (Iterator itr = keys.iterator(); itr.hasNext();) {
474 Object key = itr.next();
475 assertTrue("Key was not an instance of String.", (key instanceof String));
476 }
477
478 }
479
480 /***
481 * Test that we can get a list of the keys in the cache
482 *
483 * @return
484 */
485 public void testCacheGetCachedObjects() {
486 globalCache.flushCache();
487 globalCache.addObject("date1", new CachedObject(new Date()));
488 globalCache.addObject("date2", new CachedObject(new Date()));
489 globalCache.addObject("date3", new CachedObject(new Date()));
490 assertTrue("Did not get object list back.", (globalCache.getCachedObjects() != null));
491 List objects = globalCache.getCachedObjects();
492 for (Iterator itr = objects.iterator(); itr.hasNext();) {
493 Object obj = itr.next();
494 assertNotNull("Object was null.", obj);
495 assertTrue("Object was not an instance of CachedObject", (obj instanceof CachedObject));
496 }
497
498 }
499
500 /***
501 * Test that the retrieved list is safe from
502 * ConcurrentModificationException's being thrown if the cache
503 * is updated while we are iterating over the List.
504 *
505 * @return
506 */
507 public void testCacheModification() {
508 globalCache.flushCache();
509 globalCache.addObject("date1", new CachedObject(new Date()));
510 globalCache.addObject("date2", new CachedObject(new Date()));
511 globalCache.addObject("date3", new CachedObject(new Date()));
512 assertTrue("Did not get key list back.", (globalCache.getKeys() != null));
513 List keys = globalCache.getKeys();
514 try {
515 for (Iterator itr = keys.iterator(); itr.hasNext();) {
516 Object key = itr.next();
517 globalCache.addObject("date4", new CachedObject(new Date()));
518 }
519 } catch (ConcurrentModificationException cme)
520 {
521 fail("Caught ConcurrentModificationException adding to cache.");
522 }
523 List objects = globalCache.getCachedObjects();
524 try {
525 for (Iterator itr = objects.iterator(); itr.hasNext();) {
526 Object obj = itr.next();
527 globalCache.addObject("date4", new CachedObject(new Date()));
528 }
529 } catch (ConcurrentModificationException cme)
530 {
531 fail("Caught ConcurrentModificationException adding to cache.");
532 }
533 }
534
535
536 /***
537 * Down cast the interface to the concreate object in order to grab the
538 * cache check frequency.
539 * @return the refresh requency in milliseconds
540 */
541 private long getCacheRefresh()
542 {
543 return ((DefaultGlobalCacheService) globalCache).getCacheCheckFrequency()*1000;
544 }
545
546 /***
547 * How long until it expires
548 * @return the cache refresh plus 1000.
549 */
550 private long getTestExpireTime()
551 {
552 return getCacheRefresh() + 1000;
553 }
554
555
556 private long getTestTimeToLive()
557 {
558 return getTestExpireTime()*5;
559 }
560 /***
561 * Simple object that can be refreshed
562 */
563 class RefreshableObject implements Refreshable
564 {
565 private int refreshCount = 0;
566 /***
567 * Increment the refresh counter
568 */
569 public void refresh()
570 {
571 this.refreshCount++;
572 }
573 /***
574 * Reutrn the number of time this object has been refreshed
575 *
576 * @return Number of times refresh() has been called
577 */
578 public int getRefreshCount()
579 {
580 return this.refreshCount;
581 }
582 }
583 }