View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache;
18  
19  import static java.util.concurrent.TimeUnit.SECONDS;
20  import static junit.framework.Assert.assertSame;
21  import static org.hamcrest.CoreMatchers.equalTo;
22  import static org.hamcrest.CoreMatchers.is;
23  import static org.hamcrest.CoreMatchers.not;
24  import static org.hamcrest.CoreMatchers.sameInstance;
25  import static org.hamcrest.number.OrderingComparison.lessThanOrEqualTo;
26  import static org.junit.Assert.assertEquals;
27  import static org.junit.Assert.assertFalse;
28  import static org.junit.Assert.assertNotNull;
29  import static org.junit.Assert.assertNull;
30  import static org.junit.Assert.assertThat;
31  import static org.junit.Assert.assertTrue;
32  import static org.junit.Assert.fail;
33  
34  import java.beans.PropertyChangeEvent;
35  import java.beans.PropertyChangeListener;
36  import java.beans.PropertyChangeSupport;
37  import java.io.ByteArrayInputStream;
38  import java.io.Serializable;
39  import java.lang.reflect.Field;
40  import java.util.ArrayList;
41  import java.util.Arrays;
42  import java.util.Collection;
43  import java.util.Date;
44  import java.util.HashMap;
45  import java.util.HashSet;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Random;
49  import java.util.Set;
50  import java.util.concurrent.Callable;
51  import java.util.concurrent.ExecutionException;
52  import java.util.concurrent.ExecutorService;
53  import java.util.concurrent.Executors;
54  import java.util.concurrent.Future;
55  import java.util.concurrent.TimeUnit;
56  import java.util.concurrent.atomic.AtomicBoolean;
57  
58  import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
59  import net.sf.ehcache.config.CacheConfiguration;
60  import net.sf.ehcache.event.CacheEventListener;
61  import net.sf.ehcache.event.RegisteredEventListeners;
62  import net.sf.ehcache.loader.CacheLoader;
63  import net.sf.ehcache.loader.CountingCacheLoader;
64  import net.sf.ehcache.loader.DelayingLoader;
65  import net.sf.ehcache.loader.ExceptionThrowingLoader;
66  import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
67  import net.sf.ehcache.util.RetryAssert;
68  
69  import org.hamcrest.core.Is;
70  import org.junit.After;
71  import org.junit.Test;
72  import org.slf4j.Logger;
73  import org.slf4j.LoggerFactory;
74  
75  /***
76   * Tests for a Cache
77   * <p/>
78   * Since expiration is rounded on seconds, we need to at least go up to the last
79   * millisecond before the next second in many of the tests
80   *
81   * @author Greg Luck, Claus Ibsen
82   * @version $Id: CacheTest.html 13146 2011-08-01 17:12:39Z oletizi $
83   */
84  public class CacheTest extends AbstractCacheTest {
85  
86      private static final Logger LOG = LoggerFactory.getLogger(CacheTest.class.getName());
87  
88  
89      /***
90       * teardown
91       */
92      @Override
93      @After
94      public void tearDown() throws Exception {
95          super.tearDown();
96      }
97  
98      /***
99       * Gets the sample cache 1
100      */
101     protected Ehcache getSampleCache1() {
102         Cache cache = manager.getCache("sampleCache1");
103         return cache;
104     }
105 
106     /***
107      * Creates a cache
108      *
109      * @return
110      */
111     protected Ehcache createTestCache() {
112         Cache cache = new Cache("test4", 1000, true, true, 0, 0);
113         manager.addCache(cache);
114         return cache;
115     }
116 
117     /***
118      * Checks we cannot use a cache after shutdown
119      */
120     @Test
121     public void testUseCacheAfterManagerShutdown() throws CacheException {
122         Ehcache cache = getSampleCache1();
123         manager.shutdown();
124         Element element = new Element("key", "value");
125         try {
126             cache.getSize();
127             fail();
128         } catch (IllegalStateException e) {
129             assertEquals("The sampleCache1 Cache is not alive (STATUS_SHUTDOWN)", e.getMessage());
130         }
131         try {
132             cache.put(element);
133             fail();
134         } catch (IllegalStateException e) {
135             assertEquals("The sampleCache1 Cache is not alive (STATUS_SHUTDOWN)", e.getMessage());
136         }
137         try {
138             cache.get("key");
139             fail();
140         } catch (IllegalStateException e) {
141             assertEquals("The sampleCache1 Cache is not alive (STATUS_SHUTDOWN)", e.getMessage());
142         }
143 
144     }
145 
146     /***
147      * Test multiple calls to dispose is not a problem
148      */
149     @Test
150     public void testMultipleDispose() {
151         Ehcache cache = new Cache("testCache", 1, true, false, 5, 2);
152         manager.addCache(cache);
153         cache.dispose();
154         // call dispose multiple times, shouldn't throw IllegalStateException anymore
155         for (int i = 0; i < 10; i++) {
156             cache.dispose();
157         }
158     }
159 
160 
161     /***
162      * Checks we cannot use a cache outside the manager
163      */
164     @Test
165     public void testUseCacheOutsideManager() throws CacheException {
166         //Not put into manager.
167         Cache cache = new Cache("testCache", 1, true, false, 5, 2);
168         Element element = new Element("key", "value");
169         try {
170             cache.getSize();
171             fail();
172         } catch (IllegalStateException e) {
173             assertEquals("The testCache Cache is not alive (STATUS_UNINITIALISED)", e.getMessage());
174         }
175         try {
176             cache.put(element);
177             fail();
178         } catch (IllegalStateException e) {
179             assertEquals("The testCache Cache is not alive (STATUS_UNINITIALISED)", e.getMessage());
180         }
181         try {
182             cache.get("key");
183             fail();
184         } catch (IllegalStateException e) {
185             assertEquals("The testCache Cache is not alive (STATUS_UNINITIALISED)", e.getMessage());
186         }
187     }
188 
189     /***
190      * Checks when and how we can set the cache name.
191      */
192     @Test
193     public void testSetCacheName() throws CacheException {
194         //Not put into manager.
195         Ehcache cache = new Cache("testCache", 1, true, false, 5, 2);
196 
197         try {
198             cache.setName(null);
199             fail();
200         } catch (IllegalArgumentException e) {
201             //expected
202         }
203 
204         cache.setName("name/with/slash");
205 
206         manager.addCache(cache);
207         try {
208             cache.setName("trying_to_change_name_after_initialised");
209             fail();
210         } catch (IllegalStateException e) {
211             //expected
212         }
213     }
214 
215 
216     /***
217      * Test using a cache which has been removed and replaced.
218      */
219     @Test
220     public void testStaleCacheReference() throws CacheException {
221         manager.addCache("test");
222         Ehcache cache = manager.getCache("test");
223         assertNotNull(cache);
224         cache.put(new Element("key1", "value1"));
225 
226         assertEquals("value1", cache.get("key1").getObjectValue());
227         manager.removeCache("test");
228         manager.addCache("test");
229 
230         try {
231             cache.get("key1");
232             fail();
233         } catch (IllegalStateException e) {
234             assertEquals("The test Cache is not alive (STATUS_SHUTDOWN)", e.getMessage());
235         }
236     }
237 
238     /***
239      * Tests getting the cache name
240      *
241      * @throws Exception
242      */
243     @Test
244     public void testCacheName() throws Exception {
245         manager.addCache("test");
246         Ehcache cache = manager.getCache("test");
247         assertEquals("test", cache.getName());
248         assertEquals(Status.STATUS_ALIVE, cache.getStatus());
249     }
250 
251 
252     /***
253      * Tests getting the cache name
254      *
255      * @throws Exception
256      */
257     @Test
258     public void testCacheWithNoIdle() throws Exception {
259         Ehcache cache = manager.getCache("sampleCacheNoIdle");
260         assertEquals("sampleCacheNoIdle", cache.getName());
261         assertEquals(Status.STATUS_ALIVE, cache.getStatus());
262         assertEquals(0, cache.getCacheConfiguration().getTimeToIdleSeconds());
263     }
264 
265     /***
266      * Test expiry based on time to live
267      * <cache name="sampleCacheNoIdle"
268      * maxElementsInMemory="1000"
269      * eternal="false"
270      * timeToLiveSeconds="5"
271      * overflowToDisk="false"
272      * />
273      */
274     @Test
275     public void testExpiryBasedOnTimeToLiveWhenNoIdle() throws Exception {
276         //Set size so the second element overflows to disk.
277         Ehcache cache = manager.getCache("sampleCacheNoIdle");
278         cache.put(new Element("key1", "value1"));
279         cache.put(new Element("key2", "value1"));
280         assertNotNull(cache.get("key1"));
281         assertNotNull(cache.get("key2"));
282 
283         //Test time to idle. Should not idle out because not specified
284         Thread.sleep(2999);
285         assertNotNull(cache.get("key1"));
286         assertNotNull(cache.get("key2"));
287 
288         //Test time to live.
289         Thread.sleep(5999);
290         assertNull(cache.get("key1"));
291         assertNull(cache.get("key2"));
292     }
293 
294 
295     /***
296      * Tests that the version and lastUpdate get upped for each put.
297      * <cache name="sampleCacheNoIdle"
298      * maxElementsInMemory="1000"
299      * eternal="false"
300      * timeToLiveSeconds="5"
301      * overflowToDisk="false"
302      * />
303      */
304     @Test
305     public void testLastUpdate() throws Exception {
306         //Set size so the second element overflows to disk.
307         Ehcache cache = manager.getCache("sampleCache1");
308         long beforeElementCreation = System.currentTimeMillis();
309         //put in delay because time resolution is not exact on Windows
310         Thread.sleep(10);
311         cache.put(new Element("key1", "value1"));
312         Element element = cache.get("key1");
313         assertTrue(element.getCreationTime() >= beforeElementCreation);
314         LOG.info("version: " + element.getVersion());
315         LOG.info("creationTime: " + element.getCreationTime());
316         LOG.info("lastUpdateTime: " + element.getLastUpdateTime());
317         assertEquals(0, element.getLastUpdateTime());
318 
319         cache.put(new Element("key1", "value1"));
320         element = cache.get("key1");
321         LOG.info("version: " + element.getVersion());
322         LOG.info("creationTime: " + element.getCreationTime());
323         LOG.info("lastUpdateTime: " + element.getLastUpdateTime());
324 
325         cache.put(new Element("key1", "value1"));
326         element = cache.get("key1");
327         LOG.info("version: " + element.getVersion());
328         LOG.info("creationTime: " + element.getCreationTime());
329         LOG.info("lastUpdateTime: " + element.getLastUpdateTime());
330     }
331 
332 
333     /***
334      * When to search the disk store
335      */
336     @Test
337     public void testOverflowToDiskAndDiskPersistent() throws Exception {
338         Ehcache cache = manager.getCache("sampleIdlingExpiringCache");
339 
340         for (int i = 0; i < 1001; i++) {
341             cache.put(new Element("key" + i, "value1"));
342         }
343 
344         assertNotNull(cache.get("key0"));
345 
346         for (int i = 0; i < 1001; i++) {
347             cache.put(new Element("key" + i, "value1"));
348             assertNotNull(cache.get("key" + i));
349         }
350     }
351 
352 
353     /***
354      * Test expiry based on time to live for a cache with config
355      * <cache name="sampleCacheNoIdle"
356      * maxElementsInMemory="1000"
357      * eternal="false"
358      * timeToLiveSeconds="5"
359      * overflowToDisk="false"
360      * />
361      * <p/>
362      * where an Elment override is set on TTL
363      */
364     @Test
365     public void testExpiryBasedOnTimeToLiveWhenNoIdleElementOverride() throws Exception {
366         //Set size so the second element overflows to disk.
367         Ehcache cache = manager.getCache("sampleCacheNoIdle");
368         Element element1 = new Element("key1", "value1");
369         element1.setTimeToLive(3);
370         cache.put(element1);
371 
372         Element element2 = new Element("key2", "value1");
373         element2.setTimeToLive(3);
374         cache.put(element2);
375         assertNotNull(cache.get("key1"));
376         assertNotNull(cache.get("key2"));
377 
378         //Test time to idle. Should not idle out because not specified
379         Thread.sleep(1999);
380         assertNotNull(cache.get("key1"));
381         assertNotNull(cache.get("key2"));
382 
383         //Test time to live.
384         Thread.sleep(4999);
385         assertNull(cache.get("key1"));
386         assertNull(cache.get("key2"));
387     }
388 
389     /***
390      * Test expiry based on time to live for a cache with config
391      * <cache name="sampleCacheNoIdle"
392      * maxElementsInMemory="1000"
393      * eternal="false"
394      * timeToLiveSeconds="5"
395      * overflowToDisk="false"
396      * />
397      * <p/>
398      * where an Element override is set on TTL
399      */
400     @Test
401     public void testExpiryBasedOnTimeToIdleElementOverride() throws Exception {
402         //Set size so the second element overflows to disk.
403         Ehcache cache = manager.getCache("sampleCacheNoIdle");
404         assertEquals(30, cache.getCacheConfiguration().getDiskSpoolBufferSizeMB());
405         Element element1 = new Element("key1", "value1");
406         element1.setTimeToIdle(1);
407         cache.put(element1);
408 
409         Element element2 = new Element("key2", "value1");
410         element2.setTimeToIdle(1);
411         cache.put(element2);
412         assertNotNull(cache.get("key1"));
413         assertNotNull(cache.get("key2"));
414 
415         //Test time to idle
416         Thread.sleep(1999);
417         assertNull(cache.get("key1"));
418         assertNull(cache.get("key2"));
419 
420     }
421 
422 
423     /***
424      * Test expiry based on time to live for a cache with config
425      * <cache name="sampleCacheNoIdle"
426      * maxElementsInMemory="1000"
427      * eternal="false"
428      * timeToLiveSeconds="5"
429      * overflowToDisk="false"
430      * />
431      * <p/>
432      * where an Elment override is set on TTL
433      */
434     @Test
435     public void testExpiryBasedEternalElementOverride() throws Exception {
436         //Set size so the second element overflows to disk.
437         Ehcache cache = manager.getCache("sampleCacheNoIdle");
438         Element element1 = new Element("key1", "value1");
439         element1.setEternal(true);
440         cache.put(element1);
441 
442         Element element2 = new Element("key2", "value1");
443         element2.setEternal(true);
444         cache.put(element2);
445         assertNotNull(cache.get("key1"));
446         assertNotNull(cache.get("key2"));
447 
448         Thread.sleep(5999);
449         assertNotNull(cache.get("key1"));
450         assertNotNull(cache.get("key2"));
451 
452     }
453 
454     /***
455      * Test expiry based on time to live. Even though eternal is false, because there are no
456      * expiry or idle times, it is eternal.
457      * <cache name="sampleCacheNotEternalButNoIdleOrExpiry"
458      * maxElementsInMemory="1000"
459      * eternal="false"
460      * overflowToDisk="false"
461      * />
462      */
463     @Test
464     public void testExpirySampleCacheNotEternalButNoIdleOrExpiry() throws Exception {
465         //Set size so the second element overflows to disk.
466         Ehcache cache = manager.getCache("sampleCacheNotEternalButNoIdleOrExpiry");
467         cache.put(new Element("key1", "value1"));
468         cache.put(new Element("key2", "value1"));
469         assertNotNull(cache.get("key1"));
470         assertNotNull(cache.get("key2"));
471 
472         //Test time to idle. Should not idle out because not specified
473         Thread.sleep(2999);
474         assertNotNull(cache.get("key1"));
475         assertNotNull(cache.get("key2"));
476 
477         //Test time to live.
478         Thread.sleep(5999);
479         assertNotNull(cache.get("key1"));
480         assertNotNull(cache.get("key2"));
481     }
482 
483 
484     /***
485      * Test overflow to disk = false
486      */
487     @Test
488     public void testNoOverflowToDisk() throws Exception {
489         //Set size so the second element overflows to disk.
490         Cache cache = new Cache("test", 1, false, false, 5, 2);
491         manager.addCache(cache);
492         cache.put(new Element("key1", "value1"));
493         cache.put(new Element("key2", "value1"));
494         assertNull(cache.get("key1"));
495         assertNotNull(cache.get("key2"));
496     }
497 
498 
499     /***
500      * Test Caches with persistent stores dispose properly. Tests:
501      * <ol>
502      * <li>No exceptions are thrown on dispose
503      * <li>You cannot re add a cache after it has been disposed and removed
504      * <li>You can create a new cache with the same name
505      * </ol>
506      */
507     @Test
508     public void testCreateAddDisposeAdd() throws CacheException {
509         Cache cache = new Cache("test2", 1, true, true, 0, 0, true, 120);
510         manager.addCache(cache);
511         cache.put(new Element("key1", "value1"));
512         cache.put(new Element("key2", "value1"));
513         int sizeFromGetSize = cache.getSize();
514         int sizeFromKeys = cache.getKeys().size();
515         assertEquals(sizeFromGetSize, sizeFromKeys);
516         assertEquals(2, cache.getSize());
517         //package protected method, only available to tests. Called by teardown
518         cache.dispose();
519         manager.removeCache("test2");
520 
521 
522         try {
523             manager.addCache(cache);
524             fail();
525         } catch (CacheException e) {
526             //expected
527         }
528 
529         //Add a new cache with the same name as the disposed one.
530         Cache cache2 = new Cache("test2", 1, true, true, 0, 0, true, 120);
531         manager.addCache(cache2);
532         Ehcache cacheFromManager = manager.getCache("test2");
533         assertTrue(cacheFromManager.getStatus().equals(Status.STATUS_ALIVE));
534 
535     }
536 
537     /***
538      * Test expiry based on time to live
539      */
540     @Test
541     public void testExpiryBasedOnTimeToLive() throws Exception {
542         //Set size so the second element overflows to disk.
543         Cache cache = new Cache("test", 1, true, false, 3, 0);
544         manager.addCache(cache);
545         cache.put(new Element("key1", "value1"));
546         cache.put(new Element("key2", "value1"));
547 
548         //Test time to live
549         assertNotNull(cache.get("key1"));
550         assertNotNull(cache.get("key2"));
551         Thread.sleep(1020);
552         //Test time to live
553         assertNotNull(cache.get("key1"));
554         assertNotNull(cache.get("key2"));
555         Thread.sleep(1020);
556         //Test time to live
557         assertNotNull(cache.get("key1"));
558         assertNotNull(cache.get("key2"));
559         Thread.sleep(1959);
560         assertNull(cache.get("key1"));
561         assertNull(cache.get("key2"));
562     }
563 
564 
565     /***
566      * Tests that a cache created from defaults will expire as per
567      * the default expiry policy.
568      *
569      * @throws Exception
570      */
571     @Test
572     public void testExpiryBasedOnTimeToLiveForDefault() throws Exception {
573         String name = "ThisIsACacheWhichIsNotConfiguredAndWillThereforeUseDefaults";
574         Ehcache cache = null;
575         CacheManager manager = CacheManager.getInstance();
576         cache = manager.getCache(name);
577         if (cache == null) {
578             LOG.warn("Could not find configuration for " + name
579                     + ". Configuring using the defaultCache settings.");
580             manager.addCache(name);
581             cache = manager.getCache(name);
582         }
583 
584         cache.put(new Element("key1", "value1"));
585         cache.put(new Element("key2", "value1"));
586 
587         //Test time to live
588         assertNotNull(cache.get("key1"));
589         assertNotNull(cache.get("key2"));
590         Thread.sleep(10999);
591         assertNull(cache.get("key1"));
592         assertNull(cache.get("key2"));
593 
594 
595     }
596 
597 
598     /***
599      * Test expiry based on time to live.
600      * <p/>
601      * Elements are put quietly back into the cache after being cloned.
602      * The elements should expire as if the putQuiet had not happened.
603      */
604     @Test
605     public void testExpiryBasedOnTimeToLiveAfterPutQuiet() throws Exception {
606         //Set size so the second element overflows to disk.
607         Cache cache = new Cache("test", 1, true, false, 5, 2);
608         manager.addCache(cache);
609         cache.put(new Element("key1", "value1"));
610         cache.put(new Element("key2", "value1"));
611 
612         Element element1 = cache.get("key1");
613         Element element2 = cache.get("key2");
614         assertNotNull(element1);
615         assertNotNull(element2);
616 
617         //Test time to live
618         Thread.sleep(2999);
619         //Should not affect age
620         cache.putQuiet((Element) element2.clone());
621         cache.putQuiet((Element) element2.clone());
622         Thread.sleep(3000);
623         assertNull(cache.get("key1"));
624         assertNull(cache.get("key2"));
625     }
626 
627     /***
628      * Test expiry based on time to live
629      */
630     @Test
631     public void testNoIdleOrExpiryBasedOnTimeToLiveForEternal() throws Exception {
632         //Set size so the second element overflows to disk.
633         Cache cache = new Cache("test", 1, true, true, 5, 2);
634         manager.addCache(cache);
635         cache.put(new Element("key1", "value1"));
636         cache.put(new Element("key2", "value1"));
637 
638         //Test time to live
639         assertNotNull(cache.get("key1"));
640         assertNotNull(cache.get("key2"));
641 
642         //Check that we did not idle out
643         Thread.sleep(2999);
644         assertNotNull(cache.get("key1"));
645         assertNotNull(cache.get("key2"));
646 
647         //Check that we did not expire out
648         Thread.sleep(3999);
649         assertNotNull(cache.get("key1"));
650         assertNotNull(cache.get("key2"));
651     }
652 
653     /***
654      * Test expiry based on time to idle.
655      */
656     @Test
657     public void testExpiryBasedOnTimeToIdle() throws Exception {
658         //Set size so the second element overflows to disk.
659         Cache cache = new Cache("test", 1, true, false, 6, 2);
660         manager.addCache(cache);
661         cache.put(new Element("key1", "value1"));
662         cache.put(new Element("key2", "value1"));
663 
664         //Test time to idle
665         Element element1 = cache.get("key1");
666         Element element2 = cache.get("key2");
667         assertNotNull(element1);
668         assertNotNull(element2);
669         Thread.sleep(4000);
670         assertNull(cache.get("key1"));
671         assertNull(cache.get("key2"));
672 
673         //Test effect of get
674         cache.put(new Element("key1", "value1"));
675         cache.put(new Element("key2", "value1"));
676         Thread.sleep(1000);
677         assertNotNull(cache.get("key1"));
678         assertNotNull(cache.get("key2"));
679 
680         Thread.sleep(4000);
681         assertNull(cache.get("key1"));
682         assertNull(cache.get("key2"));
683     }
684 
685 
686     /***
687      * Test expiry based on time to idle.
688      */
689     @Test
690     public void testExpiryBasedOnTimeToIdleAfterPutQuiet() throws Exception {
691         //Set size so the second element overflows to disk.
692         Cache cache = new Cache("test", 1, true, false, 5, 3);
693         manager.addCache(cache);
694         cache.put(new Element("key1", "value1"));
695         cache.put(new Element("key2", "value1"));
696 
697         //Test time to idle
698         Element element1 = cache.get("key1");
699         Element element2 = cache.get("key2");
700         assertNotNull(element1);
701         assertNotNull(element2);
702 
703         //Now, getQuiet and check still times out 2 seconds after last get
704         Thread.sleep(1050);
705         element1 = cache.getQuiet("key1");
706         element2 = cache.getQuiet("key2");
707         Thread.sleep(2949);
708         assertNull(cache.getQuiet("key1"));
709         assertNull(cache.getQuiet("key2"));
710 
711         //Now put back in with putQuiet. Should be immediately expired
712         cache.putQuiet((Element) element1.clone());
713         cache.putQuiet((Element) element2.clone());
714         assertNull(cache.get("key1"));
715         element2 = cache.get("key2");
716         assertNull(element2);
717     }
718 
719     /***
720      * Test element statistics, including get and getQuiet
721      * eternal="false"
722      * timeToIdleSeconds="5"
723      * timeToLiveSeconds="10"
724      * overflowToDisk="true"
725      */
726     @Test
727     public void testElementStatistics() throws Exception {
728         //Set size so the second element overflows to disk.
729         Cache cache = new Cache("test", 1, true, false, 5, 2);
730         manager.addCache(cache);
731 
732         cache.setStatisticsEnabled(true);
733 
734         cache.put(new Element("key1", "value1"));
735         cache.put(new Element("key2", "value1"));
736         //allow disk write thread to catch up - MNK-2057
737         Thread.sleep(100);
738 
739         Element element1 = cache.get("key1");
740         assertEquals("Element hit count", 1, element1.getHitCount());
741         element1 = cache.getQuiet("key1");
742         assertEquals("Element hit count", 1, element1.getHitCount());
743         element1 = cache.get("key1");
744         assertEquals("Element hit count", 2, element1.getHitCount());
745     }
746 
747     /***
748      * Test cache statistics, including get and getQuiet
749      */
750     @Test
751     public void testCacheStatistics() throws Exception {
752         //Set size so the second element overflows to disk.
753         Cache cache = new Cache("test", 1, true, false, 5, 2);
754         manager.addCache(cache);
755 
756         cache.setStatisticsEnabled(true);
757 
758         cache.put(new Element("key1", "value1"));
759         cache.put(new Element("key2", "value1"));
760 
761         //Allow disk write thread to do it's thing...
762         Thread.sleep(100);
763 
764         Element element1 = cache.get("key1");
765         assertEquals("Cache hit count", 1, cache.getStatistics().getCacheHits());
766         assertEquals("Element hit count", 1, element1.getHitCount());
767         element1 = cache.getQuiet("key1");
768         assertEquals("Cache hit count", 1, cache.getStatistics().getCacheHits());
769         assertEquals("Element hit count", 1, element1.getHitCount());
770         element1 = cache.get("key1");
771         assertEquals("Cache hit count", 2, cache.getStatistics().getCacheHits());
772         assertEquals("Element hit count", 2, element1.getHitCount());
773 
774 
775         assertEquals("Cache miss count", 0, cache.getStatistics().getCacheMisses());
776         cache.get("doesnotexist");
777         assertEquals("Cache miss count", 1, cache.getStatistics().getCacheMisses());
778 
779 
780     }
781 
782     /***
783      * Checks that getQuiet works how we expect it to
784      *
785      * @throws Exception
786      */
787     @Test
788     public void testGetQuietAndPutQuiet() throws Exception {
789         //Set size so the second element overflows to disk.
790         Cache cache = new Cache("test", 1, true, false, 5, 2);
791         manager.addCache(cache);
792 
793         cache.setStatisticsEnabled(true);
794 
795         cache.put(new Element("key1", "value1"));
796         cache.put(new Element("key2", "value1"));
797 
798         //allow the writer thread to complete
799         Thread.sleep(200);
800 
801         Element element1 = cache.get("key1");
802         long lastAccessedElement1 = element1.getLastAccessTime();
803         long hitCountElement1 = element1.getHitCount();
804         assertEquals("Element-1 Hit Count", 1, hitCountElement1);
805         assertEquals("Cache Hit Count", 1L, cache.getStatistics().getCacheHits());
806 
807         element1 = cache.getQuiet("key1");
808         element1 = cache.getQuiet("key1");
809         assertEquals(1L, cache.getStatistics().getCacheHits());
810         Element clonedElement1 = (Element) element1.clone();
811         cache.putQuiet(clonedElement1);
812         element1 = cache.getQuiet("key1");
813         assertEquals("last access time should be unchanged",
814                 lastAccessedElement1, element1.getLastAccessTime());
815         assertEquals("hit count should be unchanged",
816                 hitCountElement1, element1.getHitCount());
817         element1 = cache.get("key1");
818         assertEquals("Should be two", 2, element1.getHitCount());
819     }
820 
821     /***
822      * Test size with put and remove.
823      * <p/>
824      * It checks that size makes sense, and also that getKeys.size() matches getSize()
825      */
826     @Test
827     public void testSizeWithPutAndRemove() throws Exception {
828         //Set size so the second element overflows to disk.
829         final Cache cache = new Cache("test2", 1, true, true, 0, 0);
830         manager.addCache(cache);
831         cache.put(new Element("key1", "value1"));
832         cache.put(new Element("key2", "value1"));
833         int sizeFromGetSize = cache.getSize();
834         int sizeFromKeys = cache.getKeys().size();
835         assertEquals(sizeFromGetSize, sizeFromKeys);
836         assertEquals(2, cache.getSize());
837         cache.put(new Element("key1", "value1"));
838         cache.put(new Element("key1", "value1"));
839 
840         //key1 should be in the Disk Store
841         assertEquals(cache.getSize(), cache.getKeys().size());
842         assertEquals(2, cache.getSize());
843         //there were two of these, so size will now be one
844         cache.remove("key1");
845         assertEquals(cache.getSize(), cache.getKeys().size());
846         assertEquals(1, cache.getSize());
847         cache.remove("key2");
848         assertEquals(cache.getSize(), cache.getKeys().size());
849         assertEquals(0, cache.getSize());
850 
851         //try null values
852         cache.removeAll();
853         Object object1 = new Object();
854         Object object2 = new Object();
855         cache.put(new Element(object1, null));
856         cache.put(new Element(object2, null));
857 
858         //Cannot overflow therefore just one
859         try {
860             RetryAssert.assertBy(3, SECONDS, new Callable<Integer>() {
861                 public Integer call() throws Exception {
862                     return cache.getSize();
863                 }
864             }, Is.is(1));
865         } catch (AssertionError e) {
866             //eviction failure
867             System.err.println(e + " - likely eviction failure: checking memory store");
868             assertEquals(2, cache.getMemoryStoreSize());
869         }
870         Element nullValueElement = cache.get(object1);
871         assertNull(nullValueElement.getValue());
872         assertNull(nullValueElement.getObjectValue());
873 
874     }
875 
876     /***
877      * Test getKeys after expiry
878      * <p/>
879      * Makes sure that if an element is expired, its key should also be expired
880      */
881     @Test
882     public void testGetKeysAfterExpiry() throws Exception {
883         //Set size so the second element overflows to disk.
884         Cache cache = new Cache("test2", 1, true, false, 1, 0);
885         manager.addCache(cache);
886         String key1 = "key1";
887         cache.put(new Element(key1, "value1"));
888         cache.put(new Element("key2", "value1"));
889         //getSize uses getKeys().size(), so these should be the same
890         assertEquals(cache.getSize(), cache.getKeys().size());
891         //getKeys does not do an expiry check, so the expired elements are counted
892         assertEquals(2, cache.getSize());
893         String keyFromDisk = (String) cache.get(key1).getObjectKey();
894         assertEquals(key1, keyFromDisk);
895         Thread.sleep(1999);
896         assertEquals(2, cache.getKeys().size());
897         //getKeysWithExpiryCheck does check and gives the correct answer of 0
898         assertEquals(0, cache.getKeysWithExpiryCheck().size());
899     }
900 
901 
902     /***
903      * Answers the question of whether key references are preserved as elements are written to disk.
904      * This is not a mandatory part of the API. If this test breaks in future it should be removed.
905      */
906     @Test
907     public void testKeysEqualsEquals() throws Exception {
908         //Set size so the second element overflows to disk.
909         Cache cache = new Cache("test2", 0, true, false, 1, 0);
910         manager.addCache(cache);
911         String key1 = "key1";
912         cache.put(new Element(key1, "value1"));
913         cache.put(new Element("key2", "value1"));
914         String keyFromDisk = (String) cache.get(key1).getObjectKey();
915         assertTrue(key1 == keyFromDisk);
916     }
917 
918     /***
919      * Test size after multiple calls, with put and remove
920      */
921     @Test
922     public void testSizeMultipleCallsWithPutAndRemove() throws Exception {
923         //Set size so the second element overflows to disk.
924         Cache cache = new Cache("test3", 1, true, true, 0, 0);
925         manager.addCache(cache);
926         cache.put(new Element("key1", "value1"));
927         cache.put(new Element("key2", "value1"));
928 
929         //key1 should be in the Disk Store
930         assertEquals(2, cache.getSize());
931         assertEquals(2, cache.getSize());
932         assertEquals(2, cache.getSize());
933         assertEquals(2, cache.getSize());
934         assertEquals(2, cache.getSize());
935         cache.remove("key1");
936         assertEquals(1, cache.getSize());
937         assertEquals(1, cache.getSize());
938         assertEquals(1, cache.getSize());
939         assertEquals(1, cache.getSize());
940         assertEquals(1, cache.getSize());
941         cache.remove("key2");
942         assertEquals(0, cache.getSize());
943         assertEquals(0, cache.getSize());
944         assertEquals(0, cache.getSize());
945         assertEquals(0, cache.getSize());
946         assertEquals(0, cache.getSize());
947     }
948 
949 
950     /***
951      * Expire elements and verify size is correct.
952      */
953     @Test
954     public void testGetSizeAfterExpiry() throws Exception {
955         //Set size so the second element overflows to disk.
956         Cache cache = new Cache("test", 1, true, false, 1, 0, false, Long.MAX_VALUE);
957         manager.addCache(cache);
958         cache.put(new Element("key1", "value1"));
959         cache.put(new Element("key2", "value1"));
960 
961         // Let the idle expire
962         Thread.sleep(1999);
963         assertEquals(null, cache.get("key2"));
964         assertEquals(null, cache.get("key1"));
965 
966         try {
967             assertEquals(0, cache.getSize());
968         } catch (AssertionError e) {
969             LOG.warn("Inline Expiry Removal Failed (May Happen Occasionally) - trying explicit removal of expired elements.");
970             cache.evictExpiredElements();
971             assertEquals(0, cache.getSize());
972         }
973     }
974 
975     /***
976      * Test create and access times
977      */
978     @Test
979     public void testAccessTimes() throws Exception {
980         //Set size so the second element overflows to disk.
981         Cache cache = new Cache("test", 5, true, false, 5, 2);
982         assertEquals(Status.STATUS_UNINITIALISED, cache.getStatus());
983         manager.addCache(cache);
984         Element newElement = new Element("key1", "value1");
985         long creationTime = newElement.getCreationTime();
986         assertTrue(newElement.getCreationTime() > (System.currentTimeMillis() - 500));
987         assertTrue(newElement.getHitCount() == 0);
988         assertTrue(newElement.getLastAccessTime() == 0);
989 
990         cache.put(newElement);
991 
992         Element element = cache.get("key1");
993         assertNotNull(element);
994         assertEquals(creationTime, element.getCreationTime());
995         assertTrue(element.getLastAccessTime() != 0);
996         assertTrue(element.getHitCount() == 1);
997 
998         //Check that access statistics were reset but not creation time
999         cache.put(element);
1000         element = cache.get("key1");
1001         assertEquals(creationTime, element.getCreationTime());
1002         assertTrue(element.getLastAccessTime() != 0);
1003         assertTrue(element.getHitCount() == 1);
1004     }
1005 
1006     /***
1007      * Tests initialisation failures
1008      */
1009     @Test
1010     public void testInitialiseFailures() {
1011         final String name = "testInitialiseFailures2";
1012         Cache cache = new Cache(name, 1, false, false, 5, 1);
1013         cache.initialise();
1014 
1015         try {
1016             cache.initialise();
1017             fail("Calling cache.initialise() multiple times should fail with IllegalStateException");
1018         } catch (IllegalStateException e) {
1019             if (e.getMessage().contains("Cannot initialise the " + name)) {
1020                 // expected exception
1021             } else {
1022                 throw e;
1023             }
1024         }
1025     }
1026 
1027     /***
1028      * Nulls should be ignored
1029      *
1030      * @throws Exception
1031      */
1032     @Test
1033     public void testNullPuts() throws Exception {
1034         Cache cache = new Cache("testPutFailures", 1, false, false, 5, 1);
1035         manager.addCache(cache);
1036 
1037         cache.put(null);
1038         cache.put(null, false);
1039         cache.putQuiet(null);
1040         cache.putQuiet(new Element(null, null));
1041 
1042         //Null Elements like this are ignored
1043         cache.put(new Element(null, "dog"));
1044         cache.put(new Element(null, null));
1045 
1046         //Null Elements like this are ignored
1047         cache.putQuiet(new Element(null, "dog"));
1048         cache.putQuiet(new Element(null, null));
1049     }
1050 
1051 
1052     /***
1053      * Tests cache, memory store and disk store sizes from config
1054      */
1055     @Test
1056     public void testSizes() throws Exception {
1057         Ehcache cache = getSampleCache1();
1058 
1059         assertEquals(0, cache.getMemoryStoreSize());
1060 
1061         for (int i = 0; i < 10010; i++) {
1062             cache.put(new Element("key" + i, "value1"));
1063         }
1064 
1065         Thread.sleep(1000);
1066 
1067         assertEquals(10000, cache.getSize());
1068         assertEquals(10000, cache.getMemoryStoreSize());
1069         assertTrue(1010 > cache.getDiskStoreSize());
1070 
1071         //NonSerializable
1072         Thread.sleep(15);
1073         cache.put(new Element(new Object(), Object.class));
1074 
1075         Thread.sleep(1000);
1076 
1077         assertEquals(10000, cache.getSize());
1078         assertTrue(1010 > cache.getDiskStoreSize());
1079         assertEquals(10000, cache.getMemoryStoreSize());
1080         assertEquals(10000, cache.getMemoryStoreSize());
1081         assertEquals(10000, cache.getMemoryStoreSize());
1082         assertEquals(10000, cache.getMemoryStoreSize());
1083 
1084 
1085         cache.remove("key4");
1086         cache.remove("key3");
1087 
1088         assertEquals(9998, cache.getSize());
1089         //cannot make any guarantees as no elements have been getted, and all are equally likely to be evicted.
1090         //assertEquals(10000, cache.getMemoryStoreSize());
1091         //assertEquals(9, cache.getDiskStoreSize());
1092 
1093 
1094         Thread.sleep(1000);
1095 
1096         cache.removeAll();
1097         assertEquals(0, cache.getSize());
1098         assertEquals(0, cache.getMemoryStoreSize());
1099         assertEquals(0, cache.getDiskStoreSize());
1100 
1101     }
1102 
1103 
1104     //@Test
1105 
1106     public void testSizesContinuous() throws Exception {
1107         while (true) {
1108             testFlushWhenOverflowToDisk();
1109         }
1110     }
1111 
1112 
1113     /***
1114      * Tests flushing the cache, with the default, which is to clear
1115      * <p/>
1116      * Note: Which element gets evicted is probabilistic. 1.5 and earlier were deterministic. Thus
1117      * the variation in what gets into the DiskStore.
1118      *
1119      * @throws Exception
1120      */
1121     @Test
1122     public void testFlushWhenOverflowToDisk() throws Exception {
1123         if (manager.getCache("testFlushWhenOverflowToDisk") == null) {
1124             manager.addCache(new Cache("testFlushWhenOverflowToDisk", 50, true, false, 100, 200, true, 120));
1125         }
1126         Cache cache = manager.getCache("testFlushWhenOverflowToDisk");
1127         cache.removeAll();
1128 
1129         assertEquals(0, cache.getMemoryStoreSize());
1130         assertEquals(0, cache.getDiskStoreSize());
1131 
1132 
1133         for (int i = 0; i < 100; i++) {
1134             cache.put(new Element(Integer.valueOf(i), new Date()));
1135         }
1136 
1137         RetryAssert.assertBy(10, TimeUnit.SECONDS, new GetCacheDiskSize(cache), is(100));
1138 
1139         for (int i = 0; i < 100; i++) {
1140             cache.get(Integer.valueOf(i));
1141         }
1142 
1143         RetryAssert.assertBy(10, TimeUnit.SECONDS, new GetCacheMemorySize(cache), lessThanOrEqualTo(50L));
1144         assertEquals(100, cache.getSize());
1145         assertEquals(100, cache.getDiskStoreSize());
1146 
1147 
1148         //Should get selected. But this is probabilistic
1149         cache.put(new Element("key", new String("sdf")));
1150         cache.put(new Element("key2", new String("fdgdf")));
1151         cache.put(new Element("key1", "value"));
1152 
1153         RetryAssert.assertBy(10, TimeUnit.SECONDS, new GetCacheDiskSize(cache), is(103));
1154 
1155         cache.get("key1");
1156 
1157         RetryAssert.assertBy(10, TimeUnit.SECONDS, new GetCacheMemorySize(cache), lessThanOrEqualTo(50L));
1158         assertEquals(103, cache.getSize());
1159         assertEquals(103, cache.getDiskStoreSize());
1160 
1161 
1162         //these "null" Elements are ignored and do not get put in
1163         cache.put(new Element(null, null));
1164         cache.put(new Element(null, null));
1165 
1166         assertEquals(103, cache.getSize());
1167         assertEquals(103, cache.getDiskStoreSize());
1168         assertThat(cache.getMemoryStoreSize(), lessThanOrEqualTo(50L));
1169 
1170         //this one does
1171         cache.put(new Element("nullValue", null));
1172 
1173         RetryAssert.assertBy(10, TimeUnit.SECONDS, new GetCacheDiskSize(cache), is(104));
1174         assertThat(cache.getMemoryStoreSize(), lessThanOrEqualTo(50L));
1175 
1176         cache.flush();
1177 
1178         RetryAssert.assertBy(10, TimeUnit.SECONDS, new GetCacheMemorySize(cache), is(0L));
1179         //Non Serializable Elements get discarded
1180         assertEquals(104, cache.getDiskStoreSize());
1181 
1182         cache.removeAll();
1183     }
1184 
1185     @Test
1186     public void testFlushWithoutClear() throws InterruptedException {
1187 
1188         CacheManager cacheManager = CacheManager.create(AbstractCacheTest.TEST_CONFIG_DIR + "ehcache.xml");
1189         Cache cache = cacheManager.getCache("SimplePageCachingFilter");
1190         cache.removeAll();
1191         for (int i = 0; i < 100; i++) {
1192             cache.put(new Element("" + i, new Date()));
1193         }
1194 
1195         Thread.sleep(200);
1196 
1197         for (int i = 0; i < 100; i++) {
1198             cache.get("" + i);
1199         }
1200 
1201         assertEquals(10, cache.getMemoryStoreSize());
1202         assertEquals(100, cache.getDiskStoreSize());
1203 
1204         cache.flush();
1205         Thread.sleep(200);
1206 
1207         assertEquals(10, cache.getMemoryStoreSize());
1208         assertEquals(100, cache.getDiskStoreSize());
1209         cacheManager.shutdown();
1210 
1211     }
1212 
1213     @Test
1214     public void testFlushWithClear() throws InterruptedException {
1215 
1216         CacheManager cacheManager = CacheManager.create(AbstractCacheTest.TEST_CONFIG_DIR + "ehcache.xml");
1217         Cache cache = cacheManager.getCache("SimplePageFragmentCachingFilter");
1218         cache.removeAll();
1219         for (int i = 0; i < 100; i++) {
1220             cache.put(new Element(Integer.toString(i), new Date()));
1221         }
1222 
1223         for (long start = System.nanoTime(); (cache.getDiskStoreSize() != 100) && (System.nanoTime() - start < TimeUnit.SECONDS.toNanos(30));) {
1224             Thread.sleep(10);
1225         }
1226 
1227         for (int i = 0; i < 100; i++) {
1228             cache.get(Integer.toString(i));
1229         }
1230 
1231         assertEquals(10, cache.getMemoryStoreSize());
1232         assertEquals(100, cache.getDiskStoreSize());
1233 
1234         cache.flush();
1235         for (long start = System.nanoTime(); (cache.getMemoryStoreSize() > 0) && (System.nanoTime() - start < TimeUnit.SECONDS.toNanos(30));) {
1236             Thread.sleep(10);
1237         }
1238 
1239         assertEquals(0, cache.getMemoryStoreSize());
1240         assertEquals(100, cache.getDiskStoreSize());
1241         cacheManager.shutdown();
1242     }
1243 
1244 
1245     /***
1246      * Shows the effect of jamming large amounts of puts into a cache that overflows to disk.
1247      * The DiskStore should cause puts to back off and avoid an out of memory error.
1248      */
1249     @Test
1250     public void testBehaviourOnDiskStoreBackUp() throws Exception {
1251         Cache cache = new Cache(new CacheConfiguration().name("testBehaviourOnDiskStoreBackUp")
1252                 .maxElementsInMemory(1000)
1253                 .overflowToDisk(true)
1254                 .eternal(false)
1255                 .timeToLiveSeconds(100)
1256                 .timeToIdleSeconds(200)
1257                 .diskPersistent(false)
1258                 .diskExpiryThreadIntervalSeconds(0)
1259                 .diskSpoolBufferSizeMB(10));
1260         manager.addCache(cache);
1261 
1262         assertEquals(0, cache.getMemoryStoreSize());
1263 
1264         Element a = null;
1265         int i = 0;
1266         try {
1267             for (; i < 150000; i++) {
1268                 String key = i + "";
1269                 String value = key;
1270                 a = new Element(key, value + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
1271                 cache.put(a);
1272             }
1273         } catch (OutOfMemoryError e) {
1274             LOG.info("OutOfMemoryError: " + e.getMessage() + " " + i);
1275             fail();
1276         }
1277     }
1278 
1279 
1280     /***
1281      * Tests using elements with null values. They should work as normal.
1282      *
1283      * @throws Exception
1284      */
1285     @Test
1286     public void testElementWithNullValue() throws Exception {
1287         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 100, 200);
1288         manager.addCache(cache);
1289 
1290         Object key1 = new Object();
1291         Element element = new Element(key1, null);
1292         cache.put(element);
1293         assertNotNull(cache.get(key1));
1294         assertNotNull(cache.getQuiet(key1));
1295         assertSame(element, cache.get(key1));
1296         assertSame(element, cache.getQuiet(key1));
1297         assertNull(cache.get(key1).getObjectValue());
1298         assertNull(cache.getQuiet(key1).getObjectValue());
1299 
1300         assertEquals(false, cache.isExpired(element));
1301     }
1302 
1303 
1304     /***
1305      * Tests put works correctly for Elements with overriden TTL
1306      *
1307      * @throws Exception
1308      */
1309     @Test
1310     public void testPutWithOverriddenTTLAndTTI() throws Exception {
1311         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 1, 1);
1312         manager.addCache(cache);
1313 
1314         Object key = new Object();
1315         Element element = new Element(key, "value");
1316         element.setTimeToLive(3);
1317         cache.put(element);
1318         Thread.sleep(1050);
1319         assertNotNull(cache.get(key));
1320         assertSame(element, cache.get(key));
1321 
1322         Element element2 = new Element(key, "value");
1323         cache.put(element2);
1324         Thread.sleep(1999);
1325         assertNull(cache.get(key));
1326 
1327         Element element3 = new Element(key, "value");
1328         element3.setTimeToLive(5);
1329         cache.put(element3);
1330         Thread.sleep(1999);
1331         assertSame(element3, cache.get(key));
1332 
1333     }
1334 
1335 
1336     /***
1337      * Tests putQuiet works correctly for Elements with overriden TTL
1338      *
1339      * @throws Exception
1340      */
1341     @Test
1342     public void testPutQuietWithOverriddenTTLAndTTI() throws Exception {
1343         Cache cache = new Cache("testElementWithNullValue", 10, false, false, 1, 1);
1344         manager.addCache(cache);
1345 
1346         Object key = new Object();
1347         Element element = new Element(key, "value");
1348         element.setTimeToLive(3);
1349         cache.putQuiet(element);
1350         Thread.sleep(1050);
1351         assertNotNull(cache.get(key));
1352         assertSame(element, cache.get(key));
1353 
1354         Element element2 = new Element(key, "value");
1355         cache.putQuiet(element2);
1356         Thread.sleep(1999);
1357         assertNull(cache.get(key));
1358 
1359         Element element3 = new Element(key, "value");
1360         element3.setTimeToLive(5);
1361         cache.putQuiet(element3);
1362         Thread.sleep(1999);
1363         assertSame(element3, cache.get(key));
1364 
1365     }
1366 
1367 
1368     /***
1369      * Tests using elements with null values. They should work as normal.
1370      *
1371      * @throws Exception
1372      */
1373     @Test
1374     public void testNonSerializableElement() throws Exception {
1375         Cache cache = new Cache("testElementWithNonSerializableValue", 1, true, false, 100, 200);
1376         manager.addCache(cache);
1377 
1378         Element element1 = new Element("key1", new Object());
1379         Element element2 = new Element("key2", new Object());
1380         cache.put(element1);
1381         cache.put(element2);
1382 
1383         Thread.sleep(1000);
1384 
1385         //Removed because could not overflow
1386         if (cache.get("key1") == null) {
1387             assertNotNull(cache.get("key2"));
1388         } else {
1389             assertNull(cache.get("key2"));
1390         }
1391     }
1392 
1393 
1394     /***
1395      * Tests serialization of Serializable classes with null values.
1396      *
1397      * @throws Exception
1398      */
1399     @Test
1400     public void testNullCollectionsAreSerializable() throws Exception {
1401         Cache cache = new Cache("testElementWithNonSerializableValue", 1, true, false, 100, 200);
1402         manager.addCache(cache);
1403         ArrayList arrayList = null;
1404 
1405         Element element1 = new Element("key1", arrayList);
1406         Element element2 = new Element("key2", arrayList);
1407         cache.put(element1);
1408         cache.put(element2);
1409 
1410         //Still retrievable because null Serializable classes are still Serializable
1411         Element element = cache.get("key1");
1412         assertNotNull(element);
1413         assertNull(element.getValue());
1414 
1415         //Still retrievable because null Serializable classes are still Serializable
1416         assertNotNull(cache.get("key2"));
1417     }
1418 
1419 
1420     /***
1421      * Tests what happens when an Element throws an Error on serialization. This mimics
1422      * what a nasty error like OutOfMemoryError could do.
1423      * <p/>
1424      * Before a change to the SpoolAndExpiryThread to handle this situation this test failed and generated the following log message.
1425      * Jun 28, 2006 7:17:16 PM net.sf.ehcache.store.DiskStore put
1426      * SEVERE: testThreadKillerCache: Elements cannot be written to disk store because the spool thread has died.
1427      *
1428      * @throws Exception
1429      */
1430     @Test
1431     public void testSpoolThreadHandlesThreadKiller() throws Exception {
1432         Cache cache = new Cache("testThreadKiller", 0, true, false, 100, 200);
1433         manager.addCache(cache);
1434 
1435         Element elementThreadKiller = new Element("key", new ThreadKiller());
1436         cache.put(elementThreadKiller);
1437         Thread.sleep(2999);
1438         Element element1 = new Element("key1", "one");
1439         Element element2 = new Element("key2", "two");
1440         cache.put(element1);
1441         cache.put(element2);
1442 
1443         Thread.sleep(2999);
1444 
1445         assertNotNull(cache.get("key1"));
1446         assertNotNull(cache.get("key2"));
1447     }
1448 
1449     /***
1450      * Tests disk store and memory store size
1451      *
1452      * @throws Exception
1453      */
1454     @Test
1455     public void testGetDiskStoreSize() throws Exception {
1456         Cache cache = new Cache("testGetDiskStoreSize", 1, true, false, 100, 200);
1457         manager.addCache(cache);
1458         assertEquals(0, cache.getDiskStoreSize());
1459 
1460         cache.put(new Element("key1", "value1"));
1461         Thread.sleep(100);
1462         assertEquals(1, cache.getDiskStoreSize());
1463         assertEquals(1, cache.getSize());
1464 
1465         cache.put(new Element("key2", "value2"));
1466         Thread.sleep(100);
1467         assertEquals(2, cache.getSize());
1468         assertEquals(2, cache.getDiskStoreSize());
1469         assertEquals(1, cache.getMemoryStoreSize());
1470 
1471         cache.put(new Element("key3", "value3"));
1472         cache.put(new Element("key4", "value4"));
1473         Thread.sleep(100);
1474         assertEquals(4, cache.getSize());
1475         assertEquals(4, cache.getDiskStoreSize());
1476         assertEquals(1, cache.getMemoryStoreSize());
1477 
1478         // remove last element inserted (is in memory store)
1479         cache.remove("key4");
1480         Thread.sleep(100);
1481         assertEquals(3, cache.getSize());
1482         assertEquals(3, cache.getDiskStoreSize());
1483         assertEquals(1, cache.getMemoryStoreSize());
1484 
1485         // remove key1 element
1486         cache.remove("key1");
1487         Thread.sleep(100);
1488         assertEquals(2, cache.getSize());
1489         assertEquals(2, cache.getDiskStoreSize());
1490         assertEquals(0, cache.getMemoryStoreSize());
1491 
1492         // add another
1493         cache.put(new Element("key5", "value5"));
1494         Thread.sleep(100);
1495         assertEquals(3, cache.getSize());
1496         assertEquals(3, cache.getDiskStoreSize());
1497         assertEquals(1, cache.getMemoryStoreSize());
1498 
1499         // remove all
1500         cache.removeAll();
1501         Thread.sleep(100);
1502         assertEquals(0, cache.getSize());
1503         assertEquals(0, cache.getDiskStoreSize());
1504         assertEquals(0, cache.getMemoryStoreSize());
1505 
1506         //Check behaviour of NonSerializable objects
1507         cache.put(new Element(new Object(), new Object()));
1508         cache.put(new Element(new Object(), new Object()));
1509         cache.put(new Element(new Object(), new Object()));
1510 
1511         Thread.sleep(200);
1512 
1513         assertEquals(1, cache.getSize());
1514         assertEquals(0, cache.getDiskStoreSize());
1515         assertEquals(1, cache.getMemoryStoreSize());
1516 
1517     }
1518 
1519     /***
1520      * Tests that attempting to clone a cache fails with the right exception.
1521      *
1522      * @throws Exception
1523      */
1524     @Test
1525     public void testCloneFailures() throws Exception {
1526         Cache cache = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1527         manager.addCache(cache);
1528         try {
1529             cache.clone();
1530             fail("Should have thrown CloneNotSupportedException");
1531         } catch (CloneNotSupportedException e) {
1532             //noop
1533         }
1534     }
1535 
1536 
1537     /***
1538      * Tests that the toString() method works.
1539      */
1540     @Test
1541     public void testToString() {
1542         Ehcache cache = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1543         assertTrue(cache.toString().indexOf("testGetMemoryStore") > -1);
1544     }
1545 
1546 
1547     /***
1548      * When does equals mean the same thing as == ?
1549      *
1550      * @throws CacheException
1551      * @throws InterruptedException
1552      */
1553     @Test
1554     public void testEquals() throws CacheException, InterruptedException {
1555         Cache cache = new Cache("cache", 1, true, false, 100, 200, false, 1);
1556         manager.addCache(cache);
1557 
1558         Element element1 = new Element("1", new Date());
1559         Element element2 = new Element("2", new Date());
1560         cache.put(element1);
1561         cache.put(element2);
1562 
1563         //Test equals and == from an Element retrieved from the MemoryStore
1564         Element elementFromStore = cache.get("2");
1565         assertEquals(element2, elementFromStore);
1566         assertTrue(element2 == elementFromStore);
1567 
1568         //Give the spool a chance to make sure it really got serialized to Disk
1569         Thread.sleep(300);
1570 
1571         //Test equals and == from an Element retrieved from the MemoryStore
1572         Element elementFromDiskStore = cache.get("1");
1573         assertEquals(element1, elementFromDiskStore);
1574         assertTrue(element1 != elementFromDiskStore);
1575     }
1576 
1577     /***
1578      * When does equals mean the same thing as == ?
1579      *
1580      * @throws CacheException
1581      * @throws InterruptedException
1582      */
1583     @Test
1584     public void testIsKeyInCache() throws CacheException, InterruptedException {
1585         Cache cache = new Cache("cache", 1, true, false, 100, 200, false, 1);
1586         manager.addCache(cache);
1587 
1588         Element element1 = new Element("1", new Date());
1589         Element element2 = new Element("2", new Date());
1590         cache.put(element1);
1591         cache.put(element2);
1592 
1593         assertTrue(cache.isKeyInCache("1"));
1594         assertTrue(cache.isKeyInCache("2"));
1595         assertFalse(cache.isKeyInCache(null));
1596     }
1597 
1598     /***
1599      * Tests the uniqueness of the GUID
1600      */
1601     @Test
1602     public void testGuid() {
1603         Ehcache cache1 = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1604         Ehcache cache2 = new Cache("testGetMemoryStore", 10, false, false, 100, 200);
1605         String guid1 = cache1.getGuid();
1606         String guid2 = cache2.getGuid();
1607         assertEquals(cache1.getName(), cache2.getName());
1608         assertTrue(!guid1.equals(guid2));
1609 
1610     }
1611 
1612 
1613     /***
1614      * Does the Object API work?
1615      */
1616     @Test
1617     public void testAPIObjectCompatibility() {
1618         Cache cache = new Cache("test", 5, true, false, 5, 2);
1619         manager.addCache(cache);
1620 
1621         Object objectKey = new Object();
1622         Object objectValue = new Object();
1623         Element objectElement = new Element(objectKey, objectValue);
1624         cache.put(objectElement);
1625 
1626         //Cannot get it back using get
1627         Element retrievedElement = cache.get(objectKey);
1628         assertNotNull(retrievedElement);
1629         try {
1630             retrievedElement.getObjectValue();
1631         } catch (CacheException e) {
1632             //expected
1633         }
1634 
1635         //Test that equals works
1636         retrievedElement = cache.get(objectKey);
1637         assertEquals(objectElement, retrievedElement);
1638 
1639         //Can with getObjectValue
1640         retrievedElement = cache.get(objectKey);
1641         assertEquals(objectValue, retrievedElement.getObjectValue());
1642 
1643     }
1644 
1645 
1646     /***
1647      * Does the Serializable API work?
1648      */
1649     @Test
1650     public void testAPISerializableCompatibility() {
1651         Cache cache = new Cache("test", 5, true, false, 5, 2);
1652         manager.addCache(cache);
1653 
1654         //Try object compatibility
1655         Serializable key = new String();
1656         Element objectElement = new Element(key, new String());
1657         cache.put(objectElement);
1658         Object retrievedObject = cache.get(key);
1659         assertEquals(retrievedObject, objectElement);
1660 
1661         //Test that equals works
1662         assertEquals(objectElement, retrievedObject);
1663     }
1664 
1665     /***
1666      * Test issues reported.
1667      */
1668     @Test
1669     public void testDiskStoreFlorian() throws InterruptedException {
1670         manager.shutdown();
1671 
1672         byte[] config = ("<ehcache> \n" +
1673                 "<diskStore path=\"java.io.tmpdir\"/> \n" +
1674                 "<defaultCache \n" +
1675                 "            maxElementsInMemory=\"10000\" \n" +
1676                 "            eternal=\"false\" \n" +
1677                 "            timeToIdleSeconds=\"120\" \n" +
1678                 "            timeToLiveSeconds=\"120\" \n" +
1679                 "            overflowToDisk=\"true\" \n" +
1680                 "            diskPersistent=\"false\" \n" +
1681                 "            diskExpiryThreadIntervalSeconds=\"120\" \n" +
1682                 "            memoryStoreEvictionPolicy=\"LRU\" \n" +
1683                 "            /> " +
1684                 "\n" +
1685                 "<cache name=\"testCache\" \n" +
1686                 "       maxElementsInMemory=\"20000\" \n" +
1687                 "       eternal=\"false\" \n" +
1688                 "       overflowToDisk=\"false\" \n" +
1689                 "       timeToIdleSeconds=\"300\" \n" +
1690                 "       timeToLiveSeconds=\"600\" \n" +
1691                 "       diskPersistent=\"false\" \n" +
1692                 "       diskExpiryThreadIntervalSeconds=\"1\" \n" +
1693                 "       memoryStoreEvictionPolicy=\"LFU\" \n" +
1694                 "/>           \n" +
1695                 "<cache name=\"test2Cache\" \n" +
1696                 "       maxElementsInMemory=\"20000\" \n" +
1697                 "       eternal=\"false\" \n" +
1698                 "       overflowToDisk=\"true\" \n" +
1699                 "       timeToIdleSeconds=\"300\" \n" +
1700                 "       timeToLiveSeconds=\"600\" \n" +
1701                 "       diskPersistent=\"false\" \n" +
1702                 "       diskExpiryThreadIntervalSeconds=\"1\" \n" +
1703                 "       memoryStoreEvictionPolicy=\"LFU\" \n" +
1704                 "/> \n" +
1705                 "</ehcache> ").getBytes();
1706 
1707 
1708         CacheManager cacheManager = new CacheManager(new ByteArrayInputStream(config));
1709         Cache cache = new Cache("test3cache", 20000, false, false, 50, 30);
1710         //assertTrue(cache.getCacheConfiguration().isOverflowToDisk());
1711         cacheManager.addCache(cache);
1712 
1713         //todo size is slow
1714         for (int i = 0; i < 25000; i++) {
1715             cache.put(new Element(i + "", "value"));
1716 //            assertEquals(i + 1, cache.getSize());
1717         }
1718         assertEquals(20000, cache.getSize());
1719 //        assertEquals(5000, cache.getDiskStoreSize());
1720     }
1721 
1722 
1723     /***
1724      * Tests added from 1606323 Elements not stored in memory or on disk. This was supposedly
1725      * a bug but works.
1726      * This test passes.
1727      *
1728      * @throws Exception
1729      */
1730     @Test
1731     public void testTimeToLive15552000() throws Exception {
1732         long timeToLiveSeconds = 15552000;
1733         doRunTest(timeToLiveSeconds);
1734     }
1735 
1736     /***
1737      * This test passes.
1738      *
1739      * @throws Exception
1740      */
1741     @Test
1742     public void testTimeToLive604800() throws Exception {
1743         long timeToLiveSeconds = 604800;
1744         doRunTest(timeToLiveSeconds);
1745     }
1746 
1747     private void doRunTest(long timeToLiveSeconds) {
1748         String name = "memoryAndDiskCache";
1749         int maxElementsInMemory = 1000;
1750         MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = MemoryStoreEvictionPolicy.LRU;
1751         boolean overflowToDisk = true;
1752         String diskStorePath = "java.io.tmpdir/cache";
1753         boolean eternal = false;
1754         long timeToIdleSeconds = 0;
1755         boolean diskPersistent = true;
1756         long diskExpiryThreadIntervalSeconds = 3600;
1757         RegisteredEventListeners registeredEventListeners = null;
1758         BootstrapCacheLoader bootstrapCacheLoader = null;
1759 
1760         Cache memoryAndDisk = new Cache(
1761                 name,
1762                 maxElementsInMemory,
1763                 memoryStoreEvictionPolicy,
1764                 overflowToDisk,
1765                 diskStorePath,
1766                 eternal,
1767                 timeToLiveSeconds,
1768                 timeToIdleSeconds,
1769                 diskPersistent,
1770                 diskExpiryThreadIntervalSeconds,
1771                 registeredEventListeners,
1772                 bootstrapCacheLoader);
1773 
1774         this.manager.addCache(memoryAndDisk);
1775 
1776         String key = "test";
1777         Object value = "value";
1778 
1779         memoryAndDisk.put(new Element(key, value));
1780 
1781         assertTrue(memoryAndDisk.isElementInMemory(key));
1782     }
1783 
1784     /***
1785      * Tests get from a finalize method, following a mailing list post from Felix Satyaputr
1786      *
1787      * @throws InterruptedException
1788      */
1789     @Test
1790     public void testGetQuietFromFinalize() throws InterruptedException {
1791 
1792 
1793         final Cache cache = new Cache("test", 1, true, false, 5, 2);
1794         manager.addCache(cache);
1795 
1796         cache.put(new Element("key", "value"));
1797         cache.put(new Element("key2", "value"));
1798         cache.put(new Element("key3", "value"));
1799         cache.put(new Element("key4", "value"));
1800         cache.put(new Element("key5", "value"));
1801 
1802         //wait for overflow to kick in
1803         Thread.sleep(200);
1804 
1805         createTestObject();
1806 
1807         //try to get object finalized
1808         System.gc();
1809         Thread.sleep(200);
1810         System.gc();
1811 
1812 
1813     }
1814 
1815     private void createTestObject() {
1816         new TestObject();
1817     }
1818 
1819 
1820     /***
1821      * A class with a finalize implementation.
1822      */
1823     class TestObject {
1824 
1825         /***
1826          * Override the Object finalize method
1827          */
1828         @Override
1829         protected void finalize() throws Throwable {
1830             manager.getCache("test").getQuiet("key");
1831             LOG.info("finalize run from thread " + Thread.currentThread().getName());
1832             super.finalize();
1833         }
1834     }
1835 
1836 
1837     @Test
1838     public void testGetWithLoader() {
1839 
1840         /***
1841          *
1842          */
1843         class TestCacheLoader implements CacheLoader {
1844 
1845 
1846             public Object load(Object key, Object argument) throws CacheException {
1847                 LOG.info("load1 " + key);
1848                 return key;
1849             }
1850 
1851             public Map loadAll(Collection keys, Object argument) throws CacheException {
1852                 return null;
1853             }
1854 
1855 
1856             public String getName() {
1857                 return null;
1858             }
1859 
1860             public CacheLoader clone(Ehcache cache) throws CloneNotSupportedException {
1861                 return null;
1862             }
1863 
1864             public void init() {
1865                 //noop
1866             }
1867 
1868             public void dispose() throws CacheException {
1869                 //noop
1870             }
1871 
1872             public Status getStatus() {
1873                 return null;
1874             }
1875 
1876             public Object load(Object o) throws CacheException {
1877                 LOG.info("load2 " + o + " " + o.getClass());
1878                 if (o.equals("c")) {
1879                     return null;
1880                 }
1881                 return o;
1882             }
1883 
1884             public Map loadAll(Collection collection) throws CacheException {
1885                 return null;
1886             }
1887 
1888 
1889         }
1890 
1891         Cache cache = manager.getCache("sampleCache1");
1892         cache.registerCacheLoader(new TestCacheLoader());
1893 
1894 
1895         Element element = cache.get("a");
1896         assertNull(element);
1897 
1898         element = cache.getWithLoader("b", null, null);
1899         assertNotNull(element);
1900 
1901         //should be null
1902         element = cache.getWithLoader("c", null, null);
1903         assertNull(element);
1904     }
1905 
1906     /***
1907      * Tests the async load with a single item
1908      */
1909     @Test
1910     public void testAsynchronousLoad() throws InterruptedException, ExecutionException {
1911 
1912         CountingCacheLoader countingCacheLoader = new CountingCacheLoader();
1913         Cache cache = manager.getCache("sampleCache1");
1914         cache.registerCacheLoader(countingCacheLoader);
1915         ExecutorService executorService = cache.getExecutorService();
1916 
1917         Future future = cache.asynchronousPut("key1", null, null);
1918 
1919         Object object = future.get();
1920         assertTrue(future.isDone());
1921         assertNull(object);
1922 
1923         assertFalse(executorService.isShutdown());
1924 
1925         assertEquals(1, cache.getSize());
1926         assertEquals(1, countingCacheLoader.getLoadCounter());
1927     }
1928 
1929     /***
1930      * Tests the async load with a single item
1931      */
1932     @Test
1933     public void testGetWithLoaderException() {
1934         Cache cache = manager.getCache("sampleCache1");
1935         cache.registerCacheLoader(new ExceptionThrowingLoader());
1936         try {
1937             cache.getWithLoader("key1", null, null);
1938             fail();
1939         } catch (CacheException e) {
1940             //expected
1941         }
1942     }
1943 
1944     /***
1945      * Tests the async load with a timeout
1946      */
1947     @Test
1948     public void testGetWithLoaderTimeout() {
1949         Cache cache = manager.getCache("sampleCacheTimeout");
1950         cache.registerCacheLoader(new DelayingLoader(2000));
1951         try {
1952             cache.getWithLoader("key1", null, null);
1953             fail();
1954         } catch (CacheException e) {
1955             //expected
1956         }
1957     }
1958 
1959     /***
1960      * Tests the async load with a timeout
1961      */
1962     @Test
1963     public void testGetAllWithLoaderTimeout() {
1964         Cache cache = manager.getCache("sampleCacheTimeout");
1965         cache.registerCacheLoader(new DelayingLoader(2000));
1966         try {
1967             cache.getAllWithLoader(Arrays.asList("key1"), null);
1968             fail();
1969         } catch (CacheException e) {
1970             //expected
1971         }
1972     }
1973 
1974     /***
1975      * Tests the loadAll async method
1976      */
1977     @Test
1978     public void testAsynchronousLoadAll() throws InterruptedException, ExecutionException {
1979 
1980         CountingCacheLoader countingCacheLoader = new CountingCacheLoader();
1981         Cache cache = manager.getCache("sampleCache1");
1982         cache.registerCacheLoader(countingCacheLoader);
1983         ExecutorService executorService = cache.getExecutorService();
1984 
1985         List keys = new ArrayList();
1986         for (int i = 0; i < 1000; i++) {
1987             keys.add(Integer.valueOf(i));
1988         }
1989 
1990         Future future = cache.asynchronousLoadAll(keys, null);
1991         assertFalse(future.isDone());
1992 
1993         Object object = future.get();
1994         assertTrue(future.isDone());
1995         assertNull(object);
1996 
1997         assertFalse(executorService.isShutdown());
1998 
1999         assertEquals(1000, cache.getSize());
2000         assertEquals(1000, countingCacheLoader.getLoadAllCounter());
2001     }
2002 
2003     /***
2004      * Tests programmatically disabling and enabling a cache
2005      */
2006     @Test
2007     public void testEnableAndDisable() throws Exception {
2008         Ehcache cache = manager.getCache("sampleCacheNoIdle");
2009         cache.put(new Element("key1put", "value1"));
2010         cache.put(new Element("key1putQuiet", "value1"));
2011         assertFalse(cache.isDisabled());
2012         assertNotNull(cache.get("key1put"));
2013         assertNotNull(cache.get("key1putQuiet"));
2014 
2015         //now disable
2016         cache.setDisabled(true);
2017 
2018         assertTrue(cache.isDisabled());
2019         assertNull(cache.get("key1put"));
2020         assertNull(cache.get("key1putQuiet"));
2021 
2022         cache.put(new Element("key2put", "value1"));
2023         cache.put(new Element("key2putQuiet", "value1"));
2024         assertNull(cache.get("key2put"));
2025         assertNull(cache.get("key2putQuiet"));
2026     }
2027 
2028 
2029     /***
2030      * Run testConcurrentPutsAreConsistent() repeatedly for 50 times to shake out issues that happen rarely.
2031      */
2032     @Test
2033     public void testConcurrentPutsAreConsistentRepeatedly() throws InterruptedException {
2034         for (int i = 0; i < 20; i++) {
2035             manager.removalAll();
2036             testConcurrentPutsAreConsistent();
2037         }
2038     }
2039 
2040     /***
2041      * Shows a consistency problem as reported against 1.6.0.
2042      * <p/>
2043      * Does not happen when not using DiskStore
2044      * Putting synchronized on put/get on cache fixes it
2045      * Only happens when the Element is retrieved from the DiskStore. Debugging shows
2046      * that the problem is caused by puts not getting through or coming in the wrong order
2047      * Putting synchronized on MemoryStore.put() fixes the issue. That is the applied fix.
2048      * <p/>
2049      * The exact cause is unknown but the behaviour of ConcurrentHashMap is suspected.
2050      */
2051     @Test
2052     public void testConcurrentPutsAreConsistent() throws InterruptedException {
2053         Cache cache = new Cache("someName", 100, true, true, 0, 0);
2054         manager.addCache(cache);
2055 
2056         cache.setStatisticsEnabled(true);
2057 
2058         ExecutorService executor = Executors.newFixedThreadPool(10);
2059 
2060         for (int i = 0; i < 5000; i++) {
2061             executor.execute(new CacheTestRunnable(cache, String.valueOf(i)));
2062         }
2063         executor.shutdown();
2064         executor.awaitTermination(10, TimeUnit.SECONDS);
2065 
2066         assertEquals("Failures: ", 0, CacheTestRunnable.FAILURES.size());
2067         assertEquals(5000, cache.getStatistics().getCacheHits());
2068 
2069     }
2070 
2071     /***
2072      * A runnable that sets 5 times in a row then calls get and checks it is the last value set
2073      */
2074     private static final class CacheTestRunnable implements Runnable {
2075         static final List FAILURES = new ArrayList();
2076 
2077         private final Ehcache cache;
2078         private final String key;
2079 
2080         private CacheTestRunnable(Ehcache cache, String key) {
2081             this.cache = cache;
2082             this.key = key;
2083         }
2084 
2085         public void run() {
2086             setValue("new value");
2087             setValue("new value2");
2088             setValue("new value3");
2089             setValue("new value4");
2090             setValue("new value5");
2091 
2092             Element element = cache.get(key);
2093             String value = element.getValue().toString();
2094             boolean result = value.equals("new value5");
2095             if (!result) {
2096                 LOG.info("key is: " + key + " value: " + value + " version: " + element.getVersion());
2097                 FAILURES.add("key is: " + key + " value: " + value);
2098             }
2099         }
2100 
2101         private void setValue(String valueToSet) {
2102             cache.put(new Element(key, valueToSet));
2103         }
2104 
2105     }
2106 
2107     /***
2108      * test cache clones do not have same statistics
2109      *
2110      * @throws Exception
2111      */
2112     @Test
2113     public void testCloneCompleteness() throws Exception {
2114         final AtomicBoolean lastValue = new AtomicBoolean();
2115         Cache cache = new Cache("testGetMemoryStore", 10, false, false, 100,
2116                 200);
2117         PropertyChangeListener changeListener = new PropertyChangeListener() {
2118             public void propertyChange(final PropertyChangeEvent evt) {
2119                 if (evt.getPropertyName().equals("Disabled")) {
2120                     LOG.info("" + evt.getSource());
2121                     lastValue.set((Boolean) evt.getNewValue());
2122                 }
2123             }
2124         };
2125         cache.addPropertyChangeListener(changeListener);
2126         Cache clone = cache.clone();
2127         clone.setName("testGetMemoryStoreClone");
2128         manager.addCache(cache);
2129         manager.addCache(clone);
2130 
2131         cache.setStatisticsEnabled(true);
2132         clone.setStatisticsEnabled(true);
2133 
2134         assertFalse(cache.getGuid().equals(clone.getGuid()));
2135 
2136         // validate updating the statistics of one cache does NOT affect a
2137         // cloned one
2138         cache.get("notFoundKey");
2139         assertEquals(1, cache.getStatistics().getCacheMisses());
2140         assertEquals(0, clone.getStatistics().getCacheMisses());
2141 
2142         cache.setDisabled(true);
2143         clone.setDisabled(true);
2144         clone.setDisabled(false);
2145 
2146         assertFalse(cache.getGuid().equals(clone.getGuid()));
2147         assertThat(getPropertyChangeSupport(cache), not(sameInstance(getPropertyChangeSupport(clone))));
2148         assertThat(lastValue.get(), is(false));
2149         clone.removePropertyChangeListener(changeListener);
2150         cache.setDisabled(false);
2151         cache.setDisabled(true);
2152         assertThat(lastValue.get(), equalTo(true));
2153         clone.setDisabled(true);
2154         clone.setDisabled(false);
2155         assertThat(lastValue.get(), equalTo(true));
2156     }
2157 
2158     private PropertyChangeSupport getPropertyChangeSupport(final Cache cache) throws Exception {
2159         PropertyChangeSupport propertyChangeSupport = null;
2160         Field field = Cache.class.getDeclaredField("propertyChangeSupport");
2161         field.setAccessible(true);
2162         propertyChangeSupport = (PropertyChangeSupport) field.get(cache);
2163 
2164         return propertyChangeSupport;
2165     }
2166 
2167 
2168     /***
2169      * Checks that notification only happens once when clearOnFlush is false i.e.
2170      * The impact of this is that there will be one copy in each store.
2171      */
2172     @Test
2173     public void testRemoveListenersCalledOnce() {
2174         Cache cache = manager.getCache("sampleCache1");
2175         RemoveCountingListener l = new RemoveCountingListener();
2176         cache.getCacheEventNotificationService().registerListener(l);
2177 
2178         cache.getCacheConfiguration().setDiskPersistent(true);
2179         cache.getCacheConfiguration().setClearOnFlush(false);
2180 
2181         Element element = new Element("foo", "bar", 1L);
2182 
2183         cache.put(element);
2184 
2185         cache.flush();
2186 
2187         cache.remove("foo");
2188 
2189         assertEquals(1, l.count);
2190         assertEquals(element, l.element);
2191     }
2192 
2193     /***
2194      * test listener
2195      */
2196     private static class RemoveCountingListener implements CacheEventListener {
2197 
2198         private int count;
2199         private Element element;
2200 
2201         public void notifyElementRemoved(Ehcache cache, Element element)
2202                 throws CacheException {
2203             count++;
2204             this.element = element;
2205         }
2206 
2207         public void dispose() {
2208 
2209         }
2210 
2211         public void notifyElementEvicted(Ehcache cache, Element element) {
2212 
2213         }
2214 
2215         public void notifyElementExpired(Ehcache cache, Element element) {
2216 
2217         }
2218 
2219         public void notifyElementPut(Ehcache cache, Element element)
2220                 throws CacheException {
2221 
2222         }
2223 
2224         public void notifyElementUpdated(Ehcache cache, Element element)
2225                 throws CacheException {
2226         }
2227 
2228         public void notifyRemoveAll(Ehcache cache) {
2229 
2230         }
2231 
2232         @Override
2233         public Object clone() throws CloneNotSupportedException {
2234             return super.clone();
2235         }
2236     }
2237 
2238     /***
2239      * Checks that TTL of Long.MAX_VALUE means value never expires.
2240      * See EHC-432.
2241      */
2242     @Test
2243     public void testMaxLongTTLIsEternal() {
2244         long maxLiveTime = Long.MAX_VALUE;
2245 
2246         final Cache cache = new Cache("bla", 5000, false, false, maxLiveTime, 0);
2247         final CacheManager cacheManager = CacheManager.create();
2248 
2249         cacheManager.addCache(cache);
2250 
2251         Element e = new Element("key", "bla");
2252         cache.put(e);
2253 
2254         // theoretically we should wait a long time here but the error from EHC-432
2255         // has already shown up in the put.  And we don't have time to wait forever
2256         // to verify this.
2257 
2258         Element e2 = cache.get("key");
2259         assertNotNull(e2);
2260     }
2261 
2262     /***
2263      * Checks that TTL of Integer.MAX_VALUE means value never expires.
2264      * See EHC-432.
2265      */
2266     @Test
2267     public void testMaxIntegerTTLIsEternal() {
2268         long maxLiveTime = Integer.MAX_VALUE;
2269 
2270         final Cache cache = new Cache("bla", 5000, false, false, maxLiveTime, 0);
2271         final CacheManager cacheManager = CacheManager.create();
2272 
2273         cacheManager.addCache(cache);
2274 
2275         Element e = new Element("key", "bla");
2276         cache.put(e);
2277 
2278         // theoretically we should wait a long time here but the error from EHC-432
2279         // has already shown up in the put.  And we don't have time to wait forever
2280         // to verify this.
2281 
2282         Element e2 = cache.get("key");
2283         assertNotNull(e2);
2284     }
2285 
2286     /***
2287      * Versioning is broken when updates are done. If an Element constructor specifying a version is used, it should
2288      * be preserved.
2289      * <p/>
2290      * See EHC-666
2291      */
2292     @Test
2293     public void testVersioningShouldBePreserved() {
2294 
2295         CacheManager cacheManager = CacheManager.getInstance();
2296         cacheManager.addCache(new Cache("mltest", 50, MemoryStoreEvictionPolicy.LRU, true, null, true, 0, 0, false, 120, null, null, 0, 2, false));
2297         Cache cache = cacheManager.getCache("mltest");
2298 
2299         Element a = new Element("a key", "a value", 1L);
2300         cache.put(a);
2301         Element aAfter = cache.get("a key");
2302         assertEquals(1L, aAfter.getVersion());
2303 
2304         LOG.info("Element after first put with specific version." + aAfter);
2305 
2306         //A put where the version is not explicitly mentioned, gets a default version of 1.
2307         Element b = new Element("a key", "a value");
2308         cache.put(b);
2309         Element bAfter = cache.get("a key");
2310         assertEquals(1L, bAfter.getVersion());
2311         LOG.info("Element after second put. No version." + bAfter);
2312 
2313         //Explicit Version should be preserved
2314         Element c = new Element("a key", "a value", 3L);
2315         cache.put(c);
2316         LOG.info("Element after third put with specific version." + cache.get("a key"));
2317         Element cAfter = cache.get("a key");
2318         assertEquals(3L, cAfter.getVersion());
2319 
2320     }
2321 
2322     /***
2323      * When bulkOperations are working fine
2324      *
2325      * @throws CacheException
2326      * @throws InterruptedException
2327      */
2328     @Test
2329     public void testBulkOperations() throws CacheException, InterruptedException {
2330         Cache cache = new Cache("cache", 1000, true, false, 100000, 200000, false, 1);
2331         manager.addCache(cache);
2332 
2333         int numOfElements = 100;
2334         Set<Element> elements = new HashSet<Element>();
2335         for(int i = 0; i < numOfElements; i++){
2336             elements.add(new Element("key" + i, "value" + i));
2337         }
2338         cache.putAll(elements);
2339         assertEquals(numOfElements, cache.getSize());
2340 
2341         Set keySet1 = new HashSet<String>();
2342         for(int i = 0; i < numOfElements; i++){
2343             keySet1.add("key"+i);
2344         }
2345 
2346         Map<Object, Element> rv = cache.getAll(keySet1);
2347         assertEquals(numOfElements, rv.size());
2348 
2349         for(Element element : rv.values()){
2350             assertTrue(elements.contains(element));
2351         }
2352 
2353         Collection<Element> values = rv.values();
2354         for(Element element : elements){
2355             assertTrue(values.contains(element));
2356         }
2357 
2358         Random rand = new Random();
2359         Set keySet2 = new HashSet<String>();
2360         for(int i = 0; i < numOfElements/2; i++){
2361             keySet2.add("key" + rand.nextInt(numOfElements));
2362         }
2363 
2364         rv = cache.getAll(keySet2);
2365         assertEquals(keySet2.size(), rv.size());
2366 
2367         for(Element element : rv.values()){
2368             assertTrue(elements.contains(element));
2369         }
2370 
2371         assertEquals(keySet2, rv.keySet());
2372 
2373         cache.removeAll(keySet2);
2374         assertEquals(numOfElements - keySet2.size(), cache.getSize());
2375 
2376         for(Object key : keySet2){
2377             assertNull(cache.get(key));
2378         }
2379 
2380         cache.removeAll();
2381         assertEquals(0, cache.getSize());
2382 
2383         cache.putAll(elements);
2384         assertEquals(elements.size(), cache.getSize());
2385 
2386         Set keySet3 = new HashSet<String>();
2387         for(int i = 0; i < numOfElements; i++){
2388             keySet3.add("key" + 2 * i);
2389         }
2390         cache.removeAll(keySet3);
2391         assertEquals(numOfElements/2, cache.getSize());
2392 
2393         Set keySet4 = new HashSet<String>();
2394         for(int i = 0; i < 2 * numOfElements; i++){
2395             keySet4.add("key" + i);
2396         }
2397 
2398         Map<Object, Element> actual = cache.getAll(keySet4);
2399         Map<Object, Element> expected = new HashMap<Object, Element>();
2400 
2401         for(int i = 0; i < numOfElements; i++) {
2402             if(i % 2 == 0) {
2403                 expected.put("key" + i, null);
2404             } else {
2405                 Element val = actual.get("key" + i);
2406                 assertNotNull("val for key" + i + " is " + val, val);
2407                 expected.put("key" + i, val);
2408             }
2409         }
2410 
2411         for(int i = numOfElements; i < 2 * numOfElements; i++) {
2412             expected.put("key" + i, null);
2413         }
2414 
2415         assertEquals(expected, actual);
2416     }
2417 
2418     static class GetCacheMemorySize implements Callable<Long> {
2419 
2420         private final Ehcache cache;
2421 
2422         public GetCacheMemorySize(Ehcache cache) {
2423             this.cache = cache;
2424         }
2425 
2426         public Long call() throws Exception {
2427             return cache.getMemoryStoreSize();
2428         }
2429     }
2430 
2431     static class GetCacheDiskSize implements Callable<Integer> {
2432 
2433         private final Ehcache cache;
2434 
2435         public GetCacheDiskSize(Ehcache cache) {
2436             this.cache = cache;
2437         }
2438 
2439         public Integer call() throws Exception {
2440             return cache.getDiskStoreSize();
2441         }
2442     }
2443 }
2444