1   package org.apache.jcs.utils.struct;
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 java.util.Iterator;
23  
24  import junit.framework.Test;
25  import junit.framework.TestCase;
26  import junit.framework.TestSuite;
27  
28  import org.apache.jcs.utils.struct.LRUMap;
29  
30  /***
31   * Tests the LRUMap
32   *
33   * @author aaronsm
34   *
35   */
36  public class LRUMapConcurrentTest
37      extends TestCase
38  {
39  
40      private static int items = 20000;
41  
42      /***
43       * Constructor for the TestSimpleLoad object
44       *
45       * @param testName
46       *            Description of the Parameter
47       */
48      public LRUMapConcurrentTest( String testName )
49      {
50          super( testName );
51      }
52  
53      /***
54       * Description of the Method
55       *
56       * @param args
57       *            Description of the Parameter
58       */
59      public static void main( String args[] )
60      {
61          String[] testCaseName = { LRUMapConcurrentTest.class.getName() };
62          junit.textui.TestRunner.main( testCaseName );
63      }
64  
65      /***
66       * A unit test suite for JUnit
67       *
68       * @return The test suite
69       */
70      public static Test suite()
71      {
72          // run the basic tests
73          TestSuite suite = new TestSuite( LRUMapConcurrentTest.class );
74  
75          // run concurrent tests
76          final LRUMap map = new LRUMap( 2000 );
77          suite.addTest( new LRUMapConcurrentTest( "conc1" )
78          {
79              public void runTest()
80                  throws Exception
81              {
82                  this.runConcurrentPutGetTests( map, 2000 );
83              }
84          } );
85          suite.addTest( new LRUMapConcurrentTest( "conc2" )
86          {
87              public void runTest()
88                  throws Exception
89              {
90                  this.runConcurrentPutGetTests( map, 2000 );
91              }
92          } );
93          suite.addTest( new LRUMapConcurrentTest( "conc3" )
94          {
95              public void runTest()
96                  throws Exception
97              {
98                  this.runConcurrentPutGetTests( map, 2000 );
99              }
100         } );
101 
102         // run more concurrent tests
103         final int max2 = 20000;
104         final LRUMap map2 = new LRUMap( max2 );
105         suite.addTest( new LRUMapConcurrentTest( "concB1" )
106         {
107             public void runTest()
108                 throws Exception
109             {
110                 this.runConcurrentRangeTests( map2, 10000, max2 );
111             }
112         } );
113         suite.addTest( new LRUMapConcurrentTest( "concB1" )
114         {
115             public void runTest()
116                 throws Exception
117             {
118                 this.runConcurrentRangeTests( map2, 0, 9999 );
119             }
120         } );
121 
122         return suite;
123     }
124 
125     /***
126      * Just test that we can put, get and remove as expected.
127      *
128      * @exception Exception
129      *                Description of the Exception
130      */
131     public void testSimpleLoad()
132         throws Exception
133     {
134         LRUMap map = new LRUMap( items );
135 
136         for ( int i = 0; i < items; i++ )
137         {
138             map.put( i + ":key", "data" + i );
139         }
140 
141         for ( int i = items - 1; i >= 0; i-- )
142         {
143             String res = (String) map.get( i + ":key" );
144             if ( res == null )
145             {
146                 assertNotNull( "[" + i + ":key] should not be null", res );
147             }
148         }
149 
150         // test removal
151         map.remove( "300:key" );
152         assertNull( map.get( "300:key" ) );
153 
154     }
155 
156     /***
157      * Just make sure that the LRU functions int he most simple case.
158      *
159      * @exception Exception
160      *                Description of the Exception
161      */
162     public void testLRURemoval()
163         throws Exception
164     {
165         int total = 10;
166         LRUMap map = new LRUMap( total );
167         map.setChunkSize( 1 );
168 
169         // put the max in
170         for ( int i = 0; i < total; i++ )
171         {
172             map.put( i + ":key", "data" + i );
173         }
174 
175         Iterator it = map.entrySet().iterator();
176         while ( it.hasNext() )
177         {
178             System.out.println( it.next() );
179         }
180         System.out.println( map.getStatistics() );
181 
182         // get the max out backwards
183         for ( int i = total - 1; i >= 0; i-- )
184         {
185             String res = (String) map.get( i + ":key" );
186             if ( res == null )
187             {
188                 assertNotNull( "[" + i + ":key] should not be null", res );
189             }
190         }
191 
192         System.out.println( map.getStatistics() );
193 
194         //since we got them backwards the total should be at the end.
195         // add one confirm that total is gone.
196         map.put( ( total ) + ":key", "data" + ( total ) );
197         assertNull( map.get( ( total - 1 ) + ":key" ) );
198 
199     }
200 
201     /***
202      * @throws Exception
203      */
204     public void testLRURemovalAgain()
205         throws Exception
206     {
207         int total = 10000;
208         LRUMap map = new LRUMap( total );
209         map.setChunkSize( 1 );
210 
211         // put the max in
212         for ( int i = 0; i < total * 2; i++ )
213         {
214             map.put( i + ":key", "data" + i );
215         }
216 
217         // get the total number, these shoukld be null
218         for ( int i = total - 1; i >= 0; i-- )
219         {
220             assertNull( map.get( i + ":key" ) );
221 
222         }
223 
224         // get the total to total *2 items out, these should be foufn.
225         for ( int i = ( total * 2 ) - 1; i >= total; i-- )
226         {
227             String res = (String) map.get( i + ":key" );
228             if ( res == null )
229             {
230                 assertNotNull( "[" + i + ":key] should not be null", res );
231             }
232         }
233 
234         System.out.println( map.getStatistics() );
235 
236     }
237 
238     /***
239      * Just make sure that we can put and get concurrently
240      *
241      * @param map
242      * @param items
243      * @throws Exception
244      */
245     public void runConcurrentPutGetTests( LRUMap map, int items )
246         throws Exception
247     {
248         for ( int i = 0; i < items; i++ )
249         {
250             map.put( i + ":key", "data" + i );
251         }
252 
253         for ( int i = items - 1; i >= 0; i-- )
254         {
255             String res = (String) map.get( i + ":key" );
256             if ( res == null )
257             {
258                 assertNotNull( "[" + i + ":key] should not be null", res );
259             }
260         }
261 
262     }
263 
264     /***
265      * Put, get, and remove from a range. This should occur at a range that is
266      * not touched by other tests.
267      *
268      * @param map
269      * @param start
270      * @param end
271      * @throws Exception
272      */
273     public void runConcurrentRangeTests( LRUMap map, int start, int end )
274         throws Exception
275     {
276         for ( int i = start; i < end; i++ )
277         {
278             map.put( i + ":key", "data" + i );
279         }
280 
281         for ( int i = end - 1; i >= start; i-- )
282         {
283             String res = (String) map.get( i + ":key" );
284             if ( res == null )
285             {
286                 assertNotNull( "[" + i + ":key] should not be null", res );
287             }
288         }
289 
290         // test removal
291         map.remove( start + ":key" );
292         assertNull( map.get( start + ":key" ) );
293 
294     }
295 
296 }