/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.invalidation;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;
import org.jboss.cache.misc.TestingUtil;
import org.jboss.cache.xml.XmlHelper;
import org.w3c.dom.Element;
import javax.transaction.RollbackException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.io.File;
/**
* Tests the async interceptor
*
* @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
*/
public class InvalidationInterceptorTest extends TestCase
{
private static Log log = LogFactory.getLog(InvalidationInterceptorTest.class);
public void testPessimisticNonTransactional() throws Exception
{
TreeCache cache1 = createCache(false);
TreeCache cache2 = createCache(false);
Fqn fqn = Fqn.fromString("/a/b");
cache1.put(fqn, "key", "value");
// test that this has NOT replicated, but rather has been invalidated:
Assert.assertEquals("value", cache1.get(fqn, "key"));
Assert.assertNull("Should NOT have replicated!", cache2.get(fqn));
log.info("***** Node not replicated, as expected.");
// now make sure cache2 is in sync with cache1:
cache2.put(fqn, "key", "value");
Assert.assertNull("Should be null", cache1.get(fqn));
Assert.assertEquals("value", cache2.get(fqn, "key"));
// now test the invalidation:
cache1.put(fqn, "key2", "value2");
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertNull("Should have been invalidated!", cache2.get(fqn));
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testUnnecessaryEvictions() throws Exception
{
TreeCache cache1 = createCache(false);
TreeCache cache2 = createCache(false);
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
cache1.put(fqn1, "hello", "world");
assertEquals("world", cache1.get(fqn1, "hello"));
assertNull(cache2.get(fqn1, "hello"));
cache2.put(fqn2, "hello", "world");
assertEquals("world", cache1.get(fqn1, "hello"));
assertNull(cache2.get(fqn1, "hello"));
assertEquals("world", cache2.get(fqn2, "hello"));
assertNull(cache1.get(fqn2, "hello"));
cache2.put(fqn1, "hello", "world");
assertEquals("world", cache2.get(fqn1, "hello"));
assertEquals("world", cache2.get(fqn2, "hello"));
assertNull(cache1.get(fqn1, "hello"));
assertNull(cache1.get(fqn2, "hello"));
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testPessimisticNonTransactionalAsync() throws Exception
{
TreeCache cache1 = createUnstartedCache( false );
TreeCache cache2 = createUnstartedCache( false );
cache1.setCacheMode(TreeCache.INVALIDATION_ASYNC);
cache2.setCacheMode(TreeCache.INVALIDATION_ASYNC);
cache1.startService();
cache2.startService();
Fqn fqn = Fqn.fromString("/a/b");
cache1.put(fqn, "key", "value");
TestingUtil.sleepThread(500); // give it time to broadcast the evict call
// test that this has NOT replicated, but rather has been invalidated:
Assert.assertEquals("value", cache1.get(fqn, "key"));
Assert.assertNull("Should NOT have replicated!", cache2.get(fqn));
log.info("***** Node not replicated, as expected.");
// now make sure cache2 is in sync with cache1:
cache2.put(fqn, "key", "value");
TestingUtil.sleepThread(500); // give it time to broadcast the evict call
Assert.assertNull("Should be null", cache1.get(fqn));
Assert.assertEquals("value", cache2.get(fqn, "key"));
// now test the invalidation:
cache1.put(fqn, "key2", "value2");
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
TestingUtil.sleepThread(500); // give it time to broadcast the evict call
Assert.assertNull("Should have been invalidated!", cache2.get(fqn));
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testPessimisticTransactional() throws Exception
{
TreeCache cache1 = createCache(false);
TreeCache cache2 = createCache(false);
Fqn fqn = Fqn.fromString("/a/b");
cache1.put(fqn, "key", "value");
// test that this has NOT replicated, but rather has been invalidated:
Assert.assertEquals("value", cache1.get(fqn, "key"));
Assert.assertNull("Should NOT have replicated!", cache2.get(fqn));
log.info("***** Node not replicated, as expected.");
// now make sure cache2 is in sync with cache1:
// make sure this is in a tx
TransactionManager txm = cache2.getTransactionManager();
Assert.assertEquals("value", cache1.get(fqn, "key"));
txm.begin();
cache2.put(fqn, "key", "value");
Assert.assertEquals("value", cache2.get(fqn, "key"));
txm.commit();
Assert.assertNull("Should be null", cache1.get(fqn));
Assert.assertEquals("value", cache2.get(fqn, "key"));
// now test the invalidation again
txm = cache1.getTransactionManager();
Assert.assertEquals("value", cache2.get(fqn, "key"));
txm.begin();
cache1.put(fqn, "key2", "value2");
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
txm.commit();
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertNull("Should have been invalidated!", cache2.get(fqn));
// test a rollback
txm = cache2.getTransactionManager();
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
txm.begin();
cache2.put(fqn, "key", "value");
Assert.assertEquals("value", cache2.get(fqn, "key"));
txm.rollback();
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertNull("Should not have committed", cache2.get(fqn));
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testOptSyncUnableToEvict() throws Exception
{
TreeCache cache1 = createCache(true);
TreeCache cache2 = createCache(true);
Fqn fqn = Fqn.fromString("/a/b");
cache2.put(fqn, "key", "value");
Assert.assertEquals("value", cache2.get(fqn, "key"));
Assert.assertNull(cache1.get(fqn));
// start a tx that cache1 will have to send out an evict ...
TransactionManager mgr1 = cache1.getTransactionManager();
TransactionManager mgr2 = cache2.getTransactionManager();
mgr1.begin();
cache1.put(fqn, "key2", "value2");
Transaction tx1 = mgr1.suspend();
mgr2.begin();
cache2.put(fqn, "key3", "value3");
Transaction tx2 = mgr2.suspend();
mgr1.resume(tx1);
// this oughtta fail
try
{
mgr1.commit();
Assert.assertTrue("Ought to have succeeded!", true);
}
catch (RollbackException roll)
{
Assert.assertTrue("Ought to have succeeded!", false);
}
mgr2.resume(tx2);
try
{
mgr2.commit();
Assert.assertTrue("Ought to have failed!", false);
}
catch (RollbackException roll)
{
Assert.assertTrue("Ought to have failed!", true);
}
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testPessTxSyncUnableToEvict() throws Exception
{
TreeCache cache1 = createCache(false);
TreeCache cache2 = createCache(false);
Fqn fqn = Fqn.fromString("/a/b");
cache1.put("/a/b", "key", "value");
Assert.assertEquals("value", cache1.get(fqn, "key"));
Assert.assertNull(cache2.get(fqn));
// start a tx that cacahe1 will have to send out an evict ...
TransactionManager mgr1 = cache1.getTransactionManager();
TransactionManager mgr2 = cache2.getTransactionManager();
mgr1.begin();
cache1.put(fqn, "key2", "value2");
Transaction tx1 = mgr1.suspend();
mgr2.begin();
cache2.put(fqn, "key3", "value3");
Transaction tx2 = mgr2.suspend();
mgr1.resume(tx1);
// this oughtta fail
try
{
mgr1.commit();
Assert.assertTrue("Ought to have failed!", false);
}
catch (RollbackException roll)
{
Assert.assertTrue("Ought to have failed!", true);
}
mgr2.resume(tx2);
try
{
mgr2.commit();
Assert.assertTrue("Ought to have succeeded!", true);
}
catch (RollbackException roll)
{
Assert.assertTrue("Ought to have succeeded!", false);
}
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testPessTxAsyncUnableToEvict() throws Exception
{
TreeCache cache1 = createUnstartedCache(false);
TreeCache cache2 = createUnstartedCache(false);
cache1.setCacheMode(TreeCache.INVALIDATION_ASYNC);
cache2.setCacheMode(TreeCache.INVALIDATION_ASYNC);
cache1.startService();
cache2.startService();
Fqn fqn = Fqn.fromString("/a/b");
cache1.put("/a/b", "key", "value");
Assert.assertEquals("value", cache1.get(fqn, "key"));
Assert.assertNull(cache2.get(fqn));
// start a tx that cacahe1 will have to send out an evict ...
TransactionManager mgr1 = cache1.getTransactionManager();
TransactionManager mgr2 = cache2.getTransactionManager();
mgr1.begin();
cache1.put(fqn, "key2", "value2");
Transaction tx1 = mgr1.suspend();
mgr2.begin();
cache2.put(fqn, "key3", "value3");
Transaction tx2 = mgr2.suspend();
mgr1.resume(tx1);
// this oughtta fail
try
{
mgr1.commit();
Assert.assertTrue("Ought to have succeeded!", true);
}
catch (RollbackException roll)
{
Assert.assertTrue("Ought to have succeeded!", false);
}
mgr2.resume(tx2);
try
{
mgr2.commit();
Assert.assertTrue("Ought to have succeeded!", true);
}
catch (RollbackException roll)
{
Assert.assertTrue("Ought to have succeeded!", false);
}
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testOptimistic() throws Exception
{
TreeCache cache1 = createCache(true);
TreeCache cache2 = createCache(true);
Fqn fqn = Fqn.fromString("/a/b");
cache1.put(fqn, "key", "value");
// test that this has NOT replicated, but rather has been invalidated:
Assert.assertEquals("value", cache1.get(fqn, "key"));
Assert.assertNull("Should NOT have replicated!", cache2.get(fqn));
log.info("***** Node not replicated, as expected.");
// now make sure cache2 is in sync with cache1:
cache2.put(fqn, "key", "value");
Assert.assertNull("Should be null", cache1.get(fqn));
Assert.assertEquals("value", cache2.get(fqn, "key"));
// now test the invalidation:
cache1.put(fqn, "key2", "value2");
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertNull("Should have been invalidated!", cache2.get(fqn));
// with tx's
TransactionManager txm = cache2.getTransactionManager();
txm.begin();
cache2.put(fqn, "key", "value");
Assert.assertEquals("value", cache2.get(fqn, "key"));
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
txm.commit();
Assert.assertNull("Should be null", cache1.get(fqn));
Assert.assertEquals("value", cache2.get(fqn, "key"));
// now test the invalidation again
txm = cache1.getTransactionManager();
txm.begin();
cache1.put(fqn, "key2", "value2");
Assert.assertEquals("value", cache2.get(fqn, "key"));
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
txm.commit();
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertNull("Should have been invalidated!", cache2.get(fqn));
// test a rollback
txm = cache2.getTransactionManager();
txm.begin();
cache2.put(fqn, "key", "value");
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertEquals("value", cache2.get(fqn, "key"));
txm.rollback();
Assert.assertEquals("value2", cache1.get(fqn, "key2"));
Assert.assertNull("Should not have committed", cache2.get(fqn));
// clean up.
cache1.stopService();
cache2.stopService();
cache1 = null;
cache2 = null;
}
public void testPessimisticNonTransactionalWithCacheLoader() throws Exception
{
TreeCache[] caches = createCachesWithSharedCL(false);
Fqn fqn = Fqn.fromString("/a/b");
caches[0].put(fqn, "key", "value");
Assert.assertEquals("value", caches[0].get(fqn, "key"));
Assert.assertEquals("value", caches[1].get(fqn, "key"));
// now make sure cache2 is in sync with cache1:
caches[1].put(fqn, "key", "value");
Assert.assertEquals("value", caches[1].get(fqn, "key"));
Assert.assertEquals("value", caches[0].get(fqn, "key"));
// now test the invalidation:
caches[0].put(fqn, "key2", "value2");
Assert.assertEquals("value2", caches[0].get(fqn, "key2"));
Assert.assertEquals("value2", caches[1].get(fqn, "key2"));
Assert.assertEquals("value", caches[0].get(fqn, "key"));
Assert.assertEquals("value", caches[1].get(fqn, "key"));
// clean up.
caches[0].remove( fqn );
caches[1].remove( fqn );
caches[0].stopService();
caches[1].stopService();
caches[0] = null;
caches[1] = null;
}
public void testPessimisticTransactionalWithCacheLoader() throws Exception
{
TreeCache[] caches = createCachesWithSharedCL(false);
Fqn fqn = Fqn.fromString("/a/b");
TransactionManager mgr = caches[0].getTransactionManager();
Assert.assertNull("Should be null", caches[0].get(fqn, "key"));
Assert.assertNull("Should be null", caches[1].get(fqn, "key"));
mgr.begin();
caches[0].put(fqn, "key", "value");
Assert.assertEquals("value", caches[0].get(fqn, "key"));
mgr.commit();
Assert.assertEquals("value", caches[1].get(fqn, "key"));
Assert.assertEquals("value", caches[0].get(fqn, "key"));
mgr.begin();
caches[0].put(fqn, "key2", "value2");
Assert.assertEquals("value2", caches[0].get(fqn, "key2"));
mgr.rollback();
Assert.assertEquals("value", caches[1].get(fqn, "key"));
Assert.assertEquals("value", caches[0].get(fqn, "key"));
Assert.assertNull("Should be null", caches[0].get(fqn, "key2"));
Assert.assertNull("Should be null", caches[1].get(fqn, "key2"));
// clean up.
caches[0].remove(fqn);
caches[1].remove(fqn);
caches[0].stopService();
caches[1].stopService();
caches[0] = null;
caches[1] = null;
}
public void testOptimisticWithCacheLoader() throws Exception
{
TreeCache[] caches = createCachesWithSharedCL(true);
Fqn fqn = Fqn.fromString("/a/b");
TransactionManager mgr = caches[0].getTransactionManager();
Assert.assertNull("Should be null", caches[0].get(fqn, "key"));
Assert.assertNull("Should be null", caches[1].get(fqn, "key"));
mgr.begin();
caches[0].put(fqn, "key", "value");
Assert.assertEquals("value", caches[0].get(fqn, "key"));
Assert.assertNull("Should be null", caches[1].get(fqn, "key"));
mgr.commit();
Assert.assertEquals("value", caches[1].get(fqn, "key"));
Assert.assertEquals("value", caches[0].get(fqn, "key"));
mgr.begin();
caches[0].put(fqn, "key2", "value2");
Assert.assertEquals("value2", caches[0].get(fqn, "key2"));
Assert.assertNull("Should be null", caches[1].get(fqn, "key2"));
mgr.rollback();
Assert.assertEquals("value", caches[1].get(fqn, "key"));
Assert.assertEquals("value", caches[0].get(fqn, "key"));
Assert.assertNull("Should be null", caches[0].get(fqn, "key2"));
Assert.assertNull("Should be null", caches[1].get(fqn, "key2"));
// clean up.
caches[0].remove(fqn);
caches[1].remove(fqn);
caches[0].stopService();
caches[1].stopService();
caches[0] = null;
caches[1] = null;
}
public void testInvalidationWithRegionBasedMarshalling() throws Exception
{
doRegionBasedTest(false);
}
public void testInvalidationWithRegionBasedMarshallingOptimistic() throws Exception
{
doRegionBasedTest(true);
}
protected void doRegionBasedTest(boolean optimistic) throws Exception
{
TreeCache[] caches = new TreeCache[2];
caches[0] = createUnstartedCache(false);
caches[1] = createUnstartedCache(false);
caches[0].setUseRegionBasedMarshalling(true);
caches[1].setUseRegionBasedMarshalling(true);
if (optimistic)
{
caches[0].setNodeLockingScheme("OPTIMISTIC");
caches[1].setNodeLockingScheme("OPTIMISTIC");
}
caches[0].startService();
caches[1].startService();
TestingUtil.blockUntilViewsReceived(caches, 5000);
Fqn fqn = Fqn.fromString("/a/b");
assertNull("Should be null", caches[0].get(fqn));
assertNull("Should be null", caches[1].get(fqn));
caches[0].put(fqn, "key", "value");
assertEquals("expecting value", "value", caches[0].get(fqn, "key"));
assertNull("Should be null", caches[1].get(fqn));
// now put in caches[1], should fire an eviction
caches[1].put(fqn, "key", "value2");
assertEquals("expecting value2", "value2", caches[1].get(fqn, "key"));
assertNull("Should be null", caches[0].get(fqn));
// clean up.
caches[0].remove(fqn);
caches[1].remove(fqn);
caches[0].stopService();
caches[1].stopService();
caches[0] = null;
caches[1] = null;
}
protected TreeCache createUnstartedCache(boolean optimistic) throws Exception
{
TreeCache cache = new TreeCache("MyCluster", null, 3000);
cache.setCacheMode(TreeCache.INVALIDATION_SYNC);
if (optimistic) cache.setNodeLockingScheme("OPTIMISTIC");
cache.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
return cache;
}
protected TreeCache createCache(boolean optimistic) throws Exception
{
TreeCache cache = createUnstartedCache(optimistic);
cache.startService();
return cache;
}
protected TreeCache[] createCachesWithSharedCL(boolean optimistic) throws Exception
{
TreeCache[] caches = new TreeCache[2];
caches[0] = createUnstartedCache(optimistic);
caches[1] = createUnstartedCache(optimistic);
caches[0].setCacheLoaderConfiguration(getCacheLoaderConfig());
caches[1].setCacheLoaderConfiguration(getCacheLoaderConfig());
caches[0].startService();
caches[1].startService();
return caches;
}
protected Element getCacheLoaderConfig() throws Exception
{
String xml = " <config>\n" +
" \n" +
" <passivation>false</passivation>\n" +
" <preload></preload>\n" +
"\n" +
" <cacheloader>\n" +
" <class>org.jboss.cache.loader.FileCacheLoader</class>\n" +
" <properties>\n" +
" location=" + getTempDir() + "\n" +
" </properties>\n" +
" <async>false</async>\n" +
" <fetchPersistentState>false</fetchPersistentState>\n" +
" <ignoreModifications>false</ignoreModifications>\n" +
" </cacheloader>\n" +
" \n" +
" </config>";
return XmlHelper.stringToElement(xml);
}
protected String getTempDir()
{
String name = "cacheloader";
String tempDir = System.getProperty("java.io.tmpdir", "/tmp") + File.separator + "JBossCache-InvalidationInterceptorTestCase-WorkingDir" + File.separator + name;
File tempDirFile = new File(tempDir);
if (!tempDirFile.exists())
{
tempDirFile.mkdirs();
}
return tempDir;
}
public static void main(String[] args)
{
TestRunner.run(suite());
}
public static Test suite()
{
return new TestSuite(InvalidationInterceptorTest.class);
}
}