/*
* 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.Cache;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.UnitTestCacheFactory;
import org.jboss.cache.config.BuddyReplicationConfig;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
import org.jboss.cache.config.Configuration.CacheMode;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
import org.jboss.cache.loader.CacheLoader;
import org.jboss.cache.loader.CacheLoaderManager;
import org.jboss.cache.loader.DummyInMemoryCacheLoader;
import org.jboss.cache.transaction.DummyTransactionManagerLookup;
import org.jboss.cache.util.TestingUtil;
import org.jgroups.Address;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import javax.transaction.TransactionManager;
import java.util.ArrayList;
import java.util.List;
/**
* Base class for BR tests
*
* @author <a href="mailto:manik AT jboss DOT org">Manik Surtani (manik AT jboss DOT org)</a>
*/
@Test(groups = {"functional", "jgroups"})
public abstract class BuddyReplicationTestsBase
{
protected ThreadLocal<List<CacheSPI<Object, Object>>> cachesTL = new ThreadLocal<List<CacheSPI<Object, Object>>>();
protected BuddyFqnTransformer fqnTransformer = new BuddyFqnTransformer();
@AfterMethod(alwaysRun = true)
public void tearDown() throws Exception
{
System.out.println("***** TEARING DOWN *****");
System.setProperty("org.jboss.cache.shutdown.force", "true");
List<CacheSPI<Object, Object>> caches = cachesTL.get();
if (caches != null)
{
// an optimisation to aid the progress of unit tests, especially in the case of TCP connections. Note that this
// is NOT necessary in live systems since each cache would typically be in a separate JVM.
for (CacheSPI c : caches)
{
if (c != null && c.getBuddyManager() != null) c.getBuddyManager().stop();
}
for (CacheSPI c : caches)
{
if (c != null)
{
TransactionManager tm = c.getTransactionManager();
if (tm != null)
{
try
{
if (tm.getTransaction() != null) tm.rollback();
}
catch (Exception e)
{
// error rolling back gtx2EntryMap
e.printStackTrace();
}
}
CacheLoaderManager clm = c.getCacheLoaderManager();
if (clm != null)
{
CacheLoader cl = c.getCacheLoaderManager().getCacheLoader();
try
{
if (cl != null) cl.remove(Fqn.ROOT);
}
catch (Exception e)
{
// unable to clean cache loader
e.printStackTrace();
}
}
c.stop();
c = null;
}
}
}
cachesTL.set(null);
System.gc();
new UnitTestCacheFactory().cleanUp();
}
protected final static int VIEW_BLOCK_TIMEOUT = 5000;
protected CacheSPI<Object, Object> createCache(int numBuddies, String buddyPoolName) throws Exception
{
return createCache(numBuddies, buddyPoolName, false, true);
}
protected CacheSPI<?, ?> createCache(int numBuddies, String buddyPoolName, boolean useDataGravitation) throws Exception
{
return createCache(numBuddies, buddyPoolName, useDataGravitation, true);
}
protected CacheSPI<Object, Object> createCache(int numBuddies, String buddyPoolName, boolean useDataGravitation, boolean start) throws Exception
{
return createCache(false, numBuddies, buddyPoolName, useDataGravitation, true, start);
}
protected CacheSPI<Object, Object> createCache(boolean optimisticLocks, int numBuddies, String buddyPoolName, boolean useDataGravitation, boolean start) throws Exception
{
return createCache(optimisticLocks, numBuddies, buddyPoolName, useDataGravitation, true, start);
}
protected CacheSPI<?, ?> createCache(int numBuddies, String buddyPoolName, boolean useDataGravitation, boolean removeOnFind, boolean start) throws Exception
{
return createCache(false, numBuddies, buddyPoolName, useDataGravitation, removeOnFind, start);
}
protected CacheSPI<Object, Object> createCache(boolean optimisticLocks, int numBuddies, String buddyPoolName, boolean useDataGravitation, boolean removeOnFind, boolean start) throws Exception
{
CacheSPI<Object, Object> c = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(UnitTestCacheConfigurationFactory.createConfiguration(CacheMode.REPL_SYNC, false, false, true), false);
String threadId = Thread.currentThread().getName();
//c.getConfiguration().setClusterName("BuddyReplicationTest-" + threadId);
BuddyReplicationConfig brc = new BuddyReplicationConfig();
if (buddyPoolName != null) brc.setBuddyPoolName(buddyPoolName);
brc.setEnabled(true);
brc.setBuddyCommunicationTimeout(500000);
brc.setDataGravitationRemoveOnFind(removeOnFind);
brc.setDataGravitationSearchBackupTrees(true);
brc.setAutoDataGravitation(useDataGravitation);
NextMemberBuddyLocatorConfig nextMemberBuddyLocatorConfig = new NextMemberBuddyLocatorConfig();
nextMemberBuddyLocatorConfig.setNumBuddies(numBuddies);
brc.setBuddyLocatorConfig(nextMemberBuddyLocatorConfig);
c.getConfiguration().setBuddyReplicationConfig(brc);
c.getConfiguration().setFetchInMemoryState(true);
c.getConfiguration().setNodeLockingScheme(optimisticLocks ? NodeLockingScheme.OPTIMISTIC : getNonOptimisticLockingScheme());
c.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
c.getConfiguration().setSyncCommitPhase(true);// helps track down breakages
// Call the hook that allows mux integration if that's what the test wants
configureMultiplexer(c);
if (start)
{
c.start();
validateMultiplexer(c);
}
return c;
}
protected NodeLockingScheme getNonOptimisticLockingScheme()
{
return NodeLockingScheme.PESSIMISTIC;
}
/**
* Provides a hook for multiplexer integration. This default implementation
* is a no-op; subclasses that test mux integration would override
* to integrate the given cache with a multiplexer.
* <p/>
* param cache a cache that has been configured but not yet created.
*/
protected void configureMultiplexer(Cache cache) throws Exception
{
// default does nothing
}
/**
* Provides a hook to check that the cache's channel came from the
* multiplexer, or not, as expected. This default impl asserts that
* the channel did not come from the multiplexer.
*
* @param cache a cache that has already been started
*/
protected void validateMultiplexer(Cache cache)
{
assertFalse("Cache is not using multiplexer", cache.getConfiguration().isUsingMultiplexer());
}
protected List<CacheSPI<Object, Object>> createCaches(int numCaches, boolean useBuddyPool) throws Exception
{
return createCaches(1, numCaches, useBuddyPool, false);
}
protected List<CacheSPI<Object, Object>> createCaches(int numCaches, boolean useBuddyPool, boolean useDataGravitation, boolean optimisticLocks) throws Exception
{
return createCaches(1, numCaches, useBuddyPool, useDataGravitation, optimisticLocks);
}
protected List<CacheSPI<Object, Object>> createCaches(int numCaches, boolean useBuddyPool, boolean useDataGravitation) throws Exception
{
return createCaches(1, numCaches, useBuddyPool, useDataGravitation);
}
protected List<CacheSPI<Object, Object>> createCachesWithCacheLoader(int numCaches, boolean useDataGravitation, boolean removeOnFind, boolean passivation) throws Exception
{
return this.createCachesWithCacheLoader(numCaches, useDataGravitation, removeOnFind, passivation, false);
}
protected List<CacheSPI<Object, Object>> createCachesWithCacheLoader(int numCaches, boolean useDataGravitation, boolean removeOnFind, boolean passivation, boolean fetchPersistent) throws Exception
{
List<CacheSPI<Object, Object>> caches = new ArrayList<CacheSPI<Object, Object>>();
for (int i = 0; i < numCaches; i++)
{
caches.add(createCacheWithCacheLoader(useDataGravitation, removeOnFind, passivation, fetchPersistent, true));
}
// allow some time for the caches to start up and discover each other
TestingUtil.blockUntilViewsReceived(caches.toArray(new Cache[0]), VIEW_BLOCK_TIMEOUT);
TestingUtil.sleepThread(getSleepTimeout());
return caches;
}
protected CacheSPI createCacheWithCacheLoader(boolean useDataGravitation, boolean removeOnFind, boolean passivation, boolean fetchPersistent, boolean start) throws Exception
{
CacheSPI cache = createCache(1, null, useDataGravitation, removeOnFind, false);
CacheLoaderConfig config = new CacheLoaderConfig();
IndividualCacheLoaderConfig iclc = new IndividualCacheLoaderConfig();
iclc.setClassName(DummyInMemoryCacheLoader.class.getName());
iclc.setFetchPersistentState(fetchPersistent);
config.addIndividualCacheLoaderConfig(iclc);
config.setShared(false);
config.setPassivation(passivation);
cache.getConfiguration().setCacheLoaderConfig(config);
if (start)
{
cache.start();
}
return cache;
}
protected List<CacheSPI<Object, Object>> createCaches(int numBuddies, int numCaches, boolean useBuddyPool) throws Exception
{
return createCaches(numBuddies, numCaches, useBuddyPool, false);
}
protected List<CacheSPI<Object, Object>> createCaches(int numBuddies, int numCaches, boolean useBuddyPool, boolean useDataGravitation) throws Exception
{
return createCaches(numBuddies, numCaches, useBuddyPool, useDataGravitation, false);
}
protected List<CacheSPI<Object, Object>> createCaches(int numBuddies, int numCaches, boolean useBuddyPool, boolean useDataGravitation, boolean optimisticLocks) throws Exception
{
return createCaches(numBuddies, numCaches, useBuddyPool, useDataGravitation, optimisticLocks, true);
}
protected List<CacheSPI<Object, Object>> createCaches(int numBuddies, int numCaches, boolean useBuddyPool, boolean useDataGravitation, boolean optimisticLocks, boolean start) throws Exception
{
List<CacheSPI<Object, Object>> caches = new ArrayList<CacheSPI<Object, Object>>(numCaches);
for (int i = 0; i < numCaches; i++)
caches.add(createCache(optimisticLocks, numBuddies, useBuddyPool ? Character.toString((char) ('A' + i)) : null, useDataGravitation, start));
if (start)
{
// allow some time for the caches to start up and discover each other
TestingUtil.blockUntilViewsReceived(caches.toArray(new Cache[0]), VIEW_BLOCK_TIMEOUT);
TestingUtil.sleepThread(getSleepTimeout());
}
return caches;
}
protected void printBuddyGroup(Cache cache)
{
BuddyManager bm = ((CacheSPI) cache).getBuddyManager();
BuddyGroup bg = bm.buddyGroup;
System.out.println("*** " + bg);
System.out.println(" Groups I participate in: " + bm.buddyGroupsIParticipateIn.keySet());
}
/**
* This is to allow for any state transfers involved (when assigning a buddy) to complete
*/
protected int getSleepTimeout()
{
return 1000;
}
protected void assertIsBuddy(Cache dataOwner, Cache buddy, boolean onlyBuddy)
{
Address dataOwnerLocalAddress = dataOwner.getLocalAddress();
Address buddyLocalAddress = buddy.getLocalAddress();
System.out.println("*** assert with groups. Testing that " + buddyLocalAddress + " is a buddy for owner " + dataOwnerLocalAddress + " only buddy? " + onlyBuddy);
printBuddyGroup(dataOwner);
BuddyManager dataOwnerBuddyManager = ((CacheSPI) dataOwner).getBuddyManager();
BuddyManager buddyBuddyManager = ((CacheSPI) buddy).getBuddyManager();
// lets test things on the data owner's side of things
if (onlyBuddy) assertEquals("Should only have one buddy", 1, dataOwnerBuddyManager.getBuddyAddresses().size());
assertTrue(buddyLocalAddress + " should be a buddy to " + dataOwnerLocalAddress, dataOwnerBuddyManager.getBuddyAddresses().contains(buddyLocalAddress));
// and now on the buddy end
BuddyGroup group = buddyBuddyManager.buddyGroupsIParticipateIn.get(dataOwnerLocalAddress);
System.out.println("*** Groups I participate in: " + buddyBuddyManager.buddyGroupsIParticipateIn);
System.out.println("*** Buddy's version of dataOwner's group " + group);
assertTrue("buddy's list of groups it participates in should contain data owner's group name", buddyBuddyManager.buddyGroupsIParticipateIn.containsKey(dataOwnerLocalAddress));
if (onlyBuddy) assertEquals(1, group.getBuddies().size());
assertTrue(buddyLocalAddress + " should be a buddy to " + group.getGroupName(), group.getBuddies().contains(buddyLocalAddress));
}
protected void assertNoLocks(List<CacheSPI<Object, Object>> caches)
{
for (Cache cache : caches)
{
if (cache != null) assertEquals(0, ((CacheSPI) cache).getNumberOfLocksHeld());
}
}
}