package org.jboss.cache.invalidation;

import junit.framework.TestCase;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;
import org.jboss.cache.config.Option;
import org.jboss.cache.misc.TestingUtil;
import org.jboss.cache.optimistic.DataVersion;
import org.jboss.cache.optimistic.DefaultDataVersion;

/**
 * Tests the edge cases defined in JBCACHE-806
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
 * @since 1.4.0
 */
public class OptimisticSyncInvalidationTest extends TestCase
{
   private TreeCache[] cache;
   private Fqn fqn = Fqn.fromString("/test/fqn");
   private DataVersion V1 = new DefaultDataVersion(1);
   private DataVersion V2 = new DefaultDataVersion(2);


   protected void setUp() throws Exception
   {
      cache = new TreeCache[2];
      cache[0] = createCache();
      cache[1] = createCache();

      TestingUtil.blockUntilViewsReceived(cache, 5000);
   }

   protected TreeCache createCache() throws Exception
   {
      TreeCache c = new TreeCache();
      c.setCacheMode(TreeCache.INVALIDATION_SYNC); // only use sync.
      c.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
      c.setNodeLockingScheme("OPTIMISTIC");
      c.startService();
      return c;
   }

   protected void tearDown() throws Exception
   {
      if (cache != null)
      {
         cleanupCache(cache[0]);
         cache[0] = null;
         cleanupCache(cache[1]);
         cache[1] = null;

         cache = null;
      }
   }

   /**
    * blocks for a short period for propagation of invalidation message to complete
    */
   protected void pause()
   {
      // no pause for sync invalidation
   }

   private void cleanupCache(TreeCache c) throws Exception
   {
      if (c != null)
      {
         if (c.getTransactionManager().getTransaction() != null)
         {
            c.getTransactionManager().rollback();
         }
         c.stopService();
      }
   }

   public void testCorrectInsertion() throws CacheException
   {
      assertTrue(V2.newerThan(V1));

      Option o = new Option();
      o.setDataVersion(V1);
      cache[0].put(fqn, "k", "v", o);

      pause();

      assertEquals("Should be in cache[0]", "v", cache[0].get(fqn, "k"));
      assertNull("Should not have propagated", cache[1].get(fqn));

      o = new Option();
      o.setDataVersion(V2);
      cache[1].put(fqn, "k", "v", o);

      pause();

      assertEquals("Newer version should be allowed to be inserted", "v", cache[1].get(fqn, "k"));
      assertNull("Newer version should have invalidated older version on remote cache", cache[0].get(fqn));
   }

   public void testIncorrectInsertion() throws CacheException
   {
      assertTrue(V2.newerThan(V1));

      Option o = new Option();
      o.setDataVersion(V2);
      cache[0].put(fqn, "k", "v", o);

      pause();

      assertEquals("Should be in cache[0]", "v", cache[0].get(fqn, "k"));
      assertNull("Should not have propagated", cache[1].get(fqn));

      o = new Option();
      o.setDataVersion(V1);
      cache[1].put(fqn, "k", "v", o);

      pause();

      assertNull("Older version should not be allowed to be inserted", cache[1].get(fqn));
      assertEquals("Newer version should still exist in remote cache", "v", cache[0].get(fqn, "k"));
   }
}
