package org.jboss.cache.invalidation;

import org.jboss.cache.*;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.util.TestingUtil;
import org.jboss.cache.optimistic.DefaultDataVersion;
import org.jboss.cache.transaction.DummyTransactionManagerLookup;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

/**
 * This test simulates the problem described in JBCACHE-1155
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
 * @since 2.1.0
 */
@Test(groups = {"functional", "jgroups"})
public class VersionInconsistencyTest
{
   private Cache cache1, cache2;
   private TransactionManager tm1, tm2;
   private Fqn node = Fqn.fromString("/a");

   @BeforeMethod
   public void setUp()
   {
      cache1 = new DefaultCacheFactory().createCache(false);
      cache2 = new DefaultCacheFactory().createCache(false);

      cache1.getConfiguration().setCacheMode(Configuration.CacheMode.INVALIDATION_SYNC);
      cache2.getConfiguration().setCacheMode(Configuration.CacheMode.INVALIDATION_SYNC);

      cache1.getConfiguration().setNodeLockingScheme(Configuration.NodeLockingScheme.OPTIMISTIC);
      cache2.getConfiguration().setNodeLockingScheme(Configuration.NodeLockingScheme.OPTIMISTIC);

      cache1.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
      cache2.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());

      cache1.start();
      cache2.start();

      tm1 = cache1.getConfiguration().getRuntimeConfig().getTransactionManager();
      tm2 = cache2.getConfiguration().getRuntimeConfig().getTransactionManager();

      TestingUtil.blockUntilViewsReceived(1000, cache1, cache2);
   }

   @AfterMethod
   public void tearDown()
   {
      cache1.stop();
      cache2.stop();
   }

   public void dataInconsistency() throws Exception
   {
      tm1.begin();
      cache1.put(node, "k", "v-older");
      Transaction t1 = tm1.suspend();

      tm2.begin();
      cache2.put(node, "k", "v-newer");
      tm2.commit();

      tm1.resume(t1);
      try
      {
         tm1.commit();
         assert false : "Should not be allowed to commit with older data!!";
      }
      catch (Exception good)
      {
      }

      // the NEWER version of the data should be available, not the OLDER one.

      Object val = cache1.get(node, "k");
      System.out.println("val = " + val);
      assert val == null : "Older data should not have committed";

      val = cache2.get(node, "k");
      System.out.println("val = " + val);
      assert val.equals("v-newer");

      // test node versions
      NodeSPI n = ((CacheSPI) cache1).peek(node, true, true);
      assert ((DefaultDataVersion) n.getVersion()).getRawVersion() == 1 : "Version should be 1";
   }
}
