View Javadoc
1   package org.apache.commons.jcs.engine.memory.shrinking;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import junit.framework.TestCase;
23  import org.apache.commons.jcs.engine.CacheElement;
24  import org.apache.commons.jcs.engine.CompositeCacheAttributes;
25  import org.apache.commons.jcs.engine.ElementAttributes;
26  import org.apache.commons.jcs.engine.ElementAttributesUtils;
27  import org.apache.commons.jcs.engine.behavior.ICacheElement;
28  import org.apache.commons.jcs.engine.control.CompositeCache;
29  import org.apache.commons.jcs.engine.control.event.ElementEventHandlerMockImpl;
30  import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType;
31  import org.apache.commons.jcs.engine.memory.MockMemoryCache;
32  
33  import java.io.IOException;
34  
35  /**
36   * This tests the functionality of the shrinker thread.
37   * <p>
38   * @author Aaron Smuts
39   */
40  public class ShrinkerThreadUnitTest
41      extends TestCase
42  {
43      /** verify the check for removal
44       * <p>
45       * @throws IOException */
46      public void testCheckForRemoval_Expired() throws IOException
47      {
48          // SETUP
49          CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
50          cacheAttr.setCacheName("testRegion");
51          cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
52          cacheAttr.setMaxSpoolPerRun( 10 );
53  
54          CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
55  
56          String key = "key";
57          String value = "value";
58  
59          ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
60          ElementAttributes elementAttr = new ElementAttributes();
61          elementAttr.setIsEternal( false );
62          element.setElementAttributes( elementAttr );
63          element.getElementAttributes().setMaxLife(1);
64  
65          long now = System.currentTimeMillis();
66          // add two seconds
67          now += 2000;
68  
69          // DO WORK
70          boolean result = cache.isExpired( element, now,
71                  ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
72                  ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
73  
74          // VERIFY
75          assertTrue( "Item should have expired.", result );
76      }
77  
78      /** verify the check for removal
79       * <p>
80       * @throws IOException */
81      public void testCheckForRemoval_NotExpired() throws IOException
82      {
83          // SETUP
84          CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
85          cacheAttr.setCacheName("testRegion");
86          cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
87          cacheAttr.setMaxSpoolPerRun( 10 );
88  
89          CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
90  
91          String key = "key";
92          String value = "value";
93  
94          ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
95          ElementAttributes elementAttr = new ElementAttributes();
96          elementAttr.setIsEternal( false );
97          element.setElementAttributes( elementAttr );
98          element.getElementAttributes().setMaxLife(1);
99  
100         long now = System.currentTimeMillis();
101         // subtract two seconds
102         now -= 2000;
103 
104         // DO WORK
105         boolean result = cache.isExpired( element, now,
106                 ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
107                 ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
108 
109         // VERIFY
110         assertFalse( "Item should not have expired.", result );
111     }
112 
113     /** verify the check for removal
114      * <p>
115      * @throws IOException */
116     public void testCheckForRemoval_IdleTooLong() throws IOException
117     {
118         // SETUP
119         CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
120         cacheAttr.setCacheName("testRegion");
121         cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
122         cacheAttr.setMaxSpoolPerRun( 10 );
123 
124         CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
125 
126         String key = "key";
127         String value = "value";
128 
129         ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
130         ElementAttributes elementAttr = new ElementAttributes();
131         elementAttr.setIsEternal( false );
132         element.setElementAttributes( elementAttr );
133         element.getElementAttributes().setMaxLife(100);
134         element.getElementAttributes().setIdleTime( 1 );
135 
136         long now = System.currentTimeMillis();
137         // add two seconds
138         now += 2000;
139 
140         // DO WORK
141         boolean result = cache.isExpired( element, now,
142                 ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
143                 ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
144 
145         // VERIFY
146         assertTrue( "Item should have expired.", result );
147     }
148 
149     /** verify the check for removal
150      * <p>
151      * @throws IOException */
152     public void testCheckForRemoval_NotIdleTooLong() throws IOException
153     {
154         // SETUP
155         CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
156         cacheAttr.setCacheName("testRegion");
157         cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
158         cacheAttr.setMaxSpoolPerRun( 10 );
159 
160         CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
161 
162         String key = "key";
163         String value = "value";
164 
165         ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
166         ElementAttributes elementAttr = new ElementAttributes();
167         elementAttr.setIsEternal( false );
168         element.setElementAttributes( elementAttr );
169         element.getElementAttributes().setMaxLife(100);
170         element.getElementAttributes().setIdleTime( 1 );
171 
172         long now = System.currentTimeMillis();
173         // subtract two seconds
174         now -= 2000;
175 
176         // DO WORK
177         boolean result = cache.isExpired( element, now,
178                 ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
179                 ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
180 
181         // VERIFY
182         assertFalse( "Item should not have expired.", result );
183     }
184 
185     /**
186      * Setup cache attributes in mock. Create the shrinker with the mock. Add some elements into the
187      * mock memory cache see that they get spooled.
188      * <p>
189      * @throws Exception
190      */
191     public void testSimpleShrink()
192         throws Exception
193     {
194         // SETUP
195         CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
196         cacheAttr.setCacheName("testRegion");
197         cacheAttr.setMemoryCacheName("org.apache.commons.jcs.engine.memory.MockMemoryCache");
198         cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
199         cacheAttr.setMaxSpoolPerRun( 10 );
200 
201         CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
202         MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
203 
204         String key = "key";
205         String value = "value";
206 
207         ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
208 
209         ElementAttributes elementAttr = new ElementAttributes();
210         elementAttr.setIsEternal( false );
211         element.setElementAttributes( elementAttr );
212         element.getElementAttributes().setMaxLife(1);
213         memory.update( element );
214 
215         ICacheElement<String, String> returnedElement1 = memory.get( key );
216         assertNotNull( "We should have received an element", returnedElement1 );
217 
218         // set this to 2 seconds ago.
219         ElementAttributesUtils.setLastAccessTime( elementAttr,  System.currentTimeMillis() - 2000 );
220 
221         // DO WORK
222         ShrinkerThread<String, String> shrinker = new ShrinkerThread<String, String>( cache );
223         shrinker.run();
224 
225         Thread.sleep( 500 );
226 
227         // VERIFY
228         ICacheElement<String, String> returnedElement2 = memory.get( key );
229         assertTrue( "Waterfall should have been called.", memory.waterfallCallCount > 0 );
230         assertNull( "We not should have received an element.  It should have been spooled.", returnedElement2 );
231     }
232 
233     /**
234      * Add 10 to the memory cache. Set the spool per run limit to 3.
235      * <p>
236      * @throws Exception
237      */
238     public void testSimpleShrinkMultiple()
239         throws Exception
240     {
241         // SETUP
242         CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
243         cacheAttr.setCacheName("testRegion");
244         cacheAttr.setMemoryCacheName("org.apache.commons.jcs.engine.memory.MockMemoryCache");
245         cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
246         cacheAttr.setMaxSpoolPerRun( 3 );
247 
248         CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
249         MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
250 
251         for ( int i = 0; i < 10; i++ )
252         {
253             String key = "key" + i;
254             String value = "value";
255 
256             ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
257 
258             ElementAttributes elementAttr = new ElementAttributes();
259             elementAttr.setIsEternal( false );
260             element.setElementAttributes( elementAttr );
261             element.getElementAttributes().setMaxLife(1);
262             memory.update( element );
263 
264             ICacheElement<String, String> returnedElement1 = memory.get( key );
265             assertNotNull( "We should have received an element", returnedElement1 );
266 
267             // set this to 2 seconds ago.
268             ElementAttributesUtils.setLastAccessTime( elementAttr,  System.currentTimeMillis() - 2000 );
269         }
270 
271         // DO WORK
272         ShrinkerThread<String, String> shrinker = new ShrinkerThread<String, String>( cache );
273         shrinker.run();
274 
275         // VERIFY
276         Thread.sleep( 500 );
277         assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
278         assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
279     }
280 
281     /**
282      * Add a mock event handler to the items. Verify that it gets called.
283      * <p>
284      * This is only testing the spooled background event
285      * <p>
286      * @throws Exception
287      */
288     public void testSimpleShrinkMultipleWithEventHandler()
289         throws Exception
290     {
291         // SETUP
292         CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
293         cacheAttr.setCacheName("testRegion");
294         cacheAttr.setMemoryCacheName("org.apache.commons.jcs.engine.memory.MockMemoryCache");
295         cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
296         cacheAttr.setMaxSpoolPerRun( 3 );
297 
298         CompositeCache<String, String> cache = new CompositeCache<String, String>(cacheAttr, new ElementAttributes());
299         MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
300 
301         ElementEventHandlerMockImpl handler = new ElementEventHandlerMockImpl();
302 
303         for ( int i = 0; i < 10; i++ )
304         {
305             String key = "key" + i;
306             String value = "value";
307 
308             ICacheElement<String, String> element = new CacheElement<String, String>( "testRegion", key, value );
309 
310             ElementAttributes elementAttr = new ElementAttributes();
311             elementAttr.addElementEventHandler( handler );
312             elementAttr.setIsEternal( false );
313             element.setElementAttributes( elementAttr );
314             element.getElementAttributes().setMaxLife(1);
315             memory.update( element );
316 
317             ICacheElement<String, String> returnedElement1 = memory.get( key );
318             assertNotNull( "We should have received an element", returnedElement1 );
319 
320             // set this to 2 seconds ago.
321             ElementAttributesUtils.setLastAccessTime( elementAttr,  System.currentTimeMillis() - 2000 );
322         }
323 
324         // DO WORK
325         ShrinkerThread<String, String> shrinker = new ShrinkerThread<String, String>( cache );
326         shrinker.run();
327 
328         // VERIFY
329         Thread.sleep( 500 );
330         assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
331         // the shrinker delegates the the composite cache on the memory cache to put the
332         // event on the queue.  This make it hard to test.  TODO we need to change this to make it easier to verify.
333         //assertEquals( "Event handler ExceededIdleTimeBackground called the wrong number of times.", 3, handler.getExceededIdleTimeBackgroundCount() );
334         assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
335     }
336 }