/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.cache.aop.eviction;

import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.aop.PojoCache;
import org.jboss.cache.aop.test.Person;
import org.jboss.cache.aop.test.Address;
import org.jboss.cache.aop.test.Student;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.misc.TestingUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Test for pojo eviction, i.e., eviction on pojo level.
 * @author Ben Wang
 */

public class PojoEvictionTest extends TestCase
{
   Log log_= LogFactory.getLog(PojoEvictionTest.class);
   PojoCache cache_;
   int wakeupIntervalMillis_ = 0;

   public PojoEvictionTest(String name)
   {
      super(name);
   }

   protected void setUp() throws Exception
   {
      super.setUp();
      log_.info("setUp() ....");
      String configFile = "META-INF/pojocache-service.xml";
      cache_ = new PojoCache();
      PropertyConfigurator config = new PropertyConfigurator();
      config.configure(cache_, configFile); // read in generic replSync xml
      cache_.start();

      wakeupIntervalMillis_ = cache_.getEvictionThreadWakeupIntervalSeconds() * 1000;
      log_.info("wakeupInterval is " + wakeupIntervalMillis_);
      if (wakeupIntervalMillis_ <= 0)
         fail("setup(): eviction thread wake up interval is illegal " + wakeupIntervalMillis_);
   }

   protected void tearDown() throws Exception
   {
      super.tearDown();
      cache_.stop();
   }

   public void testPutAndEvict() throws Exception
   {
      log_.info("testPutAndEvict() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      cache_.putObject("/pojo", test);
      Person result = (Person)cache_.getObject("/pojo");
      assertEquals(" ", test, result);
      result.setAge(20);

      int period = (wakeupIntervalMillis_ *2+ 500);
      log_.info("period is " + period);
      TestingUtil.sleepThread(period*2);  // it really depends on the eviction thread time.

      assertFalse("pojo node should not exist ", cache_.exists("/pojo"));
      assertEquals("Age should still be after eviction/detachment: ", 20, test.getAge());
   }

   /**
    * THis is not working properly now for maxNode becuase we should evict based on the while graph instead of
    * just children. E.g., in this case, we should evict Student as a whole. But we also need to consider the
    * object graph scenario. We will refactor the eviction policy in 2.0 release to address these.
    */
   public void XtestPutAndMaxNodeEvict() throws Exception
   {
      log_.info("testPutAndMaxNodeEvict() ....");
      String fqn = "/testMaxNode";

      Student test = new Student();
      test.setName("Ben");
      test.setAge(10);
      Address addr = new Address();
      addr.setZip(95123);
      List lang = new ArrayList();
      lang.add("English");
      lang.add("French");
      lang.add("Mandarin");
      test.setLanguages(lang);

      cache_.putObject(fqn, test);
      Person result = (Person)cache_.getObject(fqn);
      assertEquals(" ", test, result);
      result.setAge(20);

      int period = (wakeupIntervalMillis_ *2+ 500);
      log_.info("period is " + period);
      TestingUtil.sleepThread(period*2);  // it really depends on the eviction thread time.

      assertFalse("pojo node should not exist ", cache_.exists(fqn));
      assertEquals("Age should still be after eviction/detachment: ", 20, test.getAge());
   }

   /**
    * This test is passing but still incomplete. We should take the object graph into consideration when
    * trying to evict a pojo. In theory, if a sub-pojo has been refreshed, should we evict the parent object?
    * @throws Exception
    */
   public void testPutObjectGraphAndEvict() throws Exception
   {
      log_.info("testPutGraphAndEvict() ....");
      Person ben = new Person();
      ben.setName("Ben");
      ben.setAge(10);

      Person mary = new Person();
      mary.setName("Mary");
      mary.setAge(20);

      Address addr = new Address();
      addr.setCity("Sunnyvale");
      addr.setZip(95123);

      ben.setAddress(addr);
      mary.setAddress(addr);

      cache_.putObject("/pojo/ben", ben);
      cache_.putObject("/pojo/mary", mary);
      Person result = (Person)cache_.getObject("/pojo/ben");
      assertEquals(" ", ben, result);
      result.setAge(20);

      int period = (wakeupIntervalMillis_);
      log_.info("period is " + period);
      TestingUtil.sleepThread(period/2);  // it really depends on the eviction thread time.
      addr.getZip();

      TestingUtil.sleepThread(period/2);
      addr.getZip();
      TestingUtil.sleepThread(period/2);
      addr.getZip();
      TestingUtil.sleepThread(period/2);
      // It is failing now but need to fix.
      assertFalse("pojo node should not exist ", cache_.exists("/pojo/mary"));
      assertFalse("pojo node should exist ", cache_.exists("/pojo/ben"));
      assertEquals("Age should still be after eviction/detachment: ", 20, ben.getAge());
   }

   public static Test suite() throws Exception
   {
      return new TestSuite(PojoEvictionTest.class);
   }


   public static void main(String[] args) throws Exception
   {
      junit.textui.TestRunner.run(PojoEvictionTest.suite());
   }

}
