1   /**
2    *  Copyright 2003-2007 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.ByteArrayInputStream;
23  import java.io.Serializable;
24  import java.util.ArrayList;
25  import java.util.Date;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Random;
29  
30  import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
31  import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
32  import net.sf.ehcache.event.RegisteredEventListeners;
33  
34  
35  /**
36   * Tests for a Cache
37   *
38   * @author Greg Luck, Claus Ibsen
39   * @version $Id: CacheTest.java 512 2007-07-10 09:18:45Z gregluck $
40   */
41  public class CacheTest extends AbstractCacheTest {
42      private static final Log LOG = LogFactory.getLog(CacheTest.class.getName());
43  
44  
45      /**
46       * teardown
47       */
48      protected void tearDown() throws Exception {
49          super.tearDown();
50      }
51  
52      /**
53       * Gets the sample cache 1
54       */
55      protected Ehcache getSampleCache1() {
56          Cache cache = manager.getCache("sampleCache1");
57          return cache;
58      }
59  
60      /**
61       * Creates a cache
62       *
63       * @return
64       */
65      protected Ehcache createTestCache() {
66          Cache cache = new Cache("test4", 1000, true, true, 0, 0);
67          manager.addCache(cache);
68          return cache;
69      }
70  
71      /**
72       * Checks we cannot use a cache after shutdown
73       */
74      public void testUseCacheAfterManagerShutdown() throws CacheException {
75          Ehcache cache = getSampleCache1();
76          manager.shutdown();
77          Element element = new Element("key", "value");
78          try {
79              cache.getSize();
80              fail();
81          } catch (IllegalStateException e) {
82              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
83          }
84          try {
85              cache.put(element);
86              fail();
87          } catch (IllegalStateException e) {
88              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
89          }
90          try {
91              cache.get("key");
92              fail();
93          } catch (IllegalStateException e) {
94              assertEquals("The sampleCache1 Cache is not alive.", e.getMessage());
95          }
96          if (cache instanceof Cache) {
97              Cache castCache = (Cache) cache;
98              //ok to get stats
99              castCache.getHitCount();
100             castCache.getMemoryStoreHitCount();
101             castCache.getDiskStoreHitCount();
102             castCache.getMissCountExpired();
103             castCache.getMissCountNotFound();
104         }
105 
106     }
107 
108 
109     /**
110      * Checks we cannot use a cache outside the manager
111      */
112     public void testUseCacheOutsideManager() throws CacheException {
113         //Not put into manager.
114         Cache cache = new Cache("testCache", 1, true, false, 5, 2);
115         Element element = new Element("key", "value");
116         try {
117             cache.getSize();
118             fail();
119         } catch (IllegalStateException e) {
120             assertEquals("The testCache Cache is not alive.", e.getMessage());
121         }
122         try {
123             cache.put(element);
124             fail();
125         } catch (IllegalStateException e) {
126             assertEquals("The testCache Cache is not alive.", e.getMessage());
127         }
128         try {
129             cache.get("key");
130             fail();
131         } catch (IllegalStateException e) {
132             assertEquals("The testCache Cache is not alive.", e.getMessage());
133         }
134         //ok to get stats
135         cache.getHitCount();
136         cache.getMemoryStoreHitCount();
137         cache.getDiskStoreHitCount();
138         cache.getMissCountExpired();
139         cache.getMissCountNotFound();
140     }
141 
142     /**
143      * Checks when and how we can set the cache name.
144      */
145     public void testSetCacheName() throws CacheException {
146         //Not put into manager.
147         Ehcache cache = new Cache("testCache", 1, true, false, 5, 2);
148 
149         try {
150             cache.setName(null);
151             fail();
152         } catch (IllegalArgumentException e) {
153             //expected
154         }
155 
156         try {
157             cache.setName("illegal/name");
158             fail();
159         } catch (IllegalArgumentException e) {
160             //expected
161         }
162 
163         manager.addCache(cache);
164         try {
165             cache.setName("trying_to_change_name_after_initialised");
166             fail();
167         } catch (IllegalStateException e) {
168             //expected
169         }
170     }
171 
172 
173     /**
174      * Test using a cache which has been removed and replaced.
175      */
176     public void testStaleCacheReference() throws CacheException {
177         manager.addCache("test");
178         Ehcache cache = manager.getCache("test");
179         assertNotNull(cache);
180         cache.put(new Element("key1", "value1"));
181 
182         assertEquals("value1", cache.get("key1").getObjectValue());
183         manager.removeCache("test");
184         manager.addCache("test");
185 
186         try {
187             cache.get("key1");
188             fail();
189         } catch (IllegalStateException e) {
190             assertEquals("The test Cache is not alive.", e.getMessage());
191         }
192     }
193 
194     /**
195      * Tests getting the cache name
196      *
197      * @throws Exception
198      */
199     public void testCacheName() throws Exception {
200         manager.addCache("test");
201         Ehcache cache = manager.getCache("test");
202         assertEquals("test", cache.getName());
203         assertEquals(Status.STATUS_ALIVE, cache.getStatus());
204     }
205 
206 
207     /**
208      * Tests getting the cache name
209      *
210      * @throws Exception
211      */
212     public void testCacheWithNoIdle() throws Exception {
213         Ehcache cache = manager.getCache("sampleCacheNoIdle");
214         assertEquals("sampleCacheNoIdle", cache.getName());
215         assertEquals(Status.STATUS_ALIVE, cache.getStatus());
216         assertEquals(0, cache.getTimeToIdleSeconds());
217     }
218 
219     /**
220      * Test expiry based on time to live
221      * <cache name="sampleCacheNoIdle"
222      * maxElementsInMemory="1000"
223      * eternal="false"
224      * timeToLiveSeconds="5"
225      * overflowToDisk="false"
226      * />
227      */
228     public void testExpiryBasedOnTimeToLiveWhenNoIdle() throws Exception {
229         //Set size so the second element overflows to disk.
230         Ehcache cache = manager.getCache("sampleCacheNoIdle");
231         cache.put(new Element("key1", "value1"));
232         cache.put(new Element("key2", "value1"));
233         assertNotNull(cache.get("key1"));
234         assertNotNull(cache.get("key2"));
235 
236         //Test time to idle. Should not idle out because not specified
237         Thread.sleep(2000);
238         assertNotNull(cache.get("key1"));
239         assertNotNull(cache.get("key2"));
240 
241         //Test time to live.
242         Thread.sleep(5020);
243         assertNull(cache.get("key1"));
244         assertNull(cache.get("key2"));
245     }
246 
247 
248     /**
249      * Test expiry based on time to live for a cache with config
250      * <cache name="sampleCacheNoIdle"
251      * maxElementsInMemory="1000"
252      * eternal="false"
253      * timeToLiveSeconds="5"
254      * overflowToDisk="false"
255      * />
256      * <p/>
257      * where an Elment override is set on TTL
258      */
259     public void testExpiryBasedOnTimeToLiveWhenNoIdleElementOverride() throws Exception {
260         //Set size so the second element overflows to disk.
261         Ehcache cache = manager.getCache("sampleCacheNoIdle");
262         Element element1 = new Element("key1", "value1");
263         element1.setTimeToLive(3);
264         cache.put(element1);
265 
266         Element element2 = new Element("key2", "value1");
267         element2.setTimeToLive(3);
268         cache.put(element2);
269         assertNotNull(cache.get("key1"));
270         assertNotNull(cache.get("key2"));
271 
272         //Test time to idle. Should not idle out because not specified
273         Thread.sleep(1000);
274         assertNotNull(cache.get("key1"));
275         assertNotNull(cache.get("key2"));
276 
277         //Test time to live.
278         Thread.sleep(4020);
279         assertNull(cache.get("key1"));
280         assertNull(cache.get("key2"));
281     }
282 
283     /**
284      * Test expiry based on time to live for a cache with config
285      * <cache name="sampleCacheNoIdle"
286      * maxElementsInMemory="1000"
287      * eternal="false"
288      * timeToLiveSeconds="5"
289      * overflowToDisk="false"
290      * />
291      * <p/>
292      * where an Elment override is set on TTL
293      */
294     public void testExpiryBasedOnTimeToIdleElementOverride() throws Exception {
295         //Set size so the second element overflows to disk.
296         Ehcache cache = manager.getCache("sampleCacheNoIdle");
297         assertEquals(30, cache.getCacheConfiguration().getDiskSpoolBufferSizeMB());
298         Element element1 = new Element("key1", "value1");
299         element1.setTimeToIdle(1);
300         cache.put(element1);
301 
302         Element element2 = new Element("key2", "value1");
303         element2.setTimeToIdle(1);
304         cache.put(element2);
305         assertNotNull(cache.get("key1"));
306         assertNotNull(cache.get("key2"));
307 
308         //Test time to idle. Should not idle out because not specified
309         Thread.sleep(1050);
310         assertNull(cache.get("key1"));
311         assertNull(cache.get("key2"));
312 
313     }
314 
315 
316     /**
317      * Test expiry based on time to live for a cache with config
318      * <cache name="sampleCacheNoIdle"
319      * maxElementsInMemory="1000"
320      * eternal="false"
321      * timeToLiveSeconds="5"
322      * overflowToDisk="false"
323      * />
324      * <p/>
325      * where an Elment override is set on TTL
326      */
327     public void testExpiryBasedEternalElementOverride() throws Exception {
328         //Set size so the second element overflows to disk.
329         Ehcache cache = manager.getCache("sampleCacheNoIdle");
330         Element element1 = new Element("key1", "value1");
331         element1.setEternal(true);
332         cache.put(element1);
333 
334         Element element2 = new Element("key2", "value1");
335         element2.setEternal(true);
336         cache.put(element2);
337         assertNotNull(cache.get("key1"));
338         assertNotNull(cache.get("key2"));
339 
340         Thread.sleep(5050);
341         assertNotNull(cache.get("key1"));
342         assertNotNull(cache.get("key2"));
343 
344     }
345 
346 
347     /**
348      * Test expiry based on time to live. Even though eternal is false, because there are no
349      * expiry or idle times, it is eternal.
350      * <cache name="sampleCacheNotEternalButNoIdleOrExpiry"
351      * maxElementsInMemory="1000"
352      * eternal="false"
353      * overflowToDisk="false"
354      * />
355      */
356     public void testExpirySampleCacheNotEternalButNoIdleOrExpiry() throws Exception {
357         //Set size so the second element overflows to disk.
358         Ehcache cache = manager.getCache("sampleCacheNotEternalButNoIdleOrExpiry");
359         cache.put(new Element("key1", "value1"));
360         cache.put(new Element("key2", "value1"));
361         assertNotNull(cache.get("key1"));
362         assertNotNull(cache.get("key2"));
363 
364         //Test time to idle. Should not idle out because not specified
365         Thread.sleep(2000);
366         assertNotNull(cache.get("key1"));
367         assertNotNull(cache.get("key2"));
368 
369         //Test time to live.
370         Thread.sleep(5020);
371         assertNotNull(cache.get("key1"));
372         assertNotNull(cache.get("key2"));
373     }
374 
375 
376     /**
377      * Test overflow to disk = false
378      */
379     public void testNoOverflowToDisk() throws Exception {
380         //Set size so the second element overflows to disk.
381         Cache cache = new Cache("test", 1, false, true, 5, 2);
382         manager.addCache(cache);
383         cache.put(new Element("key1", "value1"));
384         cache.put(new Element("key2", "value1"));
385         assertNull(cache.get("key1"));
386         assertNotNull(cache.get("key2"));
387     }
388 
389 
390     /**
391      * Performance tests for a range of Memory Store - Disk Store combinations.
392      * <p/>
393      * This demonstrates that a memory only store is approximately an order of magnitude
394      * faster than a disk only store.
395      * <p/>
396      * It also shows that double the performance of a Disk Only store can be obtained
397      * with a maximum memory size of only 1. Accordingly a Cache created without a
398      * maximum memory size of less than 1 will issue a warning.
399      * <p/>
400      * Threading changes were made in v1.41 of DiskStore. The before and after numbers are shown.
401      */
402     public void testProportionMemoryAndDiskPerformance() throws Exception {
403         StopWatch stopWatch = new StopWatch();
404         long time = 0;
405 
406         //Memory only Typical 192ms
407         Cache memoryOnlyCache = new Cache("testMemoryOnly", 5000, false, false, 5, 2);
408         manager.addCache(memoryOnlyCache);
409         time = stopWatch.getElapsedTime();
410         for (int i = 0; i < 5000; i++) {
411             Integer key = new Integer(i);
412             memoryOnlyCache.put(new Element(new Integer(i), "value"));
413             memoryOnlyCache.get(key);
414         }
415         time = stopWatch.getElapsedTime();
416         LOG.info("Time for MemoryStore: " + time);
417         assertTrue("Time to put and get 5000 entries into MemoryStore", time < 300);
418 
419         //Set size so that all elements overflow to disk.
420         // 1245 ms v1.38 DiskStore
421         // 273 ms v1.42 DiskStore
422         Cache diskOnlyCache = new Cache("testDiskOnly", 0, true, false, 5, 2);
423         manager.addCache(diskOnlyCache);
424         time = stopWatch.getElapsedTime();
425         for (int i = 0; i < 5000; i++) {
426             Integer key = new Integer(i);
427             diskOnlyCache.put(new Element(key, "value"));
428             diskOnlyCache.get(key);
429         }
430         time = stopWatch.getElapsedTime();
431         LOG.info("Time for DiskStore: " + time);
432         assertTrue("Time to put and get 5000 entries into DiskStore was less than 2 sec", time < 2000);
433 
434         // 1 Memory, 999 Disk
435         // 591 ms v1.38 DiskStore
436         // 56 ms v1.42 DiskStore
437         Cache m1d999Cache = new Cache("m1d999Cache", 1, true, false, 5, 2);
438         manager.addCache(m1d999Cache);
439         time = stopWatch.getElapsedTime();
440         for (int i = 0; i < 5000; i++) {
441             Integer key = new Integer(i);
442             m1d999Cache.put(new Element(key, "value"));
443             m1d999Cache.get(key);
444         }
445         time = stopWatch.getElapsedTime();
446         LOG.info("Time for m1d999Cache: " + time);
447         assertTrue("Time to put and get 5000 entries into m1d999Cache", time < 2000);
448 
449         // 500 Memory, 500 Disk
450         // 669 ms v1.38 DiskStore
451         // 47 ms v1.42 DiskStore
452         Cache m500d500Cache = new Cache("m500d500Cache", 500, true, false, 5, 2);
453         manager.addCache(m500d500Cache);
454         time = stopWatch.getElapsedTime();
455         for (int i = 0; i < 5000; i++) {
456             Integer key = new Integer(i);
457             m500d500Cache.put(new Element(key, "value"));
458             m500d500Cache.get(key);
459         }
460         time = stopWatch.getElapsedTime();
461         LOG.info("Time for m500d500Cache: " + time);
462         assertTrue("Time to put and get 5000 entries into m500d500Cache", time < 2000);
463 
464     }
465 
466     /**
467      * Test Caches with persistent stores dispose properly. Tests:
468      * <ol>
469      * <li>No exceptions are thrown on dispose
470      * <li>You cannot re add a cache after it has been disposed and removed
471      * <li>You can create a new cache with the same name
472      * </ol>
473      */
474     public void testCreateAddDisposeAdd() throws CacheException {
475         Cache cache = new Cache("test2", 1, true, true, 0, 0, true, 120);
476         manager.addCache(cache);
477         cache.put(new Element("key1", "value1"));
478         cache.put(new Element("key2", "value1"));
479         int sizeFromGetSize = cache.getSize();
480         int sizeFromKeys = cache.getKeys().size();
481         assertEquals(sizeFromGetSize, sizeFromKeys);
482         assertEquals(2, cache.getSize());
483         //package protected method, only available to tests. Called by teardown
484         cache.dispose();
485         manager.removeCache("test2");
486 
487 
488         try {
489             manager.addCache(cache);
490             fail();
491         } catch (CacheException e) {
492             //expected
493         }
494 
495         //Add a new cache with the same name as the disposed one.
496         Cache cache2 = new Cache("test2", 1, true, true, 0, 0, true, 120);
497         manager.addCache(cache2);
498         Ehcache cacheFromManager = manager.getCache("test2");
499         assertTrue(cacheFromManager.getStatus().equals(Status.STATUS_ALIVE));
500 
501     }
502 
503     /**
504      * Test expiry based on time to live
505      */
506     public void testExpiryBasedOnTimeToLive() throws Exception {
507         //Set size so the second element overflows to disk.
508         Cache cache = new Cache("test", 1, true, false, 3, 0);
509         manager.addCache(cache);
510         cache.put(new Element("key1", "value1"));
511         cache.put(new Element("key2", "value1"));
512 
513         //Test time to live
514         assertNotNull(cache.get("key1"));
515         assertNotNull(cache.get("key2"));
516         Thread.sleep(1020);
517         //Test time to live
518         assertNotNull(cache.get("key1"));
519         assertNotNull(cache.get("key2"));
520         Thread.sleep(1020);
521         //Test time to live
522         assertNotNull(cache.get("key1"));
523         assertNotNull(cache.get("key2"));
524         Thread.sleep(1020);
525         assertNull(cache.get("key1"));
526         assertNull(cache.get("key2"));
527     }
528 
529 
530     /**
531      * Tests that a cache created from defaults will expire as per
532      * the default expiry policy.
533      *
534      * @throws Exception
535      */
536     public void testExpiryBasedOnTimeToLiveForDefault() throws Exception {
537         String name = "ThisIsACacheWhichIsNotConfiguredAndWillThereforeUseDefaults";
538         Ehcache cache = null;
539         CacheManager manager = CacheManager.getInstance();
540         cache = manager.getCache(name);
541         if (cache == null) {
542             LOG.warn("Could not find configuration for " + name
543                     + ". Configuring using the defaultCache settings.");
544             manager.addCache(name);
545             cache = manager.getCache(name);
546         }
547 
548         cache.put(new Element("key1", "value1"));
549         cache.put(new Element("key2", "value1"));
550 
551         //Test time to live
552         assertNotNull(cache.get("key1"));
553         assertNotNull(cache.get("key2"));
554         Thread.sleep(10020);
555         assertNull(cache.get("key1"));
556         assertNull(cache.get("key2"));
557 
558 
559     }
560 
561 
562     /**
563      * Test expiry based on time to live.
564      * <p/>
565      * Elements are put quietly back into the cache after being cloned.
566      * The elements should expire as if the putQuiet had not happened.
567      */
568     public void testExpiryBasedOnTimeToLiveAfterPutQuiet() throws Exception {
569         //Set size so the second element overflows to disk.
570         Cache cache = new Cache("test", 1, true, false, 5, 2);
571         manager.addCache(cache);
572         cache.put(new Element("key1", "value1"));
573         cache.put(new Element("key2", "value1"));
574 
575         Element element1 = cache.get("key1");
576         Element element2 = cache.get("key2");
577         assertNotNull(element1);
578         assertNotNull(element2);
579 
580         //Test time to live
581         Thread.sleep(2020);
582         //Should not affect age
583         cache.putQuiet((Element) element2.clone());
584         cache.putQuiet((Element) element2.clone());
585         Thread.sleep(3020);
586         assertNull(cache.get("key1"));
587         assertNull(cache.get("key2"));
588     }
589 
590     /**
591      * Test expiry based on time to live
592      */
593     public void testNoIdleOrExpiryBasedOnTimeToLiveForEternal() throws Exception {
594         //Set size so the second element overflows to disk.
595         Cache cache = new Cache("test", 1, true, true, 5, 2);
596         manager.addCache(cache);
597         cache.put(new Element("key1", "value1"));
598         cache.put(new Element("key2", "value1"));
599 
600         //Test time to live
601         assertNotNull(cache.get("key1"));
602         assertNotNull(cache.get("key2"));
603 
604         //Check that we did not idle out
605         Thread.sleep(2020);
606         assertNotNull(cache.get("key1"));
607         assertNotNull(cache.get("key2"));
608 
609         //Check that we did not expire out
610         Thread.sleep(3020);
611         assertNotNull(cache.get("key1"));
612         assertNotNull(cache.get("key2"));
613     }
614 
615     /**
616      * Test expiry based on time to idle.
617      */
618     public void testExpiryBasedOnTimeToIdle() throws Exception {
619         //Set size so the second element overflows to disk.
620         Cache cache = new Cache("test", 1, true, false, 6, 2);
621         manager.addCache(cache);
622         cache.put(new Element("key1", "value1"));
623         cache.put(new Element("key2", "value1"));
624 
625         //Test time to idle
626         Element element1 = cache.get("key1");
627         Element element2 = cache.get("key2");
628         assertNotNull(element1);
629         assertNotNull(element2);
630         Thread.sleep(2050);
631         assertNull(cache.get("key1"));
632         assertNull(cache.get("key2"));
633 
634         //Test effect of get
635         cache.put(new Element("key1", "value1"));
636         cache.put(new Element("key2", "value1"));
637         Thread.sleep(1050);
638         assertNotNull(cache.get("key1"));
639         assertNotNull(cache.get("key2"));
640 
641         Thread.sleep(2050);
642         assertNull(cache.get("key1"));
643         assertNull(cache.get("key2"));
644     }
645 
646 
647     /**
648      * Test expiry based on time to idle.
649      */
650     public void testExpiryBasedOnTimeToIdleAfterPutQuiet() throws Exception {
651         //Set size so the second element overflows to disk.
652         Cache cache = new Cache("test", 1, true, false, 5, 3);
653         manager.addCache(cache);
654         cache.put(new Element("key1", "value1"));
655         cache.put(new Element("key2", "value1"));
656 
657         //Test time to idle
658         Element element1 = cache.get("key1");
659         Element element2 = cache.get("key2");
660         assertNotNull(element1);
661         assertNotNull(element2);
662 
663         //Now, getQuiet and check still times out 2 seconds after last get
664         Thread.sleep(1050);
665         element1 = cache.getQuiet("key1");
666         element2 = cache.getQuiet("key2");
667         Thread.sleep(2050);
668         assertNull(cache.getQuiet("key1"));
669         assertNull(cache.getQuiet("key2"));
670 
671         //Now put back in with putQuiet. Should be immediately expired
672         cache.putQuiet((Element) element1.clone());
673         cache.putQuiet((Element) element2.clone());
674         assertNull(cache.get("key1"));
675         element2 = cache.get("key2");
676         assertNull(element2);
677     }
678 
679     /**
680      * Test element statistics, including get and getQuiet
681      * eternal="false"
682      * timeToIdleSeconds="5"
683      * timeToLiveSeconds="10"
684      * overflowToDisk="true"
685      */
686     public void testElementStatistics() throws Exception {
687         //Set size so the second element overflows to disk.
688         Cache cache = new Cache("test", 1, true, false, 5, 2);
689         manager.addCache(cache);
690         cache.put(new Element("key1", "value1"));
691         cache.put(new Element("key2", "value1"));
692 
693         Element element1 = cache.get("key1");
694         assertEquals("Should be one", 1, element1.getHitCount());
695         element1 = cache.getQuiet("key1");
696         assertEquals("Should be one", 1, element1.getHitCount());
697         element1 = cache.get("key1");
698         assertEquals("Should be two", 2, element1.getHitCount());
699     }
700 
701     /**
702      * Test cache statistics, including get and getQuiet
703      */
704     public void testCacheStatistics() throws Exception {
705         //Set size so the second element overflows to disk.
706         Cache cache = new Cache("test", 1, true, false, 5, 2);
707         manager.addCache(cache);
708         cache.put(new Element("key1", "value1"));
709         cache.put(new Element("key2", "value1"));
710 
711         Element element1 = cache.get("key1");
712         assertEquals("Should be one", 1, element1.getHitCount());
713         assertEquals("Should be one", 1, cache.getHitCount());
714         element1 = cache.getQuiet("key1");
715         assertEquals("Should be one", 1, element1.getHitCount());
716         assertEquals("Should be one", 1, cache.getHitCount());
717         element1 = cache.get("key1");
718         assertEquals("Should be two", 2, element1.getHitCount());
719         assertEquals("Should be two", 2, cache.getHitCount());
720 
721 
722         assertEquals("Should be 0", 0, cache.getMissCountNotFound());
723         cache.get("doesnotexist");
724         assertEquals("Should be 1", 1, cache.getMissCountNotFound());
725 
726 
727     }
728 
729     /**
730      * Checks that getQuiet works how we expect it to
731      *
732      * @throws Exception
733      */
734     public void testGetQuietAndPutQuiet() throws Exception {
735         //Set size so the second element overflows to disk.
736         Cache cache = new Cache("test", 1, true, false, 5, 2);
737         manager.addCache(cache);
738         cache.put(new Element("key1", "value1"));
739         cache.put(new Element("key2", "value1"));
740 
741         Element element1 = cache.get("key1");
742         long lastAccessedElement1 = element1.getLastAccessTime();
743         long hitCountElement1 = element1.getHitCount();
744         assertEquals("Should be two", 1, element1.getHitCount());
745 
746         element1 = cache.getQuiet("key1");
747         element1 = cache.getQuiet("key1");
748         Element clonedElement1 = (Element) element1.clone();
749         cache.putQuiet(clonedElement1);
750         element1 = cache.getQuiet("key1");
751         assertEquals("last access time should be unchanged",
752                 lastAccessedElement1, element1.getLastAccessTime());
753         assertEquals("hit count should be unchanged",
754                 hitCountElement1, element1.getHitCount());
755         element1 = cache.get("key1");
756         assertEquals("Should be two", 2, element1.getHitCount());
757     }
758 
759     /**
760      * Test size with put and remove.
761      * <p/>
762      * It checks that size makes sense, and also that getKeys.size() matches getSize()
763      */
764     public void testSizeWithPutAndRemove() throws Exception {
765         //Set size so the second element overflows to disk.
766         Cache cache = new Cache("test2", 1, true, true, 0, 0);
767         manager.addCache(cache);
768         cache.put(new Element("key1", "value1"));
769         cache.put(new Element("key2", "value1"));
770         int sizeFromGetSize = cache.getSize();
771         int sizeFromKeys = cache.getKeys().size();
772         assertEquals(sizeFromGetSize, sizeFromKeys);
773         assertEquals(2, cache.getSize());
774         cache.put(new Element("key1", "value1"));
775         cache.put(new Element("key1", "value1"));
776 
777         //key1 should be in the Disk Store
778         assertEquals(cache.getSize(), cache.getKeys().size());
779         assertEquals(2, cache.getSize());
780         //there were two of these, so size will now be one
781         cache.remove("key1");
782         assertEquals(cache.getSize(), cache.getKeys().size());
783         assertEquals(1, cache.getSize());
784         cache.remove("key2");
785         assertEquals(cache.getSize(), cache.getKeys().size());
786         assertEquals(0, cache.getSize());
787 
788         //try null values
789         cache.put(new Element("nullValue1", null));
790         cache.put(new Element("nullValue2", null));
791         //Cannot overflow therefore just one
792         assertEquals(1, cache.getSize());
793         Element nullValueElement = cache.get("nullValue2");
794         assertNull(nullValueElement.getValue());
795         assertNull(nullValueElement.getObjectValue());
796 
797     }
798 
799     /**
800      * Test getKeys after expiry
801      * <p/>
802      * Makes sure that if an element is expired, its key should also be expired
803      */
804     public void testGetKeysAfterExpiry() throws Exception {
805         //Set size so the second element overflows to disk.
806         Cache cache = new Cache("test2", 1, true, false, 1, 0);
807         manager.addCache(cache);
808         String key1 = "key1";
809         cache.put(new Element(key1, "value1"));
810         cache.put(new Element("key2", "value1"));
811         //getSize uses getKeys().size(), so these should be the same
812         assertEquals(cache.getSize(), cache.getKeys().size());
813         //getKeys does not do an expiry check, so the expired elements are counted
814         assertEquals(2, cache.getSize());
815         String keyFromDisk = (String) cache.get(key1).getObjectKey();
816         assertTrue(key1 == keyFromDisk);
817         Thread.sleep(1050);
818         assertEquals(2, cache.getKeys().size());
819         //getKeysWithExpiryCheck does check and gives the correct answer of 0
820         assertEquals(0, cache.getKeysWithExpiryCheck().size());
821     }
822 
823 
824     /**
825      * Answers the question of whether key references are preserved as elements are written to disk.
826      * This is not a mandatory part of the API. If this test breaks in future it should be removed.
827      */
828     public void testKeysEqualsEquals() throws Exception {
829         //Set size so the second element overflows to disk.
830         Cache cache = new Cache("test2", 0, true, false, 1, 0);
831         manager.addCache(cache);
832         String key1 = "key1";
833         cache.put(new Element(key1, "value1"));
834         cache.put(new Element("key2", "value1"));
835         String keyFromDisk = (String) cache.get(key1).getObjectKey();
836         assertTrue(key1 == keyFromDisk);
837     }
838 
839     /**
840      * Test size after multiple calls, with put and remove
841      */
842     public void testSizeMultipleCallsWithPutAndRemove() throws Exception {
843         //Set size so the second element overflows to disk.
844         Cache cache = new Cache("test3", 1, true, true, 0, 0);
845         manager.addCache(cache);
846         cache.put(new Element("key1", "value1"));
847         cache.put(new Element("key2", "value1"));
848 
849         //key1 should be in the Disk Store
850         assertEquals(2, cache.getSize());
851         assertEquals(2, cache.getSize());
852         assertEquals(2, cache.getSize());
853         assertEquals(2, cache.getSize());
854         assertEquals(2, cache.getSize());
855         cache.remove("key1");
856         assertEquals(1, cache.getSize());
857         assertEquals(1, cache.getSize());
858         assertEquals(1, cache.getSize());
859         assertEquals(1, cache.getSize());
860         assertEquals(1, cache.getSize());
861         cache.remove("key2");
862         assertEquals(0, cache.getSize());
863         assertEquals(0, cache.getSize());
864         assertEquals(0, cache.getSize());
865         assertEquals(0, cache.getSize());
866         assertEquals(0, cache.getSize());
867     }
868 
869     /**
870      * Checks the expense of checking for duplicates
871      * Typical Results Duplicate Check: 8ms versus 3ms for No Duplicate Check
872      * <p/>
873      * 66ms for 1000, 6ms for no duplicate/expiry
874      * 187565 for 100000, where 500 is the in-memory size. 964ms without checking expiry. 134ms for getKeysNoDuplicateCheckTime
875      * 18795 for 100000, where 50000 is in-memory size. 873ms without checking expiry. 158ms for getKeysNoDuplicateCheckTime
876      */
877     public void testGetKeysPerformance() throws Exception {
878         //Set size so the second element overflows to disk.
879         Ehcache cache = createTestCache();
880 
881         for (int i = 0; i < 2000; i++) {
882             cache.put(new Element("key" + i, "value"));
883         }
884         //let the notifiers cool down
885         Thread.sleep(1000);
886         StopWatch stopWatch = new StopWatch();
887         List keys = cache.getKeys();
888         assertTrue("Should be 2000 keys. ", keys.size() == 2000);
889         long getKeysTime = stopWatch.getElapsedTime();
890         cache.getKeysNoDuplicateCheck();
891         long getKeysNoDuplicateCheckTime = stopWatch.getElapsedTime();
892         LOG.info("Time to get 1000 keys: With Duplicate Check: " + getKeysTime
893                 + " Without Duplicate Check: " + getKeysNoDuplicateCheckTime);
894         assertTrue("Getting keys took more than 150ms", getKeysTime < 100);
895     }
896 
897     /**
898      * Checks the expense of checking in-memory size
899      * 3467890 bytes in 1601ms for JDK1.4.2
900      */
901     public void testCalculateInMemorySizePerformanceAndReasonableness() throws Exception {
902         //Set size so the second element overflows to disk.
903         Ehcache cache = createTestCache();
904 
905         //Set up object graphs
906         for (int i = 0; i < 1000; i++) {
907             HashMap map = new HashMap(100);
908             for (int j = 0; j < 100; j++) {
909                 map.put("key" + j, new String[]{"adfdafs", "asdfdsafa", "sdfasdf"});
910             }
911             cache.put(new Element("key" + i, map));
912         }
913 
914         StopWatch stopWatch = new StopWatch();
915         long size = cache.calculateInMemorySize();
916         assertTrue("Size is " + size + ". Check it for reasonableness.", size > 100000 && size < 5000000);
917         long elapsed = stopWatch.getElapsedTime();
918         LOG.info("In-memory size in bytes: " + size
919                 + " time to calculate in ms: " + elapsed);
920         assertTrue("Calculate memory size takes less than 3.5 seconds", elapsed < 3500);
921     }
922 
923 
924     /**
925      * Expire elements and verify size is correct.
926      */
927     public void testGetSizeAfterExpiry() throws Exception {
928         //Set size so the second element overflows to disk.
929         Cache cache = new Cache("test", 1, true, false, 1, 0);
930         manager.addCache(cache);
931         cache.put(new Element("key1", "value1"));
932         cache.put(new Element("key2", "value1"));
933 
934         //Let the idle expire
935         Thread.sleep(1020);
936         assertEquals(null, cache.get("key1"));
937         assertEquals(null, cache.get("key2"));
938 
939         assertEquals(0, cache.getSize());
940     }
941 
942     /**
943      * Test create and access times
944      */
945     public void testAccessTimes() throws Exception {
946         //Set size so the second element overflows to disk.
947         Cache cache = new Cache("test", 5, true, false, 5, 2);
948         assertEquals(Status.STATUS_UNINITIALISED, cache.getStatus());
949         manager.addCache(cache);
950         Element newElement = new Element("key1", "value1");
951         long creationTime = newElement.getCreationTime();
952         assertTrue(newElement.getCreationTime() > (System.currentTimeMillis() - 500));
953         assertTrue(newElement.getHitCount() == 0);
954         assertTrue(newElement.getLastAccessTime() == 0);
955 
956         cache.put(newElement);
957 
958         Element element = cache.get("key1");
959         assertNotNull(element);
960         assertEquals(creationTime, element.getCreationTime());
961         assertTrue(element.getLastAccessTime() != 0);
962         assertTrue(element.getHitCount() == 1);
963 
964         //Check that access statistics were reset but not creation time
965         cache.put(element);
966         element = cache.get("key1");
967         assertEquals(creationTime, element.getCreationTime());
968         assertTrue(element.getLastAccessTime() != 0);
969         assertTrue(element.getHitCount() == 1);
970     }
971 
972     /**
973      * Tests initialisation failures
974      */
975     public void testInitialiseFailures() {
976         try {
977             Cache cache = new Cache("testInitialiseFailures2", 1, false, false, 5, 1);
978             cache.initialise();
979 
980             cache.initialise();
981             fail("Should have thrown IllegalArgumentException");
982         } catch (IllegalStateException e) {
983             //noop
984         }
985     }
986 
987     /**
988      * Tests putting nulls throws correct exception
989      *
990      * @throws Exception
991      */
992     public void testPutFailures() throws Exception {
993         Cache cache = new Cache("testPutFailures", 1, false, false, 5, 1);
994         manager.addCache(cache);
995 
996         try {
997             cache.put(null);
998             fail("Should have thrown IllegalArgumentException");
999         } catch (IllegalArgumentException e) {
1000             //noop
1001         }
1002 
1003         try {
1004             cache.putQuiet(null);
1005             fail("Should have thrown IllegalArgumentException");
1006         } catch (IllegalArgumentException e) {
1007             //noop
1008         }
1009 
1010         //Null Elements like this are OK
1011         cache.putQuiet(new Element(null, null));
1012     }
1013 
1014     /**
1015      * Tests cache, memory store and disk store sizes from config
1016      */
1017     public void testSizes() throws Exception {
1018         Ehcache cache = getSampleCache1();
1019 
1020         assertEquals(0, cache.getMemoryStoreSize());
1021 
1022         for (int i = 0; i < 10010; i++) {
1023             cache.put(new Element("key" + i, "value1"));
1024         }
1025         assertEquals(10010, cache.getSize());
1026         assertEquals(10000, cache.getMemoryStoreSize());
1027         assertEquals(10, cache.getDiskStoreSize());
1028 
1029         //NonSerializable
1030         cache.put(new Element(new Object(), Object.class));
1031 
1032         assertEquals(10011, cache.getSize());
1033         assertEquals(10000, cache.getMemoryStoreSize());
1034         assertEquals(11, cache.getDiskStoreSize());
1035 
1036 
1037         cache.remove("key4");
1038         cache.remove("key3");
1039 
1040         assertEquals(10009, cache.getSize());
1041         assertEquals(10000, cache.getMemoryStoreSize());
1042         assertEquals(9, cache.getDiskStoreSize());
1043 
1044 
1045         cache.removeAll();
1046         assertEquals(0, cache.getSize());
1047         assertEquals(0, cache.getMemoryStoreSize());
1048         assertEquals(0, cache.getDiskStoreSize());
1049 
1050     }
1051 
1052     /**
1053      * Tests flushing the cache
1054      *
1055      * @throws Exception
1056      */
1057     public void testFlushWhenOverflowToDisk() throws Exception {
1058         Cache cache = new Cache("testGetMemoryStoreSize", 50, true, false, 100, 200);
1059         manager.addCache(cache);
1060 
1061         assertEquals(0, cache.getMemoryStoreSize());
1062 
1063         for (int i = 0; i < 100; i++) {
1064             cache.put(new Element("" + i, new Date()));
1065         }
1066         //Not spoolable, should get ignored
1067         cache.put(new Element("key", new Object()));
1068         cache.put(new Element(new Object(), new Object()));
1069         cache.put(new Element(new Object(), "value"));
1070 
1071         //these "null" Elements are keyed the same way and only count as one
1072         cache.put(new Element(null, null));
1073         cache.put(new Element(null, null));
1074 
1075         cache.put(new Element("nullValue", null));
1076 
1077         assertEquals(50, cache.getMemoryStoreSize());
1078         assertEquals(55, cache.getDiskStoreSize());
1079 
1080         cache.flush();
1081         assertEquals(0, cache.getMemoryStoreSize());
1082         //Non Serializable Elements gets discarded
1083         assertEquals(100, cache.getDiskStoreSize());
1084 
1085     }
1086 
1087 
1088     /**
1089      * When flushing large MemoryStores, OutOfMemory issues can happen if we are
1090      * not careful to move each to Element to the DiskStore, rather than copy them all
1091      * and then delete them from the MemoryStore.
1092      * <p/>
1093      * This test manipulates a MemoryStore right on the edge of what can fit into the 64MB standard VM size.
1094      * An inefficient spool will cause an OutOfMemoryException.
1095      *
1096      * @throws Exception
1097      */
1098     public void testMemoryEfficiencyOfFlushWhenOverflowToDisk() throws Exception {
1099         Cache cache = new Cache("testGetMemoryStoreSize", 40000, true, false, 100, 200);
1100         manager.addCache(cache);
1101 
1102         assertEquals(0, cache.getMemoryStoreSize());
1103 
1104         for (int i = 0; i < 80000; i++) {
1105             cache.put(new Element("" + i, new byte[480]));
1106         }
1107 
1108         assertEquals(40000, cache.getMemoryStoreSize());
1109         assertEquals(40000, cache.getDiskStoreSize());
1110 
1111         long beforeMemory = measureMemoryUse();
1112         cache.flush();
1113 
1114         //It takes a while to write all the Elements to disk
1115         Thread.sleep(5000);
1116 
1117         long afterMemory = measureMemoryUse();
1118         long memoryIncrease = afterMemory - beforeMemory;
1119         assertTrue(memoryIncrease < 40000000);
1120 
1121         assertEquals(0, cache.getMemoryStoreSize());
1122         assertEquals(80000, cache.getDiskStoreSize());
1123 
1124     }
1125 
1126     /**
1127      * Shows the effect of jamming large amounts of puts into a cache that overflows to disk.
1128      * The DiskStore should cause puts to back off and avoid an out of memory error.
1129      */
1130     public void testBehaviourOnDiskStoreBackUp() throws Exception {
1131         Cache cache = new Cache("testGetMemoryStoreSize", 10, true, false, 100, 200, false, 0);
1132         manager.addCache(cache);
1133 
1134         assertEquals(0, cache.getMemoryStoreSize());
1135 
1136         Element a = null;
1137         int i = 0;
1138         try {
1139             for (; i < 200000; i++) {
1140                 String key = i + "";
1141                 String value = key;
1142                 a = new Element(key, value + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
1143                 cache.put(a);
1144             }
1145         } catch (OutOfMemoryError e) {
1146             LOG.info("OutOfMemoryError: " + e.getMessage() + " " + i);
1147             fail();
1148         }
1149     }
1150 
1151 
1152     /**
1153      * Tests using elements with null values. They should work as normal.
1154      *
1155      * @throws Exception
1156      */
1157     public void testElementWithNullValue() throws Exception {
1158         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 100, 200);
1159         manager.addCache(cache);
1160 
1161         Object key1 = new Object();
1162         Element element = new Element(key1, null);
1163         cache.put(element);
1164         assertNotNull(cache.get(key1));
1165         assertNotNull(cache.getQuiet(key1));
1166         assertSame(element, cache.get(key1));
1167         assertSame(element, cache.getQuiet(key1));
1168         assertNull(cache.get(key1).getObjectValue());
1169         assertNull(cache.getQuiet(key1).getObjectValue());
1170 
1171         assertEquals(false, cache.isExpired(element));
1172     }
1173 
1174 
1175     /**
1176      * Tests put works correctly for Elements with overriden TTL
1177      *
1178      * @throws Exception
1179      */
1180     public void testPutWithOverriddenTTLAndTTI() throws Exception {
1181         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 1, 1);
1182         manager.addCache(cache);
1183 
1184         Object key = new Object();
1185         Element element = new Element(key, "value");
1186         element.setTimeToLive(2);
1187         cache.put(element);
1188         Thread.sleep(1050);
1189         assertNotNull(cache.get(key));
1190         assertSame(element, cache.get(key));
1191 
1192 
1193         Element element2 = new Element(key, "value");
1194         cache.put(element2);
1195         Thread.sleep(1050);
1196         assertNull(cache.get(key));
1197 
1198         Element element3 = new Element(key, "value");
1199         element3.setTimeToLive(2);
1200         cache.put(element3);
1201         Thread.sleep(1500);
1202         assertSame(element3, cache.get(key));
1203 
1204     }
1205 
1206 
1207     /**
1208      * Tests putQuiet works correctly for Elements with overriden TTL
1209      *
1210      * @throws Exception
1211      */
1212     public void testPutQuietWithOverriddenTTLAndTTI() throws Exception {
1213         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 1, 1);
1214         manager.addCache(cache);
1215 
1216         Object key = new Object();
1217         Element element = new Element(key, "value");
1218         element.setTimeToLive(2);
1219         cache.putQuiet(element);
1220         Thread.sleep(1050);
1221         assertNotNull(cache.get(key));
1222         assertSame(element, cache.get(key));
1223 
1224 
1225         Element element2 = new Element(key, "value");
1226         cache.putQuiet(element2);
1227         Thread.sleep(1050);
1228         assertNull(cache.get(key));
1229 
1230         Element element3 = new Element(key, "value");
1231         element3.setTimeToLive(2);
1232         cache.putQuiet(element3);
1233         Thread.sleep(1500);
1234         assertSame(element3, cache.get(key));
1235 
1236     }
1237 
1238 
1239     /**
1240      * Tests using elements with null values. They should work as normal.
1241      *
1242      * @throws Exception
1243      */
1244     public void testNonSerializableElement() throws Exception {
1245         Cache cache = new Cache("testElementWithNonSerializableValue", 1, true, false, 100, 200);
1246         manager.addCache(cache);
1247 
1248         Element element1 = new Element("key1", new Object());
1249         Element element2 = new Element("key2", new Object());
1250         cache.put(element1);
1251         cache.put(element2);
1252 
1253         //Removed because could not overflow
1254         assertNull(cache.get("key1"));
1255 
1256         //Second one should be in the MemoryStore and retrievable
1257         assertNotNull(cache.get("key2"));
1258     }
1259 
1260 
1261     /**
1262      * Tests what happens when an Element throws an Error on serialization. This mimics
1263      * what a nasty error like OutOfMemoryError could do.
1264      * <p/>
1265      * Before a change to the SpoolAndExpiryThread to handle this situation this test failed and generated the following log message.
1266      * Jun 28, 2006 7:17:16 PM net.sf.ehcache.store.DiskStore put
1267      * SEVERE: testThreadKillerCache: Elements cannot be written to disk store because the spool thread has died.
1268      *
1269      * @throws Exception
1270      */
1271     public void testSpoolThreadHandlesThreadKiller() throws Exception {
1272         Cache cache = new Cache("testThreadKiller", 1, true, false, 100, 200);
1273         manager.addCache(cache);
1274 
1275         Element elementThreadKiller = new Element("key", new ThreadKiller());
1276         cache.put(elementThreadKiller);
1277         Element element1 = new Element("key1", "one");
1278         Element element2 = new Element("key2", "two");
1279         cache.put(element1);
1280         cache.put(element2);
1281 
1282         Thread.sleep(2000);
1283 
1284         assertNotNull(cache.get("key1"));
1285         assertNotNull(cache.get("key2"));
1286     }
1287 
1288     /**
1289      * Tests disk store and memory store size
1290      *
1291      * @throws Exception
1292      */
1293     public void testGetDiskStoreSize() throws Exception {
1294         Cache cache = new Cache("testGetDiskStoreSize", 1, true, false, 100, 200);
1295         manager.addCache(cache);
1296         assertEquals(0, cache.getDiskStoreSize());
1297 
1298         cache.put(new Element("key1", "value1"));
1299         assertEquals(0, cache.getDiskStoreSize());
1300         assertEquals(1, cache.getSize());
1301 
1302         cache.put(new Element("key2", "value2"));
1303         assertEquals(2, cache.getSize());
1304         assertEquals(1, cache.getDiskStoreSize());
1305         assertEquals(1, cache.getMemoryStoreSize());
1306 
1307         cache.put(new Element("key3", "value3"));
1308         cache.put(new Element("key4", "value4"));
1309         assertEquals(4, cache.getSize());
1310         assertEquals(3, cache.getDiskStoreSize());
1311         assertEquals(1, cache.getMemoryStoreSize());
1312 
1313         // remove last element inserted (is in memory store)
1314         assertNotNull(cache.getMemoryStore().get("key4"));
1315         cache.remove("key4");
1316         assertEquals(3, cache.getSize());
1317         assertEquals(3, cache.getDiskStoreSize());
1318         assertEquals(0, cache.getMemoryStoreSize());
1319 
1320         // remove key1 element
1321         assertNotNull(cache.getDiskStore().get("key1"));
1322         cache.remove("key1");
1323         assertEquals(2, cache.getSize());
1324         assertEquals(2, cache.getDiskStoreSize());
1325         assertEquals(0, cache.getMemoryStoreSize());
1326 
1327         // add another
1328         cache.put(new Element("key5", "value5"));
1329         assertEquals(3, cache.getSize());
1330         assertEquals(2, cache.getDiskStoreSize());
1331         assertEquals(1, cache.getMemoryStoreSize());
1332 
1333         // remove all
1334         cache.removeAll();
1335         assertEquals(0, cache.getSize());
1336         assertEquals(0, cache.getDiskStoreSize());
1337         assertEquals(0, cache.getMemoryStoreSize());
1338 
1339         //Check behaviour of NonSerializable objects
1340         cache.put(new Element(new Object(), new Object()));
1341         cache.put(new Element(new Object(), new Object()));
1342         cache.put(new Element(new Object(), new Object()));
1343         assertEquals(1, cache.getSize());
1344         assertEquals(0, cache.getDiskStoreSize());
1345         assertEquals(1, cache.getMemoryStoreSize());
1346 
1347     }
1348 
1349     /**
1350      * Tests that attempting to clone a cache fails with the right exception.
1351      *
1352      * @throws Exception
1353      */
1354     public void testCloneFailures() throws Exception {
1355         Cache cache = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1356         manager.addCache(cache);
1357         try {
1358             cache.clone();
1359             fail("Should have thrown CloneNotSupportedException");
1360         } catch (CloneNotSupportedException e) {
1361             //noop
1362         }
1363     }
1364 
1365 
1366     /**
1367      * Tests that the toString() method works.
1368      */
1369     public void testToString() {
1370         Ehcache cache = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1371         assertTrue(cache.toString().indexOf("testGetMemoryStore") > -1);
1372         assertEquals(410, cache.toString().length());
1373     }
1374 
1375 
1376     /**
1377      * When does equals mean the same thing as == ?
1378      *
1379      * @throws CacheException
1380      * @throws InterruptedException
1381      */
1382     public void testEquals() throws CacheException, InterruptedException {
1383         Cache cache = new Cache("cache", 1, true, false, 100, 200, false, 1);
1384         manager.addCache(cache);
1385 
1386         Element element1 = new Element("1", new Date());
1387         Element element2 = new Element("2", new Date());
1388         cache.put(element1);
1389         cache.put(element2);
1390 
1391         //Test equals and == from an Element retrieved from the MemoryStore
1392         Element elementFromStore = cache.get("2");
1393         assertEquals(element2, elementFromStore);
1394         assertTrue(element2 == elementFromStore);
1395 
1396         //Give the spool a chance to make sure it really got serialized to Disk
1397         Thread.sleep(300);
1398 
1399         //Test equals and == from an Element retrieved from the MemoryStore
1400         Element elementFromDiskStore = cache.get("1");
1401         assertEquals(element1, elementFromDiskStore);
1402         assertTrue(element1 != elementFromDiskStore);
1403     }
1404 
1405     /**
1406      * Tests the uniqueness of the GUID
1407      */
1408     public void testGuid() {
1409         Ehcache cache1 = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1410         Ehcache cache2 = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1411         String guid1 = cache1.getGuid();
1412         String guid2 = cache2.getGuid();
1413         assertEquals(cache1.getName(), cache2.getName());
1414         assertTrue(!guid1.equals(guid2));
1415 
1416     }
1417 
1418 
1419     /**
1420      * Does the Object API work?
1421      */
1422     public void testAPIObjectCompatibility() {
1423         Cache cache = new Cache("test", 5, true, false, 5, 2);
1424         manager.addCache(cache);
1425 
1426         Object objectKey = new Object();
1427         Object objectValue = new Object();
1428         Element objectElement = new Element(objectKey, objectValue);
1429         cache.put(objectElement);
1430 
1431         //Cannot get it back using get
1432         Element retrievedElement = cache.get(objectKey);
1433         assertNotNull(retrievedElement);
1434         try {
1435             retrievedElement.getObjectValue();
1436         } catch (CacheException e) {
1437             //expected
1438         }
1439 
1440         //Test that equals works
1441         retrievedElement = cache.get(objectKey);
1442         assertEquals(objectElement, retrievedElement);
1443 
1444         //Can with getObjectValue
1445         retrievedElement = cache.get(objectKey);
1446         assertEquals(objectValue, retrievedElement.getObjectValue());
1447 
1448     }
1449 
1450 
1451     /**
1452      * Does the Serializable API work?
1453      */
1454     public void testAPISerializableCompatibility() {
1455         Cache cache = new Cache("test", 5, true, false, 5, 2);
1456         manager.addCache(cache);
1457 
1458         //Try object compatibility
1459         Serializable key = new String();
1460         Element objectElement = new Element(key, new String());
1461         cache.put(objectElement);
1462         Object retrievedObject = cache.get(key);
1463         assertEquals(retrievedObject, objectElement);
1464 
1465         //Test that equals works
1466         assertEquals(objectElement, retrievedObject);
1467     }
1468 
1469     /**
1470      * Test issues reported.
1471      */
1472     public void testDiskStoreFlorian() {
1473         manager.shutdown();
1474 
1475         byte[] config = ("<ehcache> \n" +
1476                 "<diskStore path=\"java.io.tmpdir\"/> \n" +
1477                 "<defaultCache \n" +
1478                 "            maxElementsInMemory=\"10000\" \n" +
1479                 "            eternal=\"false\" \n" +
1480                 "            timeToIdleSeconds=\"120\" \n" +
1481                 "            timeToLiveSeconds=\"120\" \n" +
1482                 "            overflowToDisk=\"true\" \n" +
1483                 "            diskPersistent=\"false\" \n" +
1484                 "            diskExpiryThreadIntervalSeconds=\"120\" \n" +
1485                 "            memoryStoreEvictionPolicy=\"LRU\" \n" +
1486                 "            /> " +
1487                 "\n" +
1488                 "<cache name=\"testCache\" \n" +
1489                 "       maxElementsInMemory=\"20000\" \n" +
1490                 "       eternal=\"false\" \n" +
1491                 "       overflowToDisk=\"false\" \n" +
1492                 "       timeToIdleSeconds=\"300\" \n" +
1493                 "       timeToLiveSeconds=\"600\" \n" +
1494                 "       diskPersistent=\"false\" \n" +
1495                 "       diskExpiryThreadIntervalSeconds=\"1\" \n" +
1496                 "       memoryStoreEvictionPolicy=\"LFU\" \n" +
1497                 "/>           \n" +
1498                 "<cache name=\"test2Cache\" \n" +
1499                 "       maxElementsInMemory=\"20000\" \n" +
1500                 "       eternal=\"false\" \n" +
1501                 "       overflowToDisk=\"true\" \n" +
1502                 "       timeToIdleSeconds=\"300\" \n" +
1503                 "       timeToLiveSeconds=\"600\" \n" +
1504                 "       diskPersistent=\"false\" \n" +
1505                 "       diskExpiryThreadIntervalSeconds=\"1\" \n" +
1506                 "       memoryStoreEvictionPolicy=\"LFU\" \n" +
1507                 "/> \n" +
1508                 "</ehcache> ").getBytes();
1509 
1510 
1511         CacheManager cacheManager = new CacheManager(new ByteArrayInputStream(config));
1512         Cache cache = new Cache("test3cache", 20000, true, false, 50, 30);
1513         assertTrue(cache.isOverflowToDisk());
1514         cacheManager.addCache(cache);
1515 
1516         for (int i = 0; i < 25000; i++) {
1517             cache.put(new Element(i + "", "value"));
1518         }
1519 
1520         assertEquals(5000, cache.getDiskStoreSize());
1521     }
1522 
1523 
1524     /**
1525      * Multi-thread read-write test with 20 threads
1526      * Just use MemoryStore to put max stress on cache
1527      * Values that work:
1528      * <pre>
1529      * size     threads     maxTime
1530      * 10000    50          200
1531      * 200000   50          500
1532      * 200000   500         800
1533      * </pre>
1534      */
1535     public void testReadWriteThreads() throws Exception {
1536 
1537         final int size = 10000;
1538         final int maxTime = (int) (400 * StopWatch.getSpeedAdjustmentFactor());
1539         final Cache cache = new Cache("test3cache", size, false, true, 30, 30);
1540         manager.addCache(cache);
1541 
1542         long start = System.currentTimeMillis();
1543         final List executables = new ArrayList();
1544         final Random random = new Random();
1545 
1546         for (int i = 0; i < size; i++) {
1547             cache.put(new Element("" + i, "value"));
1548         }
1549 
1550         // 50% of the time get data
1551         for (int i = 0; i < 30; i++) {
1552             final Executable executable = new Executable() {
1553                 public void execute() throws Exception {
1554                     final StopWatch stopWatch = new StopWatch();
1555                     long start = stopWatch.getElapsedTime();
1556                     cache.get("key" + random.nextInt(size));
1557                     long end = stopWatch.getElapsedTime();
1558                     long elapsed = end - start;
1559                     assertTrue("Get time outside of allowed range: " + elapsed, elapsed < maxTime);
1560                 }
1561             };
1562             executables.add(executable);
1563         }
1564 
1565         //25% of the time add data
1566         for (int i = 0; i < 10; i++) {
1567             final Executable executable = new Executable() {
1568                 public void execute() throws Exception {
1569                     final StopWatch stopWatch = new StopWatch();
1570                     long start = stopWatch.getElapsedTime();
1571                     cache.put(new Element("key" + random.nextInt(size), "value"));
1572                     long end = stopWatch.getElapsedTime();
1573                     long elapsed = end - start;
1574                     assertTrue("Put time outside of allowed range: " + elapsed, elapsed < maxTime);
1575                 }
1576             };
1577             executables.add(executable);
1578         }
1579 
1580         //25% of the time remove the data
1581         for (int i = 0; i < 10; i++) {
1582             final Executable executable = new Executable() {
1583                 public void execute() throws Exception {
1584                     final StopWatch stopWatch = new StopWatch();
1585                     long start = stopWatch.getElapsedTime();
1586                     cache.remove("key" + random.nextInt(size));
1587                     long end = stopWatch.getElapsedTime();
1588                     long elapsed = end - start;
1589                     assertTrue("Remove time outside of allowed range: " + elapsed, elapsed < maxTime);
1590                 }
1591             };
1592             executables.add(executable);
1593         }
1594 
1595         //some of the time remove the data
1596         for (int i = 0; i < 10; i++) {
1597             final Executable executable = new Executable() {
1598                 public void execute() throws Exception {
1599                     final StopWatch stopWatch = new StopWatch();
1600                     long start = stopWatch.getElapsedTime();
1601                     int randomInteger = random.nextInt(20);
1602                     if (randomInteger == 3) {
1603                         cache.removeAll();
1604                     }
1605                     long end = stopWatch.getElapsedTime();
1606                     long elapsed = end - start;
1607                     //remove all is slower
1608                     assertTrue("RemoveAll time outside of allowed range: " + elapsed, elapsed < (maxTime * 3));
1609                 }
1610             };
1611             executables.add(executable);
1612         }
1613 
1614         runThreads(executables);
1615         long end = System.currentTimeMillis();
1616         LOG.info("Total time for the test: " + (end - start) + " ms");
1617     }
1618 
1619 
1620     /**
1621      * Tests added from 1606323 Elements not stored in memory or on disk. This was supposedly
1622      * a bug but works.
1623      * This test passes.
1624      *
1625      * @throws Exception
1626      */
1627     public void testTimeToLive15552000() throws Exception {
1628         long timeToLiveSeconds = 15552000;
1629         doRunTest(timeToLiveSeconds);
1630     }
1631 
1632     /**
1633      * This test passes.
1634      *
1635      * @throws Exception
1636      */
1637     public void testTimeToLive604800() throws Exception {
1638         long timeToLiveSeconds = 604800;
1639         doRunTest(timeToLiveSeconds);
1640     }
1641 
1642     private void doRunTest(long timeToLiveSeconds) {
1643         String name = "memoryAndDiskCache";
1644         int maxElementsInMemory = 1000;
1645         MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = MemoryStoreEvictionPolicy.LRU;
1646         boolean overflowToDisk = true;
1647         String diskStorePath = "java.io.tmp.dir/cache";
1648         boolean eternal = false;
1649         long timeToIdleSeconds = 0;
1650         boolean diskPersistent = true;
1651         long diskExpiryThreadIntervalSeconds = 3600;
1652         RegisteredEventListeners registeredEventListeners = null;
1653         BootstrapCacheLoader bootstrapCacheLoader = null;
1654 
1655         Cache memoryAndDisk = new Cache(
1656                 name,
1657                 maxElementsInMemory,
1658                 memoryStoreEvictionPolicy,
1659                 overflowToDisk,
1660                 diskStorePath,
1661                 eternal,
1662                 timeToLiveSeconds,
1663                 timeToIdleSeconds,
1664                 diskPersistent,
1665                 diskExpiryThreadIntervalSeconds,
1666                 registeredEventListeners,
1667                 bootstrapCacheLoader);
1668 
1669         this.manager.addCache(memoryAndDisk);
1670 
1671         String key = "test";
1672         Object value = new Object();
1673 
1674         memoryAndDisk.put(new Element(key, value));
1675 
1676         assertTrue(memoryAndDisk.isElementInMemory(key));
1677     }
1678 
1679     /**
1680      * Tests get from a finalize method, following a mailing list post from Felix Satyaputr
1681      *
1682      * @throws InterruptedException
1683      */
1684     public void testGetQuietFromFinalize() throws InterruptedException {
1685 
1686 
1687         final Cache cache = new Cache("test", 1, true, false, 5, 2);
1688         manager.addCache(cache);
1689 
1690         cache.put(new Element("key", "value"));
1691         cache.put(new Element("key2", "value"));
1692         cache.put(new Element("key3", "value"));
1693         cache.put(new Element("key4", "value"));
1694         cache.put(new Element("key5", "value"));
1695 
1696         //wait for overflow to kick in
1697         Thread.sleep(200);
1698 
1699         createTestObject();
1700 
1701         //try to get object finalized
1702         System.gc();
1703         Thread.sleep(200);
1704         System.gc();
1705 
1706 
1707     }
1708 
1709     private void createTestObject() {
1710         new TestObject();
1711     }
1712 
1713 
1714     /**
1715      * A class with a finalize implementation.
1716      */
1717     class TestObject {
1718 
1719         /**
1720          * Override the Object finalize method
1721          */
1722         protected void finalize() throws Throwable {
1723             manager.getCache("test").getQuiet("key");
1724             LOG.info("finalize run from thread " + Thread.currentThread().getName());
1725             super.finalize();
1726         }
1727     }
1728 
1729 
1730 }