/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.optimistic;

import junit.framework.Assert;
import org.jboss.cache.Fqn;
import org.jboss.cache.OptimisticTreeNode;
import org.jboss.cache.TreeCache;

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

/**
 * Unit test that covers versioning of data and workspace nodes when using optimistic locking.
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class OptimisticVersioningTest extends AbstractOptimisticTestCase
{
   TreeCache cache1, cache2;
   protected void setUp() throws Exception
   {
      super.setUp();
      cache1 = createReplicatedCache(TreeCache.REPL_SYNC);
      cache2 = createReplicatedCache(TreeCache.REPL_SYNC);
   }
   protected void tearDown() throws Exception
   {
      super.tearDown();
      cache1.remove(Fqn.ROOT);
      cache1.stopService();
      cache2.remove(Fqn.ROOT);
      cache2.stopService();
   }
    public OptimisticVersioningTest(String name)
    {
        super(name);
    }

    public void testVersionPropagation() throws Exception
    {
        Fqn fqn = Fqn.fromString("/a/b");
        String key = "key";

        cache1.put(fqn, key, "value");

        DataVersion v1 = ((OptimisticTreeNode) cache1.get(fqn)).getVersion();
        DataVersion v2 = ((OptimisticTreeNode) cache2.get(fqn)).getVersion();

        Assert.assertEquals("value", cache1.get(fqn, key));
        Assert.assertEquals("value", cache2.get(fqn, key));
        Assert.assertEquals("Version info should have propagated", v1, v2);

        // change stuff in the node again...
        cache1.put(fqn, key, "value2");

        v1 = ((OptimisticTreeNode) cache1.get(fqn)).getVersion();
        v2 = ((OptimisticTreeNode) cache2.get(fqn)).getVersion();

        Assert.assertEquals("value2", cache1.get(fqn, key));
        Assert.assertEquals("value2", cache2.get(fqn, key));
        Assert.assertEquals("Version info should have propagated", v1, v2);
    }

    public void testTwoCachesUpdatingSimultaneously() throws Exception
    {
        TransactionManager mgr1 = cache1.getTransactionManager();
        TransactionManager mgr2 = cache2.getTransactionManager();
        Transaction tx1, tx2;

        Fqn fqn = Fqn.fromString("/a/b");
        String key = "key";

        cache1.put(fqn, key, "value");

        DataVersion v1 = ((OptimisticTreeNode) cache1.get(fqn)).getVersion();
        DataVersion v2 = ((OptimisticTreeNode) cache2.get(fqn)).getVersion();

        Assert.assertEquals("value", cache1.get(fqn, key));
        Assert.assertEquals("value", cache2.get(fqn, key));
        Assert.assertEquals("Version info should have propagated", v1, v2);

        // Start a tx on cache 1
        mgr1.begin();
        cache1.put(fqn, key, "value2");
        tx1 = mgr1.suspend();

        // start a tx on cache 2
        mgr2.begin();
        cache2.put(fqn, key, "value3");
        tx2 = mgr2.suspend();

        // which tx completes, which fail?
        mgr1.resume(tx1);
        // should succeed...
        mgr1.commit();

        try
        {
            mgr2.resume(tx2);
            mgr2.commit();
            Assert.assertTrue("Should have failed", false);
        }
        catch (RollbackException rbe)
        {
            Assert.assertTrue("Should have failed", true);
        }

        // data versions should be in sync.
        v1 = ((OptimisticTreeNode) cache1.get(fqn)).getVersion();
        v2 = ((OptimisticTreeNode) cache2.get(fqn)).getVersion();

        Assert.assertEquals("Version info should have propagated", v1, v2);
    }
}
