package org.jboss.cache.mgmt;

import java.util.HashMap;
import java.util.List;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.jboss.cache.Fqn;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.TreeCache;
import org.jboss.cache.interceptors.InvalidationInterceptor;

/**
 * Simple functional tests for InvalidationInterceptor statistics
 * @author Jerry Gauthier
 * @version $Id: InvalidationTest.java 1322 2006-02-26 16:34:17Z jerrygauth $
 */
public class InvalidationTest extends TestCase
{
   private static final String CLUSTER_NAME = "InvalidationTestCluster";
   private static final String CAPITAL = "capital";
   private static final String CURRENCY = "currency";
   private static final String POPULATION = "population";
   private static final String AREA = "area";
   
   TreeCache cache1 = null;
   TreeCache cache2 = null;

   protected void setUp() throws Exception
   {
      super.setUp();
      cache1 = createCache(CLUSTER_NAME);
      cache2 = createCache(CLUSTER_NAME);
   }

   protected void tearDown() throws Exception
   {
      super.tearDown();
      if(cache1 != null)
      {
         cache1.stopService();
         cache1.destroyService();
         cache1 = null;
      }
      if(cache2 != null)
      {
         cache2.stopService();
         cache2.destroyService();
         cache2 = null;
      }
   }

   public void testInvalidationMgmt() throws Exception
   {
      assertNotNull("Cache1 is null.", cache1);
      assertNotNull("Cache2 is null.", cache2);
      
      // populate cache1 with test data 
      loadCache1(cache1);
      
      // confirm that data is in cache1 and not in cache2
      Fqn key = Fqn.fromString("Europe/Austria");
      assertNotNull("Cache1 retrieval error: expected to retrieve " + CAPITAL + " for " + key, cache1.get(key, CAPITAL));
      assertNull("Cache2 retrieval error: did not expect to retrieve " + CAPITAL + " for " + key, cache2.get(key, CAPITAL));
      key = Fqn.fromString("Europe/Albania");
      assertNotNull("Cache1 retrieval error: expected to retrieve " + CAPITAL + " for " + key, cache1.get(key, CAPITAL));
      assertNull("Cache2 retrieval error: did not expect to retrieve " + CAPITAL + " for " + key, cache2.get(key, CAPITAL));
 
      // populate cache2 with test data - this will invalidate Austria
      loadCache2(cache2);
      
      // confirm that Austria is now in cache2 and not in cache1
      key = Fqn.fromString("Europe/Austria");
      assertNull("Cache1 retrieval error: did not expect to retrieve " + CAPITAL + " for " + key, cache1.get(key, CAPITAL));
      assertNotNull("Cache2 retrieval error: expected to retrieve " + CAPITAL + " for " + key, cache2.get(key, CAPITAL));

      // confirm that Albania is still in cache1
      key = Fqn.fromString("Europe/Albania");
      assertNotNull("Cache1 retrieval error after unrelated eviction: expected to retrieve " + CAPITAL + " for " + key, cache1.get(key, CAPITAL));

      // Note: because these tests are normally executed without a server, the interceptor
      // MBeans are usually not available for use in the tests.  Consequently it's necessary 
      // to obtain a reference to the interceptor and work with it directly.
      InvalidationInterceptor mgmt1 = getInvalidationInterceptor(cache1);
      assertNotNull("Cache1 InvalidationInterceptor not found.", mgmt1);
      InvalidationInterceptor mgmt2 = getInvalidationInterceptor(cache2);
      assertNotNull("Cache2 InvalidationInterceptor not found.", mgmt2);      
     
      // verify basic statistics for entries loaded into cache
      assertEquals("Cache1 Invalidations count error: ", new Long(6), new Long(mgmt1.getInvalidations()));
      assertEquals("Cache2 Invalidations count error: ", new Long(10), new Long(mgmt2.getInvalidations()));
      
      // reset statistics
      mgmt1.resetStatistics();
      mgmt2.resetStatistics();
     
      // check the statistics again
      assertEquals("Cache1 Invalidations count error after reset: ", new Long(0), new Long(mgmt1.getInvalidations()));
      assertEquals("Cache2 Invalidations count error after reset: ", new Long(0), new Long(mgmt2.getInvalidations()));

   }
   
   private void loadCache1(TreeCache cache) throws Exception
   {
      cache.put("Europe", new HashMap());
      cache.put("Europe/Austria", new HashMap());      
      cache.put("Europe/Austria", CAPITAL, "Vienna");      
      cache.put("Europe/Austria", CURRENCY, "Euro");      
      cache.put("Europe/Austria", POPULATION, new Integer(8184691));
      
      HashMap albania = new HashMap(4);
      albania.put(CAPITAL, "Tirana");
      albania.put(CURRENCY, "Lek");
      albania.put(POPULATION, new Integer(3563112));
      albania.put(AREA, new Integer(28748));
      cache.put("Europe/Albania", albania);      
      
   }
   
   private void loadCache2(TreeCache cache) throws Exception
   {
      cache.put("Europe", new HashMap());
      cache.put("Europe/Austria", new HashMap());      
      cache.put("Europe/Austria", CAPITAL, "Vienna");      
      cache.put("Europe/Austria", CURRENCY, "Euro");      
      cache.put("Europe/Austria", POPULATION, new Integer(8184691));
      
      cache.put("Europe/Romania", new HashMap());      
      cache.put("Europe/Romania", CAPITAL, "Bucharest");      
      cache.put("Europe/Romania", CURRENCY, "Leu");      
      cache.put("Europe/Romania", POPULATION, new Integer(22329977));
      cache.put("Europe/Romania", AREA, new Integer(237500));
      
   }
   
   private TreeCache createCache(String clusterName) throws Exception
   {
      TreeCache cache = new TreeCache();
      PropertyConfigurator config=new PropertyConfigurator();
      config.configure(cache, "META-INF/invalidationSync-service.xml");
      cache.setCacheMode(TreeCache.INVALIDATION_SYNC);
      cache.setUseInterceptorMbeans(true);
      cache.setClusterName(clusterName);
      cache.createService();
      cache.startService();
      return cache;
   }
   
   private InvalidationInterceptor getInvalidationInterceptor(TreeCache cache)
   {
      List interceptors = cache.getInterceptors();
      if (interceptors.isEmpty())
         return null;
     
     for (int i = 0; i < interceptors.size(); i++)
     {
        Object o = interceptors.get(i);
        if (o instanceof InvalidationInterceptor)
           return (InvalidationInterceptor)o;
     }
     return null;
   }

   public static Test suite()
   {
      return new TestSuite(InvalidationTest.class);
   }

}
