View Javadoc

1   /**
2    *  Copyright 2003-2006 Greg Luck
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;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  import java.io.Serializable;
23  import java.lang.ref.SoftReference;
24  import java.util.Date;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  
30  /**
31   * Tests for a Cache
32   *
33   * @author Greg Luck, Claus Ibsen
34   * @version $Id: CacheTest.java 141 2006-06-30 01:56:32Z gregluck $
35   */
36  public class CacheTest extends AbstractCacheTest {
37      private static final Log LOG = LogFactory.getLog(CacheTest.class.getName());
38  
39  
40      /**
41       * teardown
42       */
43      protected void tearDown() throws Exception {
44          super.tearDown();
45      }
46  
47      /**
48       * Checks we cannot use a cache after shutdown
49       */
50      public void testUseCacheAfterManagerShutdown() throws CacheException {
51          Cache cache = manager.getCache("sampleCache1");
52          manager.shutdown();
53          Element element = new Element("key", "value");
54          try {
55              cache.getSize();
56              fail();
57          } catch (IllegalStateException e) {
58              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
59          }
60          try {
61              cache.put(element);
62              fail();
63          } catch (IllegalStateException e) {
64              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
65          }
66          try {
67              cache.get("key");
68              fail();
69          } catch (IllegalStateException e) {
70              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
71          }
72          try {
73              cache.getHitCount();
74              fail();
75          } catch (IllegalStateException e) {
76              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
77          }
78          try {
79              cache.getMemoryStoreHitCount();
80              fail();
81          } catch (IllegalStateException e) {
82              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
83          }
84          try {
85              cache.getDiskStoreHitCount();
86              fail();
87          } catch (IllegalStateException e) {
88              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
89          }
90          try {
91              cache.getMissCountExpired();
92              fail();
93          } catch (IllegalStateException e) {
94              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
95          }
96          try {
97              cache.getMissCountNotFound();
98              fail();
99          } catch (IllegalStateException e) {
100             assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
101         }
102     }
103 
104     /**
105      * Checks we cannot use a cache outside the manager
106      */
107     public void testUseCacheOutsideManager() throws CacheException {
108         //Not put into manager.
109         Cache cache = new Cache("testCache", 1, true, false, 5, 2);
110         Element element = new Element("key", "value");
111         try {
112             cache.getSize();
113             fail();
114         } catch (IllegalStateException e) {
115             assertEquals("The testCache Cache is not alive.", e.getMessage());
116         }
117         try {
118             cache.put(element);
119             fail();
120         } catch (IllegalStateException e) {
121             assertEquals("The testCache Cache is not alive.", e.getMessage());
122         }
123         try {
124             cache.get("key");
125             fail();
126         } catch (IllegalStateException e) {
127             assertEquals("The testCache Cache is not alive.", e.getMessage());
128         }
129         try {
130             cache.getHitCount();
131             fail();
132         } catch (IllegalStateException e) {
133             assertEquals("The testCache Cache is not alive.", e.getMessage());
134         }
135         try {
136             cache.getMemoryStoreHitCount();
137             fail();
138         } catch (IllegalStateException e) {
139             assertEquals("The testCache Cache is not alive.", e.getMessage());
140         }
141         try {
142             cache.getDiskStoreHitCount();
143             fail();
144         } catch (IllegalStateException e) {
145             assertEquals("The testCache Cache is not alive.", e.getMessage());
146         }
147         try {
148             cache.getMissCountExpired();
149             fail();
150         } catch (IllegalStateException e) {
151             assertEquals("The testCache Cache is not alive.", e.getMessage());
152         }
153         try {
154             cache.getMissCountNotFound();
155             fail();
156         } catch (IllegalStateException e) {
157             assertEquals("The testCache Cache is not alive.", e.getMessage());
158         }
159     }
160 
161 
162     /**
163      * Test using a cache which has been removed and replaced.
164      */
165     public void testStaleCacheReference() throws CacheException {
166         manager.addCache("test");
167         Cache cache = manager.getCache("test");
168         assertNotNull(cache);
169         cache.put(new Element("key1", "value1"));
170 
171         assertEquals("value1", cache.get("key1").getObjectValue());
172         manager.removeCache("test");
173         manager.addCache("test");
174 
175         try {
176             cache.get("key1");
177             fail();
178         } catch (IllegalStateException e) {
179             assertEquals("The test Cache is not alive.", e.getMessage());
180         }
181     }
182 
183     /**
184      * Tests getting the cache name
185      *
186      * @throws Exception
187      */
188     public void testCacheName() throws Exception {
189         manager.addCache("test");
190         Cache cache = manager.getCache("test");
191         assertEquals("test", cache.getName());
192         assertEquals(Status.STATUS_ALIVE, cache.getStatus());
193     }
194 
195 
196 
197     /**
198      * Tests getting the cache name
199      *
200      * @throws Exception
201      */
202     public void testCacheWithNoIdle() throws Exception {
203         Cache cache = manager.getCache("sampleCacheNoIdle");
204         assertEquals("sampleCacheNoIdle", cache.getName());
205         assertEquals(Status.STATUS_ALIVE, cache.getStatus());
206         assertEquals(0, cache.getTimeToIdleSeconds());
207     }
208 
209     /**
210      * Test expiry based on time to live
211      * <cache name="sampleCacheNoIdle"
212      * maxElementsInMemory="1000"
213      * eternal="false"
214      * timeToLiveSeconds="5"
215      * overflowToDisk="false"
216      * />
217      */
218     public void testExpiryBasedOnTimeToLiveWhenNoIdle() throws Exception {
219         //Set size so the second element overflows to disk.
220         Cache cache = manager.getCache("sampleCacheNoIdle");
221         cache.put(new Element("key1", "value1"));
222         cache.put(new Element("key2", "value1"));
223         assertNotNull(cache.get("key1"));
224         assertNotNull(cache.get("key2"));
225 
226         //Test time to idle. Should not idle out because not specified
227         Thread.sleep(2000);
228         assertNotNull(cache.get("key1"));
229         assertNotNull(cache.get("key2"));
230 
231         //Test time to live.
232         Thread.sleep(5001);
233         assertNull(cache.get("key1"));
234         assertNull(cache.get("key2"));
235     }
236 
237 
238     /**
239      * Test expiry based on time to live. Even though eternal is false, because there are no
240      * expiry or idle times, it is eternal.
241      * <cache name="sampleCacheNotEternalButNoIdleOrExpiry"
242      * maxElementsInMemory="1000"
243      * eternal="false"
244      * overflowToDisk="false"
245      * />
246      */
247     public void testExpirySampleCacheNotEternalButNoIdleOrExpiry() throws Exception {
248         //Set size so the second element overflows to disk.
249         Cache cache = manager.getCache("sampleCacheNotEternalButNoIdleOrExpiry");
250         cache.put(new Element("key1", "value1"));
251         cache.put(new Element("key2", "value1"));
252         assertNotNull(cache.get("key1"));
253         assertNotNull(cache.get("key2"));
254 
255         //Test time to idle. Should not idle out because not specified
256         Thread.sleep(2000);
257         assertNotNull(cache.get("key1"));
258         assertNotNull(cache.get("key2"));
259 
260         //Test time to live.
261         Thread.sleep(5001);
262         assertNotNull(cache.get("key1"));
263         assertNotNull(cache.get("key2"));
264     }
265 
266 
267     /**
268      * Test overflow to disk = false
269      */
270     public void testNoOverflowToDisk() throws Exception {
271         //Set size so the second element overflows to disk.
272         Cache cache = new Cache("test", 1, false, true, 5, 2);
273         manager.addCache(cache);
274         cache.put(new Element("key1", "value1"));
275         cache.put(new Element("key2", "value1"));
276         assertNull(cache.get("key1"));
277         assertNotNull(cache.get("key2"));
278     }
279 
280 
281     /**
282      * Performance tests for a range of Memory Store - Disk Store combinations.
283      * <p/>
284      * This demonstrates that a memory only store is approximately an order of magnitude
285      * faster than a disk only store.
286      * <p/>
287      * It also shows that double the performance of a Disk Only store can be obtained
288      * with a maximum memory size of only 1. Accordingly a Cache created without a
289      * maximum memory size of less than 1 will issue a warning.
290      * <p/>
291      * Threading changes were made in v1.41 of DiskStore. The before and after numbers are shown.
292      */
293     public void testProportionMemoryAndDiskPerformance() throws Exception {
294         StopWatch stopWatch = new StopWatch();
295         long time = 0;
296 
297         //Memory only Typical 192ms
298         Cache memoryOnlyCache = new Cache("testMemoryOnly", 5000, false, false, 5, 2);
299         manager.addCache(memoryOnlyCache);
300         time = stopWatch.getElapsedTime();
301         for (int i = 0; i < 5000; i++) {
302             Integer key = new Integer(i);
303             memoryOnlyCache.put(new Element(new Integer(i), "value"));
304             memoryOnlyCache.get(key);
305         }
306         time = stopWatch.getElapsedTime();
307         LOG.info("Time for MemoryStore: " + time);
308         assertTrue("Time to put and get 5000 entries into MemoryStore", time < 300);
309 
310         //Set size so that all elements overflow to disk.
311         // 1245 ms v1.38 DiskStore
312         // 273 ms v1.42 DiskStore
313         Cache diskOnlyCache = new Cache("testDiskOnly", 0, true, false, 5, 2);
314         manager.addCache(diskOnlyCache);
315         time = stopWatch.getElapsedTime();
316         for (int i = 0; i < 5000; i++) {
317             Integer key = new Integer(i);
318             diskOnlyCache.put(new Element(key, "value"));
319             diskOnlyCache.get(key);
320         }
321         time = stopWatch.getElapsedTime();
322         LOG.info("Time for DiskStore: " + time);
323         assertTrue("Time to put and get 5000 entries into DiskStore was less than 2 sec", time < 2000);
324 
325         // 1 Memory, 999 Disk
326         // 591 ms v1.38 DiskStore
327         // 56 ms v1.42 DiskStore
328         Cache m1d999Cache = new Cache("m1d999Cache", 1, true, false, 5, 2);
329         manager.addCache(m1d999Cache);
330         time = stopWatch.getElapsedTime();
331         for (int i = 0; i < 5000; i++) {
332             Integer key = new Integer(i);
333             m1d999Cache.put(new Element(key, "value"));
334             m1d999Cache.get(key);
335         }
336         time = stopWatch.getElapsedTime();
337         LOG.info("Time for m1d999Cache: " + time);
338         assertTrue("Time to put and get 5000 entries into m1d999Cache", time < 2000);
339 
340         // 500 Memory, 500 Disk
341         // 669 ms v1.38 DiskStore
342         // 47 ms v1.42 DiskStore
343         Cache m500d500Cache = new Cache("m500d500Cache", 500, true, false, 5, 2);
344         manager.addCache(m500d500Cache);
345         time = stopWatch.getElapsedTime();
346         for (int i = 0; i < 5000; i++) {
347             Integer key = new Integer(i);
348             m500d500Cache.put(new Element(key, "value"));
349             m500d500Cache.get(key);
350         }
351         time = stopWatch.getElapsedTime();
352         LOG.info("Time for m500d500Cache: " + time);
353         assertTrue("Time to put and get 5000 entries into m500d500Cache", time < 2000);
354 
355     }
356 
357     /**
358      * Test Caches with persistent stores dispose properly. Tests:
359      * <ol>
360      * <li>No exceptions are thrown on dispose
361      * <li>You cannot re add a cache after it has been disposed and removed
362      * <li>You can create a new cache with the same name
363      * </ol>
364      */
365     public void testCreateAddDisposeAdd() throws CacheException {
366         Cache cache = new Cache("test2", 1, true, true, 0, 0, true, 120);
367         manager.addCache(cache);
368         cache.put(new Element("key1", "value1"));
369         cache.put(new Element("key2", "value1"));
370         int sizeFromGetSize = cache.getSize();
371         int sizeFromKeys = cache.getKeys().size();
372         assertEquals(sizeFromGetSize, sizeFromKeys);
373         assertEquals(2, cache.getSize());
374         //package protected method, only available to tests. Called by teardown
375         cache.dispose();
376         manager.removeCache("test2");
377 
378 
379         try {
380             manager.addCache(cache);
381             fail();
382         } catch (IllegalStateException e) {
383             //expected
384         }
385 
386         //Add a new cache with the same name as the disposed one.
387         Cache cache2 = new Cache("test2", 1, true, true, 0, 0, true, 120);
388         manager.addCache(cache2);
389         Cache cacheFromManager = manager.getCache("test2");
390         assertTrue(cacheFromManager.getStatus().equals(Status.STATUS_ALIVE));
391 
392     }
393 
394     /**
395      * Test expiry based on time to live
396      */
397     public void testExpiryBasedOnTimeToLive() throws Exception {
398         //Set size so the second element overflows to disk.
399         Cache cache = new Cache("test", 1, true, false, 5, 2);
400         manager.addCache(cache);
401         cache.put(new Element("key1", "value1"));
402         cache.put(new Element("key2", "value1"));
403 
404         //Test time to live
405         assertNotNull(cache.get("key1"));
406         assertNotNull(cache.get("key2"));
407         Thread.sleep(5010);
408         assertNull(cache.get("key1"));
409         assertNull(cache.get("key2"));
410     }
411 
412 
413     /**
414      * Tests that a cache created from defaults will expire as per
415      * the default expiry policy.
416      *
417      * @throws Exception
418      */
419     public void testExpiryBasedOnTimeToLiveForDefault() throws Exception {
420         String name = "ThisIsACacheWhichIsNotConfiguredAndWillThereforeUseDefaults";
421         Cache cache = null;
422         CacheManager manager = CacheManager.getInstance();
423         cache = manager.getCache(name);
424         if (cache == null) {
425             LOG.warn("Could not find configuration for " + name
426                     + ". Configuring using the defaultCache settings.");
427             manager.addCache(name);
428             cache = manager.getCache(name);
429         }
430 
431         cache.put(new Element("key1", "value1"));
432         cache.put(new Element("key2", "value1"));
433 
434         //Test time to live
435         assertNotNull(cache.get("key1"));
436         assertNotNull(cache.get("key2"));
437         Thread.sleep(10010);
438         assertNull(cache.get("key1"));
439         assertNull(cache.get("key2"));
440 
441 
442     }
443 
444 
445     /**
446      * Test expiry based on time to live.
447      * <p/>
448      * Elements are put quietly back into the cache after being cloned.
449      * The elements should expire as if the putQuiet had not happened.
450      */
451     public void testExpiryBasedOnTimeToLiveAfterPutQuiet() throws Exception {
452         //Set size so the second element overflows to disk.
453         Cache cache = new Cache("test", 1, true, false, 5, 2);
454         manager.addCache(cache);
455         cache.put(new Element("key1", "value1"));
456         cache.put(new Element("key2", "value1"));
457 
458         Element element1 = cache.get("key1");
459         Element element2 = cache.get("key2");
460         assertNotNull(element1);
461         assertNotNull(element2);
462 
463         //Test time to live
464         Thread.sleep(2010);
465         //Should not affect age
466         cache.putQuiet((Element) element2.clone());
467         cache.putQuiet((Element) element2.clone());
468         Thread.sleep(3010);
469         assertNull(cache.get("key1"));
470         assertNull(cache.get("key2"));
471     }
472 
473     /**
474      * Test expiry based on time to live
475      */
476     public void testNoIdleOrExpiryBasedOnTimeToLiveForEternal() throws Exception {
477         //Set size so the second element overflows to disk.
478         Cache cache = new Cache("test", 1, true, true, 5, 2);
479         manager.addCache(cache);
480         cache.put(new Element("key1", "value1"));
481         cache.put(new Element("key2", "value1"));
482 
483         //Test time to live
484         assertNotNull(cache.get("key1"));
485         assertNotNull(cache.get("key2"));
486 
487         //Check that we did not idle out
488         Thread.sleep(2010);
489         assertNotNull(cache.get("key1"));
490         assertNotNull(cache.get("key2"));
491 
492         //Check that we did not expire out
493         Thread.sleep(3010);
494         assertNotNull(cache.get("key1"));
495         assertNotNull(cache.get("key2"));
496     }
497 
498     /**
499      * Test expiry based on time to idle.
500      */
501     public void testExpiryBasedOnTimeToIdle() throws Exception {
502         //Set size so the second element overflows to disk.
503         Cache cache = new Cache("test", 1, true, false, 5, 2);
504         manager.addCache(cache);
505         cache.put(new Element("key1", "value1"));
506         cache.put(new Element("key2", "value1"));
507 
508         //Test time to idle
509         Element element1 = cache.get("key1");
510         Element element2 = cache.get("key2");
511         assertNotNull(element1);
512         assertNotNull(element2);
513         Thread.sleep(2010);
514         assertNull(cache.get("key1"));
515         assertNull(cache.get("key2"));
516     }
517 
518 
519     /**
520      * Test expiry based on time to idle.
521      */
522     public void testExpiryBasedOnTimeToIdleAfterPutQuiet() throws Exception {
523         //Set size so the second element overflows to disk.
524         Cache cache = new Cache("test", 1, true, false, 5, 3);
525         manager.addCache(cache);
526         cache.put(new Element("key1", "value1"));
527         cache.put(new Element("key2", "value1"));
528 
529         //Test time to idle
530         Element element1 = cache.get("key1");
531         Element element2 = cache.get("key2");
532         assertNotNull(element1);
533         assertNotNull(element2);
534 
535         //Now, getQuiet and check still times out 2 seconds after last get
536         Thread.sleep(1010);
537         element1 = cache.getQuiet("key1");
538         element2 = cache.getQuiet("key2");
539         Thread.sleep(2010);
540         assertNull(cache.getQuiet("key1"));
541         assertNull(cache.getQuiet("key2"));
542 
543         //Now put back in with putQuiet. Should be immediately expired
544         cache.putQuiet((Element) element1.clone());
545         cache.putQuiet((Element) element2.clone());
546         assertNull(cache.get("key1"));
547         element2 = cache.get("key2");
548         assertNull(element2);
549     }
550 
551     /**
552      * Test statistics
553      */
554     public void testStatistics() throws Exception {
555         //Set size so the second element overflows to disk.
556         Cache cache = new Cache("test", 1, true, false, 5, 2);
557         manager.addCache(cache);
558         cache.put(new Element("key1", "value1"));
559         cache.put(new Element("key2", "value1"));
560 
561         //key1 should be in the Disk Store
562         cache.get("key1");
563         assertEquals(1, cache.getHitCount());
564         assertEquals(1, cache.getDiskStoreHitCount());
565         assertEquals(0, cache.getMemoryStoreHitCount());
566         assertEquals(0, cache.getMissCountExpired());
567         assertEquals(0, cache.getMissCountNotFound());
568 
569         //key 1 should now be in the LruMemoryStore
570         cache.get("key1");
571         assertEquals(2, cache.getHitCount());
572         assertEquals(1, cache.getDiskStoreHitCount());
573         assertEquals(1, cache.getMemoryStoreHitCount());
574         assertEquals(0, cache.getMissCountExpired());
575         assertEquals(0, cache.getMissCountNotFound());
576 
577         //Let the idle expire
578         Thread.sleep(5010);
579 
580         //key 1 should now be expired
581         cache.get("key1");
582         assertEquals(2, cache.getHitCount());
583         assertEquals(1, cache.getDiskStoreHitCount());
584         assertEquals(1, cache.getMemoryStoreHitCount());
585         assertEquals(1, cache.getMissCountExpired());
586         assertEquals(1, cache.getMissCountNotFound());
587     }
588 
589     /**
590      * Test element statistics, including get and getQuiet
591      * eternal="false"
592      * timeToIdleSeconds="5"
593      * timeToLiveSeconds="10"
594      * overflowToDisk="true"
595      */
596     public void testElementStatistics() throws Exception {
597         //Set size so the second element overflows to disk.
598         Cache cache = new Cache("test", 1, true, false, 5, 2);
599         manager.addCache(cache);
600         cache.put(new Element("key1", "value1"));
601         cache.put(new Element("key2", "value1"));
602 
603         Element element1 = cache.get("key1");
604         assertEquals("Should be one", 1, element1.getHitCount());
605         element1 = cache.getQuiet("key1");
606         assertEquals("Should be one", 1, element1.getHitCount());
607         element1 = cache.get("key1");
608         assertEquals("Should be two", 2, element1.getHitCount());
609     }
610 
611     /**
612      * Checks that getQuiet works how we expect it to
613      *
614      * @throws Exception
615      */
616     public void testGetQuietAndPutQuiet() throws Exception {
617         //Set size so the second element overflows to disk.
618         Cache cache = new Cache("test", 1, true, false, 5, 2);
619         manager.addCache(cache);
620         cache.put(new Element("key1", "value1"));
621         cache.put(new Element("key2", "value1"));
622 
623         Element element1 = cache.get("key1");
624         long lastAccessedElement1 = element1.getLastAccessTime();
625         long hitCountElement1 = element1.getHitCount();
626         assertEquals("Should be two", 1, element1.getHitCount());
627 
628         element1 = cache.getQuiet("key1");
629         element1 = cache.getQuiet("key1");
630         Element clonedElement1 = (Element) element1.clone();
631         cache.putQuiet(clonedElement1);
632         element1 = cache.getQuiet("key1");
633         assertEquals("last access time should be unchanged",
634                 lastAccessedElement1, element1.getLastAccessTime());
635         assertEquals("hit count should be unchanged",
636                 hitCountElement1, element1.getHitCount());
637         element1 = cache.get("key1");
638         assertEquals("Should be two", 2, element1.getHitCount());
639     }
640 
641     /**
642      * Test size with put and remove.
643      * <p/>
644      * It checks that size makes sense, and also that getKeys.size() matches getSize()
645      */
646     public void testSizeWithPutAndRemove() throws Exception {
647         //Set size so the second element overflows to disk.
648         Cache cache = new Cache("test2", 1, true, true, 0, 0);
649         manager.addCache(cache);
650         cache.put(new Element("key1", "value1"));
651         cache.put(new Element("key2", "value1"));
652         int sizeFromGetSize = cache.getSize();
653         int sizeFromKeys = cache.getKeys().size();
654         assertEquals(sizeFromGetSize, sizeFromKeys);
655         assertEquals(2, cache.getSize());
656         cache.put(new Element("key1", "value1"));
657         cache.put(new Element("key1", "value1"));
658 
659         //key1 should be in the Disk Store
660         assertEquals(cache.getSize(), cache.getKeys().size());
661         assertEquals(2, cache.getSize());
662         //there were two of these, so size will now be one
663         cache.remove("key1");
664         assertEquals(cache.getSize(), cache.getKeys().size());
665         assertEquals(1, cache.getSize());
666         cache.remove("key2");
667         assertEquals(cache.getSize(), cache.getKeys().size());
668         assertEquals(0, cache.getSize());
669 
670         //try null values
671         cache.put(new Element("nullValue1", null));
672         cache.put(new Element("nullValue2", null));
673         //Cannot overflow therefore just one
674         assertEquals(1, cache.getSize());
675         Element nullValueElement = cache.get("nullValue2");
676         assertNull(nullValueElement.getValue());
677         assertNull(nullValueElement.getObjectValue());
678 
679     }
680 
681     /**
682      * Test getKeys after expiry
683      * <p/>
684      * Makes sure that if an element is expired, its key should also be expired
685      */
686     public void testGetKeysAfterExpiry() throws Exception {
687         //Set size so the second element overflows to disk.
688         Cache cache = new Cache("test2", 1, true, false, 1, 0);
689         manager.addCache(cache);
690         cache.put(new Element("key1", "value1"));
691         cache.put(new Element("key2", "value1"));
692         //getSize uses getKeys().size(), so these should be the same
693         assertEquals(cache.getSize(), cache.getKeys().size());
694         //getKeys does not do an expiry check, so the expired elements are counted
695         assertEquals(2, cache.getSize());
696         Thread.sleep(1010);
697         assertEquals(2, cache.getKeys().size());
698         //getKeysWithExpiryCheck does check and gives the correct answer of 0
699         assertEquals(0, cache.getKeysWithExpiryCheck().size());
700     }
701 
702     /**
703      * Test size after multiple calls, with put and remove
704      */
705     public void testSizeMultipleCallsWithPutAndRemove() throws Exception {
706         //Set size so the second element overflows to disk.
707         Cache cache = new Cache("test3", 1, true, true, 0, 0);
708         manager.addCache(cache);
709         cache.put(new Element("key1", "value1"));
710         cache.put(new Element("key2", "value1"));
711 
712         //key1 should be in the Disk Store
713         assertEquals(2, cache.getSize());
714         assertEquals(2, cache.getSize());
715         assertEquals(2, cache.getSize());
716         assertEquals(2, cache.getSize());
717         assertEquals(2, cache.getSize());
718         cache.remove("key1");
719         assertEquals(1, cache.getSize());
720         assertEquals(1, cache.getSize());
721         assertEquals(1, cache.getSize());
722         assertEquals(1, cache.getSize());
723         assertEquals(1, cache.getSize());
724         cache.remove("key2");
725         assertEquals(0, cache.getSize());
726         assertEquals(0, cache.getSize());
727         assertEquals(0, cache.getSize());
728         assertEquals(0, cache.getSize());
729         assertEquals(0, cache.getSize());
730     }
731 
732     /**
733      * Checks the expense of checking for duplicates
734      * Typical Results Duplicate Check: 8ms versus 3ms for No Duplicate Check
735      * <p/>
736      * 66ms for 1000, 6ms for no duplicate/expiry
737      * 187565 for 100000, where 500 is the in-memory size. 964ms without checking expiry. 134ms for getKeysNoDuplicateCheckTime
738      * 18795 for 100000, where 50000 is in-memory size. 873ms without checking expiry. 158ms for getKeysNoDuplicateCheckTime
739      */
740     public void testGetKeysPerformance() throws Exception {
741         //Set size so the second element overflows to disk.
742         Cache cache = new Cache("test4", 1000, true, true, 0, 0);
743         manager.addCache(cache);
744 
745         for (int i = 0; i < 2000; i++) {
746             cache.put(new Element("key" + i, "value"));
747         }
748         //let the notifiers cool down
749         Thread.sleep(1000);
750         StopWatch stopWatch = new StopWatch();
751         List keys = cache.getKeys();
752         assertTrue("Should be 2000 keys. ", keys.size() == 2000);
753         long getKeysTime = stopWatch.getElapsedTime();
754         cache.getKeysNoDuplicateCheck();
755         long getKeysNoDuplicateCheckTime = stopWatch.getElapsedTime();
756         LOG.info("Time to get 1000 keys: With Duplicate Check: " + getKeysTime
757                 + " Without Duplicate Check: " + getKeysNoDuplicateCheckTime);
758         assertTrue("Getting keys took more than 150ms", getKeysTime < 100);
759     }
760 
761     /**
762      * Checks the expense of checking in-memory size
763      * 3467890 bytes in 1601ms for JDK1.4.2
764      */
765     public void testCalculateInMemorySizePerformanceAndReasonableness() throws Exception {
766         //Set size so the second element overflows to disk.
767         Cache cache = new Cache("test4", 1000, true, true, 0, 0);
768         manager.addCache(cache);
769 
770         //Set up object graphs
771         for (int i = 0; i < 1000; i++) {
772             HashMap map = new HashMap(100);
773             for (int j = 0; j < 100; j++) {
774                 map.put("key" + j, new String[]{"adfdafs", "asdfdsafa", "sdfasdf"});
775             }
776             cache.put(new Element("key" + i, map));
777         }
778 
779         StopWatch stopWatch = new StopWatch();
780         long size = cache.calculateInMemorySize();
781         assertTrue("Size is " + size + ". Check it for reasonableness.", size > 100000 && size < 5000000);
782         long elapsed = stopWatch.getElapsedTime();
783         LOG.info("In-memory size in bytes: " + size
784                 + " time to calculate in ms: " + elapsed);
785         assertTrue("Calculate memory size takes less than 3.5 seconds", elapsed < 3500);
786     }
787 
788 
789     /**
790      * Expire elements and verify size is correct.
791      */
792     public void testGetSizeAfterExpiry() throws Exception {
793         //Set size so the second element overflows to disk.
794         Cache cache = new Cache("test", 1, true, false, 5, 2);
795         manager.addCache(cache);
796         cache.put(new Element("key1", "value1"));
797         cache.put(new Element("key2", "value1"));
798 
799         //Let the idle expire
800         Thread.sleep(5010);
801         assertEquals(null, cache.get("key1"));
802         assertEquals(null, cache.get("key2"));
803 
804         assertEquals(0, cache.getSize());
805     }
806 
807     /**
808      * Test create and access times
809      */
810     public void testAccessTimes() throws Exception {
811         //Set size so the second element overflows to disk.
812         Cache cache = new Cache("test", 5, true, false, 5, 2);
813         assertEquals(Status.STATUS_UNINITIALISED, cache.getStatus());
814         manager.addCache(cache);
815         Element newElement = new Element("key1", "value1");
816         long creationTime = newElement.getCreationTime();
817         assertTrue(newElement.getCreationTime() > (System.currentTimeMillis() - 500));
818         assertTrue(newElement.getHitCount() == 0);
819         assertTrue(newElement.getLastAccessTime() == 0);
820 
821         cache.put(newElement);
822 
823         Element element = cache.get("key1");
824         assertNotNull(element);
825         assertEquals(creationTime, element.getCreationTime());
826         assertTrue(element.getLastAccessTime() != 0);
827         assertTrue(element.getHitCount() == 1);
828 
829         //Check that access statistics were reset but not creation time
830         cache.put(element);
831         element = cache.get("key1");
832         assertEquals(creationTime, element.getCreationTime());
833         assertTrue(element.getLastAccessTime() != 0);
834         assertTrue(element.getHitCount() == 1);
835     }
836 
837     /**
838      * Tests initialisation failures
839      */
840     public void testInitialiseFailures() {
841         try {
842             Cache cache = new Cache("testInitialiseFailures2", 1, false, false, 5, 1);
843             cache.initialise();
844 
845             cache.initialise();
846             fail("Should have thrown IllegalArgumentException");
847         } catch (IllegalStateException e) {
848             //noop
849         }
850     }
851 
852     /**
853      * Tests putting nulls throws correct exception
854      *
855      * @throws Exception
856      */
857     public void testPutFailures() throws Exception {
858         Cache cache = new Cache("testPutFailures", 1, false, false, 5, 1);
859         manager.addCache(cache);
860 
861         try {
862             cache.put(null);
863             fail("Should have thrown IllegalArgumentException");
864         } catch (IllegalArgumentException e) {
865             //noop
866         }
867 
868         try {
869             cache.putQuiet(null);
870             fail("Should have thrown IllegalArgumentException");
871         } catch (IllegalArgumentException e) {
872             //noop
873         }
874 
875         //Null Elements like this are OK
876         cache.putQuiet(new Element(null, null));
877     }
878 
879     /**
880      * Tests memory store size
881      *
882      * @throws Exception
883      */
884     public void testGetMemoryStoreSize() throws Exception {
885         Cache cache = new Cache("testGetMemoryStoreSize", 10, false, false, 100, 200);
886         manager.addCache(cache);
887 
888         assertEquals(0, cache.getMemoryStoreSize());
889 
890         cache.put(new Element("key1", "value1"));
891         assertEquals(1, cache.getMemoryStoreSize());
892 
893         cache.put(new Element("key2", "value2"));
894         assertEquals(2, cache.getMemoryStoreSize());
895 
896         cache.put(new Element("key3", "value3"));
897         cache.put(new Element("key4", "value4"));
898         //NonSerializable
899         cache.put(new Element(new Object(), Object.class));
900         assertEquals(5, cache.getMemoryStoreSize());
901 
902         cache.remove("key4");
903         cache.remove("key3");
904         assertEquals(3, cache.getMemoryStoreSize());
905 
906         cache.removeAll();
907         assertEquals(0, cache.getMemoryStoreSize());
908     }
909 
910     /**
911      * Tests flushing the cache
912      *
913      * @throws Exception
914      */
915     public void testFlushWhenOverflowToDisk() throws Exception {
916         Cache cache = new Cache("testGetMemoryStoreSize", 50, true, false, 100, 200);
917         manager.addCache(cache);
918 
919         assertEquals(0, cache.getMemoryStoreSize());
920 
921         for (int i = 0; i < 100; i++) {
922             cache.put(new Element("" + i, new Date()));
923         }
924         //Not spoolable, should get ignored
925         cache.put(new Element("key", new Object()));
926         cache.put(new Element(new Object(), new Object()));
927         cache.put(new Element(new Object(), "value"));
928 
929         //these "null" Elements are keyed the same way and only count as one
930         cache.put(new Element(null, null));
931         cache.put(new Element(null, null));
932 
933         cache.put(new Element("nullValue", null));
934 
935         assertEquals(50, cache.getMemoryStoreSize());
936         assertEquals(55, cache.getDiskStoreSize());
937 
938         cache.flush();
939         assertEquals(0, cache.getMemoryStoreSize());
940         //Non Serializable Elements gets discarded
941         assertEquals(100, cache.getDiskStoreSize());
942 
943     }
944 
945 
946     /**
947      * When flushing large MemoryStores, OutOfMemory issues can happen if we are
948      * not careful to move each to Element to the DiskStore, rather than copy them all
949      * and then delete them from the MemoryStore.
950      * <p/>
951      * This test manipulates a MemoryStore right on the edge of what can fit into the 64MB standard VM size.
952      * An inefficient spool will cause an OutOfMemoryException.
953      *
954      * @throws Exception
955      */
956     public void testMemoryEfficiencyOfFlushWhenOverflowToDisk() throws Exception {
957         Cache cache = new Cache("testGetMemoryStoreSize", 40000, true, false, 100, 200);
958         manager.addCache(cache);
959 
960         assertEquals(0, cache.getMemoryStoreSize());
961 
962         for (int i = 0; i < 80000; i++) {
963             cache.put(new Element("" + i, new byte[480]));
964         }
965 
966         assertEquals(40000, cache.getMemoryStoreSize());
967         assertEquals(40000, cache.getDiskStoreSize());
968 
969         long beforeMemory = measureMemoryUse();
970         cache.flush();
971 
972         //It takes a while to write all the Elements to disk
973         Thread.sleep(5000);
974 
975         long afterMemory = measureMemoryUse();
976         long memoryIncrease = afterMemory - beforeMemory;
977         assertTrue(memoryIncrease < 40000000);
978 
979         assertEquals(0, cache.getMemoryStoreSize());
980         assertEquals(80000, cache.getDiskStoreSize());
981 
982     }
983 
984 
985     /**
986      * Tests using elements with null values. They should work as normal.
987      *
988      * @throws Exception
989      */
990     public void testElementWithNullValue() throws Exception {
991         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 100, 200);
992         manager.addCache(cache);
993 
994         Object key1 = new Object();
995         Element element = new Element(key1, null);
996         cache.put(element);
997         assertNotNull(cache.get(key1));
998         assertNotNull(cache.getQuiet(key1));
999         assertSame(element, cache.get(key1));
1000         assertSame(element, cache.getQuiet(key1));
1001         assertNull(cache.get(key1).getObjectValue());
1002         assertNull(cache.getQuiet(key1).getObjectValue());
1003 
1004         assertEquals(false, cache.isExpired(element));
1005     }
1006 
1007 
1008     /**
1009      * Tests using elements with null values. They should work as normal.
1010      *
1011      * @throws Exception
1012      */
1013     public void testNonSerializableElement() throws Exception {
1014         Cache cache = new Cache("testElementWithNonSerializableValue", 1, true, false, 100, 200);
1015         manager.addCache(cache);
1016 
1017         Element element1 = new Element("key1", new Object());
1018         Element element2 = new Element("key2", new Object());
1019         cache.put(element1);
1020         cache.put(element2);
1021 
1022         //Removed because could not overflow
1023         assertNull(cache.get("key1"));
1024 
1025         //Second one should be in the MemoryStore and retrievable
1026         assertNotNull(cache.get("key2"));
1027     }
1028 
1029 
1030     /**
1031      * Tests what happens when an Element throws an Error on serialization. This mimics
1032      * what a nasty error like OutOfMemoryError could do.
1033      * <p/>
1034      * Before a change to the SpoolThread to handle this situation this test failed and generated the following log message.
1035      * Jun 28, 2006 7:17:16 PM net.sf.ehcache.store.DiskStore put
1036      * SEVERE: testThreadKillerCache: Elements cannot be written to disk store because the spool thread has died.
1037      *
1038      * @throws Exception
1039      */
1040     public void testSpoolThreadHandlesThreadKiller() throws Exception {
1041         Cache cache = new Cache("testThreadKiller", 1, true, false, 100, 200);
1042         manager.addCache(cache);
1043 
1044         Element elementThreadKiller = new Element("key", new ThreadKiller());
1045         cache.put(elementThreadKiller);
1046         Element element1 = new Element("key1", "one");
1047         Element element2 = new Element("key2", "two");
1048         cache.put(element1);
1049         cache.put(element2);
1050 
1051         Thread.sleep(2000);
1052 
1053         assertNotNull(cache.get("key1"));
1054         assertNotNull(cache.get("key2"));
1055     }
1056 
1057     /**
1058      * Tests disk store and memory store size
1059      *
1060      * @throws Exception
1061      */
1062     public void testGetDiskStoreSize() throws Exception {
1063         Cache cache = new Cache("testGetDiskStoreSize", 1, true, false, 100, 200);
1064         manager.addCache(cache);
1065         assertEquals(0, cache.getDiskStoreSize());
1066 
1067         cache.put(new Element("key1", "value1"));
1068         assertEquals(0, cache.getDiskStoreSize());
1069         assertEquals(1, cache.getSize());
1070 
1071         cache.put(new Element("key2", "value2"));
1072         assertEquals(2, cache.getSize());
1073         assertEquals(1, cache.getDiskStoreSize());
1074         assertEquals(1, cache.getMemoryStoreSize());
1075 
1076         cache.put(new Element("key3", "value3"));
1077         cache.put(new Element("key4", "value4"));
1078         assertEquals(4, cache.getSize());
1079         assertEquals(3, cache.getDiskStoreSize());
1080         assertEquals(1, cache.getMemoryStoreSize());
1081 
1082         // remove last element inserted (is in memory store)
1083         assertNotNull(cache.getMemoryStore().get("key4"));
1084         cache.remove("key4");
1085         assertEquals(3, cache.getSize());
1086         assertEquals(3, cache.getDiskStoreSize());
1087         assertEquals(0, cache.getMemoryStoreSize());
1088 
1089         // remove key1 element
1090         assertNotNull(cache.getDiskStore().get("key1"));
1091         cache.remove("key1");
1092         assertEquals(2, cache.getSize());
1093         assertEquals(2, cache.getDiskStoreSize());
1094         assertEquals(0, cache.getMemoryStoreSize());
1095 
1096         // add another
1097         cache.put(new Element("key5", "value5"));
1098         assertEquals(3, cache.getSize());
1099         assertEquals(2, cache.getDiskStoreSize());
1100         assertEquals(1, cache.getMemoryStoreSize());
1101 
1102         // remove all
1103         cache.removeAll();
1104         assertEquals(0, cache.getSize());
1105         assertEquals(0, cache.getDiskStoreSize());
1106         assertEquals(0, cache.getMemoryStoreSize());
1107 
1108         //Check behaviour of NonSerializable objects
1109         cache.put(new Element(new Object(), new Object()));
1110         cache.put(new Element(new Object(), new Object()));
1111         cache.put(new Element(new Object(), new Object()));
1112         assertEquals(1, cache.getSize());
1113         assertEquals(0, cache.getDiskStoreSize());
1114         assertEquals(1, cache.getMemoryStoreSize());
1115 
1116     }
1117 
1118     /**
1119      * Tests that attempting to clone a cache fails with the right exception.
1120      *
1121      * @throws Exception
1122      */
1123     public void testCloneFailures() throws Exception {
1124         Cache cache = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1125         manager.addCache(cache);
1126         try {
1127             cache.clone();
1128             fail("Should have thrown CloneNotSupportedException");
1129         } catch (CloneNotSupportedException e) {
1130             //noop
1131         }
1132     }
1133 
1134 
1135     /**
1136      * Tests that the toString() method works.
1137      */
1138     public void testToString() {
1139         Cache cache = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1140         assertTrue(cache.toString().indexOf("testGetMemoryStore") > -1);
1141         assertEquals(389, cache.toString().length());
1142     }
1143 
1144 
1145     /**
1146      * When does equals mean the same thing as == ?
1147      *
1148      * @throws CacheException
1149      * @throws InterruptedException
1150      */
1151     public void testEquals() throws CacheException, InterruptedException {
1152         Cache cache = new Cache("cache", 1, true, false, 100, 200, false, 1);
1153         manager.addCache(cache);
1154 
1155         Element element1 = new Element("1", new Date());
1156         Element element2 = new Element("2", new Date());
1157         cache.put(element1);
1158         cache.put(element2);
1159 
1160         //Test equals and == from an Element retrieved from the MemoryStore
1161         Element elementFromStore = cache.get("2");
1162         assertEquals(element2, elementFromStore);
1163         assertTrue(element2 == elementFromStore);
1164 
1165         //Give the spool a chance to make sure it really got serialized to Disk
1166         Thread.sleep(300);
1167 
1168         //Test equals and == from an Element retrieved from the MemoryStore
1169         Element elementFromDiskStore = cache.get("1");
1170         assertEquals(element1, elementFromDiskStore);
1171         assertTrue(element1 != elementFromDiskStore);
1172     }
1173 
1174     /**
1175      * Tests the uniqueness of the GUID
1176      */
1177     public void testGuid() {
1178         Cache cache1 = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1179         Cache cache2 = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1180         String guid1 = cache1.getGuid();
1181         String guid2 = cache2.getGuid();
1182         assertEquals(cache1.getName(), cache2.getName());
1183         assertTrue(!guid1.equals(guid2));
1184 
1185     }
1186 
1187 
1188     /**
1189      * SoftReference behaviour testing.
1190      */
1191     public void testSoftReferences() {
1192         Map map = new HashMap();
1193         for (int i = 0; i < 100; i++) {
1194             map.put(new Integer(i), new SoftReference(new byte[1000000]));
1195         }
1196 
1197         int counter = 0;
1198         for (int i = 0; i < 100; i++) {
1199             SoftReference softReference = (SoftReference) map.get(new Integer(i));
1200             byte[] payload = (byte[]) softReference.get();
1201             if (payload != null) {
1202                 LOG.info("Value found for " + i);
1203                 counter++;
1204             }
1205         }
1206 
1207         assertTrue("You should get more than this out of SoftReferences", counter > 32);
1208 
1209     }
1210 
1211 
1212     /**
1213      * Does the Object API work?
1214      */
1215     public void testAPIObjectCompatibility() {
1216         //Set size so the second element overflows to disk.
1217         Cache cache = new Cache("test", 5, true, false, 5, 2);
1218         manager.addCache(cache);
1219 
1220         Object objectKey = new Object();
1221         Object objectValue = new Object();
1222         Element objectElement = new Element(objectKey, objectValue);
1223         cache.put(objectElement);
1224 
1225         //Cannot get it back using get
1226         Element retrievedElement = cache.get(objectKey);
1227         assertNotNull(retrievedElement);
1228         try {
1229             retrievedElement.getObjectValue();
1230         } catch (CacheException e) {
1231             //expected
1232         }
1233 
1234         //Test that equals works
1235         retrievedElement = cache.get(objectKey);
1236         assertEquals(objectElement, retrievedElement);
1237 
1238         //Can with getObjectValue
1239         retrievedElement = cache.get(objectKey);
1240         assertEquals(objectValue, retrievedElement.getObjectValue());
1241 
1242     }
1243 
1244 
1245     /**
1246      * Does the Serializable API work?
1247      */
1248     public void testAPISerializableCompatibility() {
1249         //Set size so the second element overflows to disk.
1250         Cache cache = new Cache("test", 5, true, false, 5, 2);
1251         manager.addCache(cache);
1252 
1253         //Try object compatibility
1254         Serializable key = new String();
1255         Element objectElement = new Element(key, new String());
1256         cache.put(objectElement);
1257         Object retrievedObject = cache.get(key);
1258         assertEquals(retrievedObject, objectElement);
1259 
1260         //Test that equals works
1261         assertEquals(objectElement, retrievedObject);
1262     }
1263 
1264 
1265 
1266 }