1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
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  
18  package org.apache.jetspeed.services.portletcache;
19  
20  // Cactus and Junit imports
21  import junit.framework.Test;
22  import junit.framework.TestSuite;
23  
24  // Turbine imports
25  import org.apache.turbine.services.TurbineServices;
26  import org.apache.turbine.services.cache.GlobalCacheService;
27  import org.apache.turbine.services.cache.CachedObject;
28  import org.apache.turbine.services.cache.ObjectExpiredException;
29  import org.apache.turbine.services.cache.Refreshable;
30  import org.apache.turbine.services.cache.RefreshableCachedObject;
31  import org.apache.turbine.util.TurbineConfig;
32  import org.apache.turbine.util.StringUtils;
33  
34  // Jetspeed imports
35  import org.apache.jetspeed.test.JetspeedTestCase;
36  
37  /***
38   * TestTurbineCache
39   *
40   * @author <a href="paulsp@apache.org">Paul Spencer</a>
41   * @version $Id: TestTurbineCache.java,v 1.1 2004/04/07 22:02:42 jford Exp $
42   */
43  public class TestTurbineCache extends JetspeedTestCase {
44      
45      private static final String cacheKey = new String("CacheKey");
46      private static final String cacheKey_2 = new String("CacheKey_2");
47      private static final long TURBINE_CACHE_REFRESH = 5000; // in millis
48      private static final long TEST_EXPIRETIME = TURBINE_CACHE_REFRESH + 1000;
49      private static final long TEST_TIMETOLIVE = TEST_EXPIRETIME * 5;
50  
51      /***
52       * Configuration object to run Turbine outside a servlet container
53       * ( uses turbine.properties )
54       */
55      private static TurbineConfig config = null;
56      
57      /***
58       * Sets up TurbineConfig using the system property:
59       * <pre>turbine.properties</pre>
60       */
61      static
62      {
63          try
64          {
65              config = new TurbineConfig( "webapp",
66              "/WEB-INF/conf/TurbineResources.properties");
67              config.init();
68          }
69          catch (Exception e)
70          {
71              fail(StringUtils.stackTrace(e));
72          }
73      }
74  
75      /***
76       * Defines the testcase name for JUnit.
77       *
78       * @param name the testcase's name.
79       */
80      public TestTurbineCache( String name ) {
81          super( name );
82      }
83      
84      /***
85       * Start the tests.
86       *
87       * @param args the arguments. Not used
88       */
89      public static void main(String args[]) {
90          junit.awtui.TestRunner.main( new String[] { TestTurbineCache.class.getName() } );
91      }
92   
93      public void setup() {
94  //        getLogger().warn("Caching test may take a few minutes");
95          System.out.println("Caching test may take a few minutes");
96      }
97      /***
98       * Creates the test suite.
99       *
100      * @return a test suite (<code>TestSuite</code>) that includes all methods
101      *         starting with "test"
102      */
103     public static Test suite() {
104         // All methods starting with "test" will be executed in the test suite.
105         return new TestSuite( TestTurbineCache.class );
106     }
107     
108     /***
109      * Simple test that verify an object can be created and deleted.
110      * @throws Exception
111      */
112     public void testSimpleAddGetCacheObject() throws Exception {
113         String testString = new String( "This is a test");
114         Object retrievedObject = null;
115         CachedObject cacheObject1 = null;
116         
117         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
118         .getInstance()
119         .getService( GlobalCacheService.SERVICE_NAME );
120         
121         // Create object
122         cacheObject1 = new CachedObject(testString);
123         assertNotNull( "Failed to create a cachable object 1", cacheObject1);
124         
125         // Add object to cache
126         globalCache.addObject(cacheKey, cacheObject1);
127         
128         // Get object from cache
129         retrievedObject = globalCache.getObject(cacheKey);
130         assertNotNull( "Did not retrieved a cached object 1", retrievedObject);
131         assertTrue( "Did not retrieved a correct, expected cached object 1", retrievedObject == cacheObject1);
132         
133         // Remove object from cache
134         globalCache.removeObject(cacheKey);
135         
136         // Verify object removed from cache
137         retrievedObject = null;
138         cacheObject1 = null;
139         try {
140             retrievedObject = globalCache.getObject(cacheKey);
141             assertNull( "Retrieved the deleted cached object 1 and did not get expected ObjectExpiredException", retrievedObject);
142             assertNotNull( "Did not get expected ObjectExpiredException retrieving a deleted object", retrievedObject);
143         } catch (ObjectExpiredException e) {
144             assertNull( "Retrieved the deleted cached object 1, but caught expected ObjectExpiredException exception", retrievedObject);
145         } catch (Exception e) {
146             throw e;
147         }
148         
149         // Remove object from cache that does NOT exist in the cache
150         globalCache.removeObject(cacheKey);
151     }
152     
153     /***
154      * Simple test that adds, retrieves, and deletes 2 object.
155      *
156      * @throws Exception
157      */
158     public void test2ObjectAddGetCachedObject() throws Exception {
159         String testString = new String( "This is a test");
160         Object retrievedObject = null;
161         CachedObject cacheObject1 = null;
162         CachedObject cacheObject2 = null;
163         
164         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
165         .getInstance()
166         .getService( GlobalCacheService.SERVICE_NAME );
167         
168         // Create and add Object #1
169         cacheObject1 = new CachedObject(testString);
170         assertNotNull( "Failed to create a cachable object 1", cacheObject1);
171         globalCache.addObject(cacheKey, cacheObject1);
172         retrievedObject = globalCache.getObject(cacheKey);
173         assertNotNull( "Did not retrieved a cached object 1", retrievedObject);
174         assertEquals( "Did not retrieved correct cached object", cacheObject1, retrievedObject);
175         
176         // Create and add Object #2
177         cacheObject2 = new CachedObject(testString);
178         assertNotNull( "Failed to create a cachable object 2", cacheObject2);
179         globalCache.addObject(cacheKey_2, cacheObject2);
180         retrievedObject = globalCache.getObject(cacheKey_2);
181         assertNotNull( "Did not retrieved a cached object 2", retrievedObject);
182         assertEquals( "Did not retrieved correct cached object 2", cacheObject2, retrievedObject);
183         
184         // Get object #1
185         retrievedObject = globalCache.getObject(cacheKey);
186         assertNotNull( "Did not retrieved a cached object 1. Attempt #2", retrievedObject);
187         assertEquals( "Did not retrieved correct cached object 1. Attempt #2", cacheObject1, retrievedObject);
188         
189         // Get object #1
190         retrievedObject = globalCache.getObject(cacheKey);
191         assertNotNull( "Did not retrieved a cached object 1. Attempt #3", retrievedObject);
192         assertEquals( "Did not retrieved correct cached object 1. Attempt #3", cacheObject1, retrievedObject);
193         
194         // Get object #2
195         retrievedObject = globalCache.getObject(cacheKey_2);
196         assertNotNull( "Did not retrieved a cached object 2. Attempt #2", retrievedObject);
197         assertEquals( "Did not retrieved correct cached object 2 Attempt #2", cacheObject2, retrievedObject);
198         
199         // Remove objects
200         globalCache.removeObject(cacheKey);
201         globalCache.removeObject(cacheKey_2);
202     }
203     
204     /***
205      * Verify that an object will throw the ObjectExpiredException
206      * when it now longer exists in cache.
207      *
208      * @throws Exception
209      */    
210     public void testObjectExpiration() throws Exception {
211         String testString = new String( "This is a test");
212         Object retrievedObject = null;
213         CachedObject cacheObject = null;
214         
215 //        getLogger().warn("This test will take a few mintes");
216         System.out.println("This test will take a few mintes");
217         
218         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
219         .getInstance()
220         .getService( GlobalCacheService.SERVICE_NAME );
221         
222         // Create and add Object that expires in 1000 millis (1 second)
223         cacheObject = new CachedObject(testString, 1000);
224         assertNotNull( "Failed to create a cachable object", cacheObject);
225         long addTime = System.currentTimeMillis();
226         globalCache.addObject(cacheKey, cacheObject);
227         
228         // Try to get un-expired object
229         try {
230             retrievedObject = null;
231             retrievedObject = globalCache.getObject(cacheKey);
232             assertNotNull( "Did not retrieved a cached object", retrievedObject);
233             assertEquals( "Did not retrieved correct cached object", cacheObject, retrievedObject);
234         } catch (ObjectExpiredException e) {
235             assertTrue( "Object expired early ( " + (System.currentTimeMillis() - addTime) + " millis)", false);
236         } catch (Exception e) {
237             throw e;
238         }
239         
240         // Sleep 1500 Millis (1.5 seconds)
241         Thread.sleep(1500);
242         
243         // Try to get expired object
244         try {
245             retrievedObject = null;
246             retrievedObject = globalCache.getObject(cacheKey);
247             assertNull( "Retrieved the expired cached object  and did not get expected ObjectExpiredException", retrievedObject);
248             assertNotNull( "Did not get expected ObjectExpiredException retrieving an expired object", retrievedObject);
249         } catch (ObjectExpiredException e) {
250             assertNull( "Retrieved the expired cached object, but caught expected ObjectExpiredException exception", retrievedObject);
251         } catch (Exception e) {
252             throw e;
253         }
254         
255         // Remove objects
256         globalCache.removeObject(cacheKey);
257     }
258 
259     /***
260      * Verify the all object will be flushed from the cache.
261      *
262      * This test can take server minutes.
263      *
264      * @throws Exception
265      */    
266 
267     public void testCacheFlush() throws Exception {
268         String testString = new String( "This is a test");
269         Object retrievedObject = null;
270         CachedObject cacheObject = null;
271         
272 
273         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
274         .getInstance()
275         .getService( GlobalCacheService.SERVICE_NAME );
276         
277         // Create and add Object that expires in 1 turbine Refresh + 1 millis 
278         cacheObject = new CachedObject(testString, (TURBINE_CACHE_REFRESH*5) + 1);
279         assertNotNull( "Failed to create a cachable object", cacheObject);
280         long addTime = System.currentTimeMillis();
281         globalCache.addObject(cacheKey, cacheObject);
282 
283         // 1 Refresh
284         Thread.sleep(TURBINE_CACHE_REFRESH + 1);
285         assertTrue("No object in cache before flush", (0 < globalCache.getNumberOfObjects()));
286         
287         // Flush Cache
288         globalCache.flushCache();
289 
290         // Wait 15 seconds, 3 Refresh
291         Thread.sleep((TURBINE_CACHE_REFRESH * 2) + 1);
292         assertEquals("After refresh", 0, globalCache.getNumberOfObjects());
293         // Remove objects
294         globalCache.removeObject(cacheKey);
295     }
296 
297     /***
298      * Verify the Cache count is correct.
299      *
300      * This test can take serveral minutes.
301      *
302      * @throws Exception
303      */    
304     
305     public void testObjectCount() throws Exception {
306 
307         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
308         .getInstance()
309         .getService( GlobalCacheService.SERVICE_NAME );
310         assertNotNull("Could not retrive cache service.", globalCache);
311         
312         // Create and add Object that expires in 1.5 turbine Refresh
313         long expireTime = TURBINE_CACHE_REFRESH + TURBINE_CACHE_REFRESH/2;
314         CachedObject cacheObject = new CachedObject("This is a test", expireTime);
315         assertNotNull( "Failed to create a cachable object", cacheObject);
316 
317         globalCache.addObject(cacheKey, cacheObject);
318         assertEquals("After adding 1 Object", 1, globalCache.getNumberOfObjects());
319         
320         // Wait until we're passed 1 refresh, but not half way.
321         Thread.sleep(TURBINE_CACHE_REFRESH + TURBINE_CACHE_REFRESH/3);
322         assertEquals("After one refresh", 1, globalCache.getNumberOfObjects());
323 
324         // Wait until we're passed 2 more refreshes
325         Thread.sleep((TURBINE_CACHE_REFRESH * 2) + TURBINE_CACHE_REFRESH/3);
326         assertEquals("After three refreshes", 0, globalCache.getNumberOfObjects());
327     }
328 
329     /***
330      * Verfy a refreshable object will refreshed in the following cases:
331      * o The object is retrieved via getObject an it is stale.
332      * o The object is determied to be stale during a cache
333      *   refresh
334      *
335      * This test can take serveral minutes.
336      *
337      * @throws Exception
338      */    
339     public void testRefreshableObject() throws Exception {
340         String testString = new String( "This is a test");
341         Object retrievedObject = null;
342         RefreshableCachedObject cacheObject = null;
343         long addTime = 0;
344         
345         boolean turbineCachePatchApplied = false; // FIXME:  Remove when patch applied
346         
347         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
348         .getInstance()
349         .getService( GlobalCacheService.SERVICE_NAME );
350         
351         // Create and add Object that expires in TEST_EXPIRETIME millis.
352         cacheObject = new RefreshableCachedObject(new RefreshableObject(), TEST_EXPIRETIME);
353         assertNotNull( "Failed to create a cachable object", cacheObject);
354         globalCache.addObject(cacheKey, cacheObject);
355         addTime = System.currentTimeMillis();
356         
357         // Try to get un-expired object
358         try {
359             retrievedObject = null;
360             retrievedObject = globalCache.getObject(cacheKey);
361             assertNotNull( "Did not retrieved a cached object", retrievedObject);
362             assertEquals( "Did not retrieved correct cached object", cacheObject, retrievedObject);
363         } catch (ObjectExpiredException e) {
364             assertTrue( "Object expired early ( " + (System.currentTimeMillis() - addTime) + " millis)", false);
365         } catch (Exception e) {
366             throw e;
367         }
368         
369         // Wait 1 Turbine cache refresh + 1 second.
370         Thread.sleep(TEST_EXPIRETIME + 1000);
371         
372         // Try to get expired object
373         try {
374             retrievedObject = null;
375             retrievedObject = globalCache.getObject(cacheKey);
376             assertNotNull( "Did not retrieved a cached object, after sleep", retrievedObject);
377             assertNotNull( "Cached object has no contents, after sleep.", ((RefreshableCachedObject)retrievedObject).getContents());
378             assertTrue( "Object did not refresh.", ( ((RefreshableObject)((RefreshableCachedObject)retrievedObject).getContents()).getRefreshCount() > 0));
379         } catch (ObjectExpiredException e) {
380             assertTrue( "Received unexpected ObjectExpiredException exception "
381             + "when retrieving refreshable object after ( "
382             + (System.currentTimeMillis() - addTime) + " millis)", false);
383         } catch (Exception e) {
384             throw e;
385         }
386         
387         // See if object will expires (testing every second for 100 seconds.  It sould not!
388         for (int i=0; (i<100); i++) { 
389             Thread.sleep(1000); // Sleep 0.5 seconds
390             
391             // Try to get expired object
392             try {
393                 retrievedObject = null;
394                 retrievedObject = globalCache.getObject(cacheKey);
395                 assertNotNull( "Did not retrieved a cached object, after sleep", retrievedObject);
396                 assertNotNull( "Cached object has no contents, after sleep.", ((RefreshableCachedObject)retrievedObject).getContents());
397                 assertTrue( "Object did not refresh.", ( ((RefreshableObject)((RefreshableCachedObject)retrievedObject).getContents()).getRefreshCount() > 0));
398             } catch (ObjectExpiredException e) {
399                 assertTrue( "Received unexpected ObjectExpiredException exception "
400                 + "when retrieving refreshable object after ( "
401                 + (System.currentTimeMillis() - addTime) + " millis)", false);
402             } catch (Exception e) {
403                 throw e;
404             }
405         }
406         
407         // Remove objects
408         globalCache.removeObject(cacheKey);
409     }
410     
411     /***
412      * Verify a cached object will be delete after it has been
413      * untouched beyond it's TimeToLive.
414      *
415      * This test can take serveral minutes.
416      *
417      * @throws Exception
418      */    
419     public void testRefreshableTimeToLive() throws Exception {
420         String testString = new String( "This is a test");
421         Object retrievedObject = null;
422         RefreshableCachedObject cacheObject = null;
423         long addTime = 0;
424         
425         GlobalCacheService globalCache = (GlobalCacheService)TurbineServices
426         .getInstance()
427         .getService( GlobalCacheService.SERVICE_NAME );
428         
429         // Create and add Object that expires in TEST_EXPIRETIME millis.
430         cacheObject = new RefreshableCachedObject(new RefreshableObject(), TEST_EXPIRETIME);
431         assertNotNull( "Failed to create a cachable object", cacheObject);
432         cacheObject.setTTL(TEST_TIMETOLIVE);
433 
434         // Verify TimeToLive was set
435         assertEquals( "Returned TimeToLive", TEST_TIMETOLIVE, cacheObject.getTTL());
436 
437         // Add object to Cache
438         globalCache.addObject(cacheKey, cacheObject);
439         addTime = System.currentTimeMillis();
440         
441         // Try to get un-expired object
442         try {
443             retrievedObject = null;
444             retrievedObject = globalCache.getObject(cacheKey);
445             assertNotNull( "Did not retrieved a cached object", retrievedObject);
446             assertEquals( "Did not retrieved correct cached object", cacheObject, retrievedObject);
447         } catch (ObjectExpiredException e) {
448             assertTrue( "Object expired early ( " + (System.currentTimeMillis() - addTime) + " millis)", false);
449         } catch (Exception e) {
450             throw e;
451         }
452         
453         // Wait long enough to allow object to expire, but do not exceed TTL
454         Thread.sleep(TEST_TIMETOLIVE - 2000);
455         
456         // Try to get expired object
457         try {
458             retrievedObject = null;
459             retrievedObject = globalCache.getObject(cacheKey);
460             assertNotNull( "Did not retrieved a cached object, after sleep", retrievedObject);
461             assertNotNull( "Cached object has no contents, after sleep.", ((RefreshableCachedObject)retrievedObject).getContents());
462             assertTrue( "Object did not refresh.", ( ((RefreshableObject)((RefreshableCachedObject)retrievedObject).getContents()).getRefreshCount() > 0));
463         } catch (ObjectExpiredException e) {
464             assertTrue( "Received unexpected ObjectExpiredException exception "
465             + "when retrieving refreshable object after ( "
466             + (System.currentTimeMillis() - addTime) + " millis)", false);
467         } catch (Exception e) {
468             throw e;
469         }
470         
471         // Wait long enough to allow object to expire and exceed TTL
472         Thread.sleep(TEST_TIMETOLIVE +5000);
473         
474         // Try to get expired object
475         try {
476             retrievedObject = null;
477             retrievedObject = globalCache.getObject(cacheKey);
478             assertNull( "Retrieved a cached object, after exceeding TimeToLive", retrievedObject);
479         } catch (ObjectExpiredException e) {
480             assertNull( "Retrieved the expired cached object, but caught expected ObjectExpiredException exception", retrievedObject);
481         } catch (Exception e) {
482             throw e;
483         }
484     }
485 
486     /***
487      * Simple object that can be refreshed
488      */
489     class RefreshableObject implements Refreshable {
490         
491         private int refreshCount = 0;
492         
493         /***
494          * Increment the refresh counter
495          */
496         public void refresh() {
497             this.refreshCount++;
498         }
499         
500         /***
501          * Reutrn the number of time this object has been refreshed
502          *
503          * @return Number of times refresh() has been called
504          */
505         public int getRefreshCount() {
506             return this.refreshCount;
507         }
508         
509     }
510     
511 }