View Javadoc

1   /*
2    * $Id: InMemoryStoreTestCase.java 22387 2011-07-12 03:53:36Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util.store;
12  
13  import org.mule.api.lifecycle.InitialisationException;
14  import org.mule.tck.junit4.AbstractMuleTestCase;
15  
16  import java.util.concurrent.CountDownLatch;
17  import java.util.concurrent.TimeUnit;
18  import org.junit.After;
19  import org.junit.Test;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  
25  public class InMemoryStoreTestCase extends AbstractMuleTestCase
26  {
27      private InMemoryObjectStore<String> store = null;
28  
29      @After
30      public void disposeStore()
31      {
32          store.dispose();
33      }
34  
35      @Test
36      public void testSimpleTimedExpiry() throws Exception
37      {
38          int entryTTL = 3000;
39          createTimedObjectStore(entryTTL);
40  
41          // store entries in quick succession
42          storeObjects("1", "2", "3");
43  
44          // they should still be alive at this point
45          assertObjectsInStore("1", "2", "3");
46  
47          // wait until the entry TTL has been exceeded
48          Thread.sleep(entryTTL + 1000);
49  
50          // make sure all values are gone
51          assertObjectsExpired("1", "2", "3");
52      }
53  
54      @Test
55      public void testComplexTimedExpiry() throws Exception
56      {
57          int entryTTL = 3000;
58          createTimedObjectStore(entryTTL);
59          
60          // store an entry ...
61          storeObjects("1");
62          
63          // ... wait half of the expiry time ...
64          Thread.sleep(entryTTL / 2);
65          
66          // ... and store another object ...
67          storeObjects("2");
68          
69          // ... now wait until the first one is expired
70          Thread.sleep((entryTTL / 2) + 500);
71          
72          assertObjectsExpired("1");
73          assertObjectsInStore("2");
74      }
75  
76      @Test
77      public void testStoreAndRetrieve() throws Exception
78      {
79          String key = "key";
80          String value = "hello";
81          
82          createBoundedObjectStore(1);
83          
84          store.store(key, value);
85          assertObjectsInStore(key);
86          
87          String retrieved = store.retrieve(key);
88          assertEquals(value, retrieved);
89          
90          store.remove(key);        
91          assertObjectsExpired(key);
92      }
93  
94      @Test
95      public void testExpiringUnboundedStore() throws Exception
96      {
97          createUnboundedObjectStore();
98          
99          // put some items into the store
100         storeObjects("1", "2", "3");
101         
102         // expire ... this should keep all objects in the store
103         store.expire();
104         
105         assertObjectsInStore("1", "2", "3");
106     }
107 
108     @Test
109     public void testMaxSize() throws Exception
110     {
111         int maxEntries = 3;
112         createBoundedObjectStore(maxEntries);
113 
114         storeObjects("1", "2", "3");
115         assertObjectsInStore("1", "2", "3");
116 
117         // exceed threshold
118         store.store("4", "4");
119 
120         // the oldest entry should still be there, not yet expired
121         assertTrue(store.contains("1"));
122 
123         // expire manually
124         store.expire();
125         assertObjectsExpired("1");
126         assertObjectsInStore("2", "3", "4");
127 
128         // exceed some more
129         storeObjects("5");
130         store.expire();
131         assertObjectsExpired("2");
132         assertObjectsInStore("3", "4", "5");
133 
134         // exceed multiple times
135         storeObjects("6", "7", "8", "9");
136         store.expire();
137         assertObjectsInStore("7", "8", "9");
138         assertObjectsExpired("3", "4", "5", "6");
139     }
140 
141     private void storeObjects(String... objects) throws Exception
142     {
143         for (String entry : objects)
144         {
145             store.store(entry, entry);
146         }
147     }
148     
149     private void assertObjectsInStore(String... identifiers) throws Exception
150     {
151         for (String id : identifiers)
152         {
153             String message = "id " + id + " not in store " + store;
154             assertTrue(message, store.contains(id));
155         }
156     }
157     
158     private void assertObjectsExpired(String... identifiers) throws Exception
159     {
160         for (String id : identifiers)
161         {
162             assertFalse(store.contains(id));
163         }
164     }
165 
166     private void createTimedObjectStore(int timeToLive) throws InitialisationException
167     {
168         int expireInterval = 1000;
169         assertTrue("objects' time to live must be greater than the expire interval", 
170             timeToLive > expireInterval);
171         
172         store = new InMemoryObjectStore<String>();
173         store.setName("timed");
174         store.setMaxEntries(3);
175         store.setEntryTTL(timeToLive);
176         store.setExpirationInterval(expireInterval);
177         store.initialise();
178     }
179 
180     private void createBoundedObjectStore(int numberOfEntries) throws InitialisationException
181     {
182         createNonexpiringObjectStore();
183         store.setName("bounded");
184         store.setMaxEntries(numberOfEntries);
185         store.initialise();
186     }
187     
188     private void createUnboundedObjectStore() throws InitialisationException
189     {
190         createNonexpiringObjectStore();
191         store.setMaxEntries(-1);
192         store.initialise();
193     }
194 
195     private void createNonexpiringObjectStore()
196     {
197         store = new NonExpiringInMemoryObjectStore();
198     }
199     
200     /**
201      * Special subclass that coordinates with the expire thread. Upon calling <code>initialize</code>
202      * the scheduler in {@link AbstractMonitoredObjectStore} runs once. The tests in this test case
203      * rely on the fact that no expiry happens during their execution. This implementation waits for
204      * the first run of the expire method in initialize and only then continues with the execution 
205      * of the current thread.
206      */
207     private static class NonExpiringInMemoryObjectStore extends InMemoryObjectStore<String>
208     {
209         private CountDownLatch expireLatch;
210 
211         public NonExpiringInMemoryObjectStore()
212         {
213             super();
214             // entryTTL=-1 means we will have to expire manually
215             setEntryTTL(-1);
216             // run the expire thread in very, very large intervals (irreleavent to this test)
217             setExpirationInterval(Integer.MAX_VALUE);
218             
219             expireLatch = new CountDownLatch(1);
220         }
221         
222         @Override
223         public void initialise() throws InitialisationException
224         {
225             super.initialise();
226             
227             // now wait for the first expire to happen
228             try
229             {
230                 expireLatch.await(30, TimeUnit.SECONDS);
231             }
232             catch (InterruptedException ie)
233             {
234                 throw new RuntimeException("Interrupted while waiting for the first expire", ie);
235             }
236         }
237 
238         @Override
239         public void expire()
240         {
241             super.expire();
242             // expire successful ... signal initialize that it can continue
243             expireLatch.countDown();
244         }
245     }
246 }