1   package org.apache.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  
24  import org.apache.jcs.engine.CacheElement;
25  import org.apache.jcs.engine.CompositeCacheAttributes;
26  import org.apache.jcs.engine.ElementAttributes;
27  import org.apache.jcs.engine.behavior.ICacheElement;
28  import org.apache.jcs.engine.control.event.ElementEventHandlerMockImpl;
29  import org.apache.jcs.engine.memory.MemoryCacheMockImpl;
30  
31  /***
32   * This tests the functionality of the shrinker thread.
33   *
34   * @author Aaron Smuts
35   *
36   */
37  public class ShrinkerThreadUnitTest
38      extends TestCase
39  {
40  
41      /***
42       * Setup cache attributes in mock. Create the shrinker with the mock. Add
43       * some elements into the mock memory cache see that they get spooled.
44       *
45       * @throws Exception
46       *
47       */
48      public void testSimpleShrink()
49          throws Exception
50      {
51          MemoryCacheMockImpl memory = new MemoryCacheMockImpl();
52  
53          CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
54          cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
55          cacheAttr.setMaxSpoolPerRun( 10 );
56  
57          memory.setCacheAttributes( cacheAttr );
58  
59          String key = "key";
60          String value = "value";
61  
62          ICacheElement element = new CacheElement( "testRegion", key, value );
63  
64          ElementAttributes elementAttr = new ElementAttributes();
65          elementAttr.setIsEternal( false );
66          element.setElementAttributes( elementAttr );
67          element.getElementAttributes().setMaxLifeSeconds( 1 );
68          memory.update( element );
69  
70          ICacheElement returnedElement1 = memory.get( key );
71          assertNotNull( "We should have received an element", returnedElement1 );
72  
73          // set this to 2 seconds ago.
74          elementAttr.lastAccessTime = System.currentTimeMillis() - 2000;
75  
76          ShrinkerThread shrinker = new ShrinkerThread( memory );
77          Thread runner = new Thread( shrinker );
78          runner.run();
79  
80          Thread.sleep( 500 );
81  
82          ICacheElement returnedElement2 = memory.get( key );
83          assertTrue( "Waterfall should have been called.", memory.waterfallCallCount > 0 );
84          assertNull( "We not should have received an element.  It should have been spooled.", returnedElement2 );
85      }
86  
87      /***
88       * Add 10 to the memory cache. Set the spool per run limit to 3.
89       *
90       * @throws Exception
91       */
92      public void testSimpleShrinkMutiple()
93          throws Exception
94      {
95          MemoryCacheMockImpl memory = new MemoryCacheMockImpl();
96  
97          CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
98          cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
99          cacheAttr.setMaxSpoolPerRun( 3 );
100 
101         memory.setCacheAttributes( cacheAttr );
102 
103         for ( int i = 0; i < 10; i++ )
104         {
105             String key = "key" + i;
106             String value = "value";
107 
108             ICacheElement element = new CacheElement( "testRegion", key, value );
109 
110             ElementAttributes elementAttr = new ElementAttributes();
111             elementAttr.setIsEternal( false );
112             element.setElementAttributes( elementAttr );
113             element.getElementAttributes().setMaxLifeSeconds( 1 );
114             memory.update( element );
115 
116             ICacheElement returnedElement1 = memory.get( key );
117             assertNotNull( "We should have received an element", returnedElement1 );
118 
119             // set this to 2 seconds ago.
120             elementAttr.lastAccessTime = System.currentTimeMillis() - 2000;
121         }
122 
123         ShrinkerThread shrinker = new ShrinkerThread( memory );
124         Thread runner = new Thread( shrinker );
125         runner.run();
126 
127         Thread.sleep( 500 );
128 
129         assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
130 
131         assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
132     }
133 
134     /***
135      * Add a mock event handler to the items.  Verify that it gets called.
136      * <p>
137      * This is only testing the spooled background event
138      *
139      * @throws Exception
140      */
141     public void testSimpleShrinkMutipleWithEventHandler()
142     throws Exception
143 {
144     MemoryCacheMockImpl memory = new MemoryCacheMockImpl();
145 
146     CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
147     cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
148     cacheAttr.setMaxSpoolPerRun( 3 );
149 
150     memory.setCacheAttributes( cacheAttr );
151 
152     ElementEventHandlerMockImpl handler = new ElementEventHandlerMockImpl();
153 
154     for ( int i = 0; i < 10; i++ )
155     {
156         String key = "key" + i;
157         String value = "value";
158 
159         ICacheElement element = new CacheElement( "testRegion", key, value );
160 
161         ElementAttributes elementAttr = new ElementAttributes();
162         elementAttr.addElementEventHandler( handler );
163         elementAttr.setIsEternal( false );
164         element.setElementAttributes( elementAttr );
165         element.getElementAttributes().setMaxLifeSeconds( 1 );
166         memory.update( element );
167 
168         ICacheElement returnedElement1 = memory.get( key );
169         assertNotNull( "We should have received an element", returnedElement1 );
170 
171         // set this to 2 seconds ago.
172         elementAttr.lastAccessTime = System.currentTimeMillis() - 2000;
173     }
174 
175     ShrinkerThread shrinker = new ShrinkerThread( memory );
176     Thread runner = new Thread( shrinker );
177     runner.run();
178 
179     Thread.sleep( 500 );
180 
181     assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
182 
183     // the shrinker delegates the the composite cache on the memory cache to put the
184     // event on the queue.  This make it hard to test.  TODO we need to change this to make it easier to verify.
185     //assertEquals( "Event handler ExceededIdleTimeBackground called the wrong number of times.", 3, handler.getExceededIdleTimeBackgroundCount() );
186 
187     assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
188 }
189 
190 
191 }