/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.eviction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.Region;
import org.jboss.cache.util.TestingUtil;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.EvictionConfig;
import org.jboss.cache.config.EvictionPolicyConfig;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
 * Unit tests for {@link ExpirationPolicy}.
 *
 * @author Elias Ross
 * @version $Revision: 5906 $
 */
@Test(groups = {"functional"})
public class ExpirationPolicyTest
{
   private static final Log log = LogFactory.getLog(ExpirationPolicyTest.class);

   private CacheSPI<Object, Object> cache;

   Fqn fqn1 = Fqn.fromString("/node/1");
   Fqn fqn2 = Fqn.fromString("/node/2");
   Fqn fqn3 = Fqn.fromString("/node/3");
   Fqn fqn4 = Fqn.fromString("/node/4");

   Long future;
   Long past;

   @BeforeMethod(alwaysRun = true)
   public void setUp() throws Exception
   {
      Configuration conf = new Configuration();
      EvictionConfig econf = new EvictionConfig(ExpirationPolicy.class.getName());
      econf.setWakeupIntervalSeconds(1);
      conf.setEvictionConfig(econf);
      cache = (CacheSPI<Object, Object>) new DefaultCacheFactory().createCache(conf, false);
      cache.start();

      future = System.currentTimeMillis() + 4000;
      past = System.currentTimeMillis() - 2000;
   }

   @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
      cache.stop();
   }

   public void testEviction() throws Exception
   {
      cache.put(fqn1, ExpirationConfiguration.EXPIRATION_KEY, future);
      cache.put(fqn2, ExpirationConfiguration.EXPIRATION_KEY, past);
      cache.put(fqn3, ExpirationConfiguration.EXPIRATION_KEY, future);
      cache.put(fqn4, "foo", "bar");
      TestingUtil.sleepThread(2000);
      assertNotNull(cache.getNode(fqn1));
      assertNull(cache.getNode(fqn2));
      assertNotNull(cache.getNode(fqn3));
      assertNotNull(cache.getNode(fqn4));

      log.info("should remove 1 and 3 now");
      TestingUtil.sleepThread(3000);
      assertNull(cache.getNode(fqn1));
      assertNull(cache.getNode(fqn3));
   }

   public void testUpdate() throws Exception
   {
      log.info("update 1 from future to past");
      cache.put(fqn1, ExpirationConfiguration.EXPIRATION_KEY, future);
      assertNotNull(cache.getNode(fqn1));
      TestingUtil.sleepThread(1500);
      cache.put(fqn1, ExpirationConfiguration.EXPIRATION_KEY, past);
      TestingUtil.sleepThread(1500);
      assertNull(cache.getNode(fqn1));
      cache.removeNode(Fqn.ROOT);

   }

   public void testUpdateToFuture() throws Exception
   {
      log.info("update 1 from future to past");
      Long future2 = future + 2000;
      cache.put(fqn1, ExpirationConfiguration.EXPIRATION_KEY, future);
      TestingUtil.sleepThread(2000);
      assertNotNull(cache.getNode(fqn1));
      cache.put(fqn1, ExpirationConfiguration.EXPIRATION_KEY, future2);
      TestingUtil.sleepThread(3000);
      assertNotNull(cache.getNode(fqn1));
      TestingUtil.sleepThread(3000);
      assertNull(cache.getNode(fqn1));
      cache.removeNode(Fqn.ROOT);
   }

   public void testMaxNodes() throws Exception
   {
      log.info("set max nodes to 2, expire soonest to expire first");
      EvictionPolicyConfig epc = cache.getRegionManager().getAllRegions(Region.Type.EVICTION).get(0).getEvictionPolicyConfig();
      ExpirationConfiguration ec = (ExpirationConfiguration) epc;
      ec.setMaxNodes(2);
      Long future2 = future + 500;
      cache.put(fqn1, ExpirationConfiguration.EXPIRATION_KEY, future2);
      cache.put(fqn2, ExpirationConfiguration.EXPIRATION_KEY, future2);
      cache.put(fqn3, ExpirationConfiguration.EXPIRATION_KEY, future);
      cache.put(fqn4, ExpirationConfiguration.EXPIRATION_KEY, past);
      assertEquals(5, cache.getNumberOfNodes());
      Thread.sleep(2000);
      assertNotNull(cache.getNode(fqn1));
      assertNotNull(cache.getNode(fqn2));
      assertNull(cache.getNode(fqn3));
      assertNull(cache.getNode(fqn4));
   }

}
