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

import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;
import org.jboss.cache.misc.TestingUtil;

import java.io.File;

/**
 * Tests how groups are formed and disbanded
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class BuddyAssignmentStateTransferTest extends BuddyReplicationTestsBase
{

    protected int timeout = 10000; // !!!
    protected int getSleepTimeout()
    {
        return timeout;
    }
    
    public void testNonRegionBasedStateTransfer() throws Exception
    {
       TreeCache[] caches = new TreeCache[2];
       try
       {
          caches[0] = createCache(1, "TEST", false, true);
          
          Fqn main = Fqn.fromString("/a/b/c");
          caches[0].put(main, "name", "Joe");
          
          caches[1] = createCache(1, "TEST", false, true);
          
          TestingUtil.blockUntilViewsReceived(caches, VIEW_BLOCK_TIMEOUT);
          TestingUtil.sleepThread(getSleepTimeout());
          
          Fqn test = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, 
                             BuddyManager.getGroupNameFromAddress(caches[0].getLocalAddress()));
          test = new Fqn(test, main);
          
          assertEquals("State transferred", "Joe", caches[1].get(test, "name"));
          
          TreeCache[] old = caches;
          caches = new TreeCache[3];
          System.arraycopy(old, 0, caches, 0, old.length);
          caches[2] = createCache(1, "TEST", false, true);
          
          TestingUtil.blockUntilViewsReceived(caches, VIEW_BLOCK_TIMEOUT);
          TestingUtil.sleepThread(getSleepTimeout());
          
          assertNull("State not transferred", caches[2].get(test, "name"));
          
          // Make 2 the buddy of 0
          caches[1].stopService();
          caches[1] = null;

          TestingUtil.sleepThread(getSleepTimeout());
          
          assertEquals("State transferred", "Joe", caches[2].get(test, "name"));
       }
       finally
       {
          cleanup(caches);
       }
    }
    
    public void testRegionBasedStateTransfer() throws Exception
    {
       TreeCache[] caches = new TreeCache[4];

       try
       {
          caches[0] = createCache(1, "TEST", false, false);
          caches[1] = createCache(1, "TEST", false, false);
          caches[2] = createCache(1, "TEST", false, false);
          // JBCACHE-1234 -- add a 4th cache so when we kill caches[1]
          // caches[0] is not the backup node for caches[2] (although
          // caches[2] *is* the backup node for caches[0]
          caches[3] = createCache(1, "TEST", false, false);
          caches[0].setInactiveOnStartup(true);
          caches[1].setInactiveOnStartup(true);
          caches[2].setInactiveOnStartup(true);
          caches[3].setInactiveOnStartup(true);
          caches[0].setUseRegionBasedMarshalling(true);
          caches[1].setUseRegionBasedMarshalling(true);
          caches[2].setUseRegionBasedMarshalling(true);
          caches[3].setUseRegionBasedMarshalling(true);
          caches[0].startService();
          caches[1].startService();
          caches[2].startService();
          caches[3].startService();
          
          TestingUtil.blockUntilViewsReceived(caches, VIEW_BLOCK_TIMEOUT);
          TestingUtil.sleepThread(getSleepTimeout());
          
          caches[0].activateRegion("/a");
          caches[1].activateRegion("/a");
          caches[2].activateRegion("/a");
          caches[3].activateRegion("/a");
          
          caches[0].activateRegion("/d");
          caches[1].activateRegion("/d");
          
          Fqn mainA = Fqn.fromString("/a/b/c");
          caches[0].put(mainA, "name", "Joe");
          
          Fqn mainD = Fqn.fromString("/d/e/f");
          caches[0].put(mainD, "name", "Joe");
          
          Fqn group = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, 
                              BuddyManager.getGroupNameFromAddress(caches[0].getLocalAddress()));
          Fqn testA = new Fqn(group, mainA);
          assertEquals("/a replicated", "Joe", caches[1].get(testA, "name"));
          assertNull("No backup of /a", caches[2].get(testA, "name"));
          
          Fqn testD = new Fqn(group, mainD);
          assertEquals("/d replicated", "Joe", caches[1].get(testD, "name"));
          assertNull("No backup of /d", caches[2].get(testD, "name"));
          
          // Make 2 the buddy of 0 -- this should cause a push from 0 to 2
          caches[1].stopService();
          caches[1] = null;

          TestingUtil.sleepThread(getSleepTimeout());          
          
          assertEquals("/a state transferred", "Joe", caches[2].get(testA, "name"));
          assertNull("/d state not transferred", caches[2].get(testD, "name"));

          // JBCACHE-1234 -- Activate region on 2 and 3.  This should cause
          // a pull from 0 by and from 2 by 3.
          caches[2].activateRegion("/d");
          caches[3].activateRegion("/d");
          assertEquals("/d transferred to cache 2", "Joe", caches[2].get(testD, "name"));
          assertNull("/d state not transferred to cache 3", caches[3].get(testD, "name"));
       }
       finally
       {
           cleanup(caches);
       }
    }
    
    public void testPersistentStateTransfer() throws Exception
    {
       String tmpLoc = System.getProperty("java.io.tmpdir", "/tmp");
       tmpLoc += File.separator + "BuddyReplicationTestsBase-";
       String tmpLoc0 = tmpLoc + 0;
       String tmpLoc1 = tmpLoc + 1;
       TreeCache[] caches = new TreeCache[2];

       try
       {
          caches[0] = createCacheWithCacheLoader(tmpLoc0, false, false, false, true, false);
          caches[0].setFetchInMemoryState(false);
          
          caches[0].startService();
          
          Fqn main = Fqn.fromString("/a/b/c");
          caches[0].put(main, "name", "Joe");
          
          caches[1] = createCacheWithCacheLoader(tmpLoc1, false, false, false, true, false);
          caches[1].setFetchInMemoryState(false);
          
          caches[1].startService();
          
          TestingUtil.blockUntilViewsReceived(caches, VIEW_BLOCK_TIMEOUT);
          TestingUtil.sleepThread(getSleepTimeout());
          
          Fqn group = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, 
                              BuddyManager.getGroupNameFromAddress(caches[0].getLocalAddress()));
          Fqn test = new Fqn(group, main);
          
          assertFalse("/a/b/c not in memory", caches[1].exists(test));
          assertEquals("/a/b/c in cache loader", "Joe", caches[1].get(test, "name"));          
       }
       finally
       {
           cleanup(caches);
       }
    }
}
