/*
*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.replicated;
import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.AbstractTreeCacheListener;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.transaction.DummyTransactionManager;
import org.jgroups.View;
import javax.naming.Context;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Test out the TreeCacheListener
*
* @version $Revision: 3100 $
*/
public class SyncCacheListenerTest extends TestCase {
TreeCache cache1, cache2;
int caching_mode=TreeCache.REPL_SYNC;
final String group_name="TreeCacheTestGroup";
String props=
"UDP(ip_mcast=true;ip_ttl=64;loopback=false;mcast_addr=228.1.2.3;" +
"mcast_port=45566;mcast_recv_buf_size=80000;mcast_send_buf_size=150000;" +
"ucast_recv_buf_size=80000;ucast_send_buf_size=150000):" +
"PING(down_thread=true;num_initial_members=2;timeout=500;up_thread=true):" +
"MERGE2(max_interval=20000;min_interval=10000):" +
"FD(down_thread=true;shun=true;up_thread=true):" +
"VERIFY_SUSPECT(down_thread=true;timeout=1500;up_thread=true):" +
"pbcast.NAKACK(down_thread=true;gc_lag=50;retransmit_timeout=600,1200,2400,4800;" +
"up_thread=true):" +
"pbcast.STABLE(desired_avg_gossip=20000;down_thread=true;up_thread=true):" +
"UNICAST(down_thread=true;min_threshold=10;timeout=600,1200,2400;window_size=100):" +
"FRAG(down_thread=true;frag_size=8192;up_thread=true):" +
"pbcast.GMS(join_retry_timeout=2000;join_timeout=5000;print_local_addr=true;shun=true):" +
"pbcast.STATE_TRANSFER(down_thread=true;up_thread=true)";
final static Log log_=LogFactory.getLog(SyncCacheListenerTest.class);
String old_factory=null;
final String FACTORY="org.jboss.cache.transaction.DummyContextFactory";
FIFOSemaphore lock=new FIFOSemaphore(1);
DummyTransactionManager tx_mgr;
Throwable t1_ex, t2_ex, ex=null;
public SyncCacheListenerTest(String name) {
super(name);
}
public void setUp() throws Exception {
super.setUp();
old_factory=System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
tx_mgr=DummyTransactionManager.getInstance();
t1_ex=t2_ex=ex=null;
}
public void tearDown() throws Exception {
super.tearDown();
DummyTransactionManager.destroy();
destroyCaches();
if(old_factory != null) {
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, old_factory);
old_factory=null;
}
}
Transaction beginTransaction() throws SystemException, NotSupportedException {
DummyTransactionManager mgr=DummyTransactionManager.getInstance();
mgr.begin();
Transaction tx=mgr.getTransaction();
return tx;
}
void initCaches(int caching_mode) throws Exception {
this.caching_mode=caching_mode;
cache1=new TreeCache();
cache2=new TreeCache();
cache1.setCacheMode(caching_mode);
cache2.setCacheMode(caching_mode);
cache1.setIsolationLevel(IsolationLevel.SERIALIZABLE);
cache2.setIsolationLevel(IsolationLevel.SERIALIZABLE);
cache1.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
cache2.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
/*
cache1.setTransactionManagerLookupClass("org.jboss.cache.JBossTransactionManagerLookup");
cache2.setTransactionManagerLookupClass("org.jboss.cache.JBossTransactionManagerLookup");
*/
cache1.setLockAcquisitionTimeout(5000);
cache2.setLockAcquisitionTimeout(5000);
cache1.start();
cache2.start();
}
void destroyCaches() throws Exception {
if(cache1 != null)
cache1.stop();
if(cache2 != null)
cache2.stop();
cache1=null;
cache2=null;
}
public void testSyncTxRepl() throws Exception {
Integer age;
Transaction tx;
try {
initCaches(TreeCache.REPL_SYNC);
tx=beginTransaction();
Listener lis = new Listener();
cache1.addTreeCacheListener(lis);
lis.put("/a/b/c", "age", new Integer(38));
cache1.getTransactionManager().suspend();
assertNull("age on cache2 must be null as the TX has not yet been committed", cache2.get("/a/b/c", "age"));
cache1.getTransactionManager().resume(tx);
tx.commit();
// value on cache2 must be 38
age=(Integer)cache2.get("/a/b/c", "age");
assertNotNull("\"age\" obtained from cache2 must be non-null ", age);
assertTrue("\"age\" must be 38", age.intValue() == 38);
}
catch(Exception e) {
fail(e.toString());
}
}
public void testRemoteCacheListener() throws Exception {
Integer age;
try {
initCaches(TreeCache.REPL_SYNC);
RemoteListener lis = new RemoteListener();
cache2.addTreeCacheListener(lis);
cache1.put("/a/b/c", "age", new Integer(38));
// value on cache2 must be 38
age=(Integer)cache2.get("/a/b/c", "age");
assertNotNull("\"age\" obtained from cache2 must be non-null ", age);
assertTrue("\"age\" must be 38", age.intValue() == 38);
cache1.remove("/a/b/c", "age");
}
catch(Exception e) {
fail(e.toString());
}
}
public void testSyncRepl() throws Exception {
Integer age;
try {
initCaches(TreeCache.REPL_SYNC);
Listener lis = new Listener();
cache1.addTreeCacheListener(lis);
lis.put("/a/b/c", "age", new Integer(38));
// value on cache2 must be 38
age=(Integer)cache2.get("/a/b/c", "age");
assertNotNull("\"age\" obtained from cache2 must be non-null ", age);
assertTrue("\"age\" must be 38", age.intValue() == 38);
}
catch(Exception e) {
fail(e.toString());
}
}
public void testSyncTxReplMap() throws Exception {
Integer age;
Transaction tx;
try {
initCaches(TreeCache.REPL_SYNC);
tx=beginTransaction();
Listener lis = new Listener();
cache1.addTreeCacheListener(lis);
Map map = new HashMap();
map.put("age", new Integer(38));
map.put("name", "Ben");
lis.put("/a/b/c", map);
cache1.getTransactionManager().suspend();
assertNull("age on cache2 must be null as the TX has not yet been committed", cache2.get("/a/b/c", "age"));
cache1.getTransactionManager().resume(tx);
tx.commit();
// value on cache2 must be 38
age=(Integer)cache2.get("/a/b/c", "age");
assertNotNull("\"age\" obtained from cache2 must be non-null ", age);
assertTrue("\"age\" must be 38", age.intValue() == 38);
}
catch(Exception e) {
fail(e.toString());
}
}
public void testSyncReplMap() throws Exception {
Integer age;
try {
initCaches(TreeCache.REPL_SYNC);
Listener lis = new Listener();
cache1.addTreeCacheListener(lis);
Map map = new HashMap();
map.put("age", new Integer(38));
map.put("name", "Ben");
lis.put("/a/b/c", map);
// value on cache2 must be 38
age=(Integer)cache2.get("/a/b/c", "age");
assertNotNull("\"age\" obtained from cache2 must be non-null ", age);
assertTrue("\"age\" must be 38", age.intValue() == 38);
}
catch(Exception e) {
fail(e.toString());
}
}
class Listener extends AbstractTreeCacheListener
{
Object key_ = null;
public void put(String fqn, Object key, Object val) throws Exception
{
key_ = key;
cache1.put(fqn, key, val);
}
public void put(String fqn, Map map) throws Exception
{
if(map.size() == 0) fail("put(): map size can't be 0");
Set set = map.keySet();
key_ = set.iterator().next(); // take anyone
cache1.put(fqn, map);
}
public void nodeCreated(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeRemoved(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeLoaded(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeEvicted(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeModified(Fqn fqn)
{
log_.debug("nodeModified visited with fqn: " +fqn);
try {
// test out if we can get the read lock since there is a write lock going as well.
cache1.get(fqn, key_);
} catch (CacheException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
fail("nodeModified: test failed with exception: " +e);
}
}
public void nodeVisited(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void cacheStarted(TreeCache cache) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void cacheStopped(TreeCache cache) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void viewChange(View new_view) // might be MergeView after merging
{
//To change body of implemented methods use File | Settings | File Templates.
}
}
class RemoteListener extends AbstractTreeCacheListener
{
public void nodeCreated(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeRemoved(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeLoaded(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeEvicted(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void nodeRemove(Fqn fqn, boolean isPre, boolean isLocal)
{
System.out.println("nodeRemove visited with fqn: " +fqn + ", isPre: "+ isPre + ", isLocal "+isLocal);
log_.debug("nodeRemove visited with fqn: " +fqn + ", isPre: "+ isPre + ", isLocal "+isLocal);
assertFalse("node was removed on remote cache so isLocal should be false", isLocal);
}
public void nodeModify(Fqn fqn, boolean isPre, boolean isLocal)
{
System.out.println("nodeModify visited with fqn: " +fqn + ", isPre: "+ isPre + ", isLocal "+isLocal);
log_.debug("nodeModify visited with fqn: " +fqn + ", isPre: "+ isPre + ", isLocal "+isLocal);
assertFalse("node was modified on remote cache so isLocal should be false", isLocal);
}
public void nodeVisited(Fqn fqn) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void cacheStarted(TreeCache cache) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void cacheStopped(TreeCache cache) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void viewChange(View new_view) // might be MergeView after merging
{
//To change body of implemented methods use File | Settings | File Templates.
}
}
public static Test suite() throws Exception {
// return getDeploySetup(SyncTxUnitTestCase.class, "cachetest.jar");
return new TestSuite(SyncCacheListenerTest.class);
}
}