package org.jboss.cache.api;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheFactory;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.Region;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.ConfigurationException;
import org.jboss.cache.notifications.annotation.CacheListener;
import org.jboss.cache.notifications.annotation.NodeCreated;
import org.jboss.cache.notifications.event.Event;
import org.jboss.cache.transaction.GenericTransactionManagerLookup;
import org.jboss.cache.util.CachePrinter;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import javax.transaction.TransactionManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Tests the {@link org.jboss.cache.Cache} public API at a high level
*
* @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
*/
@Test(groups = "functional")
public class CacheAPITest
{
private Cache<String, String> cache;
protected boolean optimistic;
final List<String> events = new ArrayList<String>();
@BeforeMethod(alwaysRun = true)
public void setUp() throws Exception
{
// start a single cache instance
CacheFactory<String, String> cf = new DefaultCacheFactory();
cache = cf.createCache("META-INF/conf-test/local-tx-service.xml", false);
cache.getConfiguration().setNodeLockingScheme(optimistic ? Configuration.NodeLockingScheme.OPTIMISTIC : Configuration.NodeLockingScheme.PESSIMISTIC);
cache.start();
events.clear();
}
@AfterMethod(alwaysRun = true)
public void tearDown()
{
if (cache != null) cache.stop();
}
/**
* Tests that the configuration contains the values expected, as well as immutability of certain elements
*/
public void testConfiguration()
{
Configuration c = cache.getConfiguration();
assertEquals(Configuration.CacheMode.LOCAL, c.getCacheMode());
assertEquals(GenericTransactionManagerLookup.class.getName(), c.getTransactionManagerLookupClass());
// note that certain values should be immutable. E.g., CacheMode cannot be changed on the fly.
try
{
c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
assert false : "Should have thrown an Exception";
}
catch (ConfigurationException e)
{
// expected
}
// others should be changeable though.
c.setLockAcquisitionTimeout(100);
}
public void testGetMembersInLocalMode()
{
assert cache.getMembers() == null : "Cache members should be null if running in LOCAL mode";
}
/**
* Basic usage of cache listeners
* <p/>
* A more complete test that tests notifications is in org.jboss.cache.notifications
*/
public void testCacheListeners()
{
assertEquals(0, cache.getCacheListeners().size());
Object dummy = new Listener();
cache.addCacheListener(dummy);
assertEquals(1, cache.getCacheListeners().size());
cache.getRoot().addChild(Fqn.fromString("/blah"));
// test that the event was captured by the listener.
// FOR A FULL TEST ON NOTIFICATIONS SEE TESTS IN org.jboss.cache.notifications
assertEquals(1, events.size());
cache.removeCacheListener(dummy);
assertEquals(0, cache.getCacheListeners().size());
}
/**
* Test that fqn-specific application of cache listeners has not been implemented and will not be implemented
* in 2.0.0. It is a feature for 2.1.0 but the interface needed to be in place now.
*/
public void testFqnBasedCacheListeners()
{
try
{
cache.getCacheListeners(Fqn.ROOT);
fail("Fqn-based cache listener operation should throw an exception");
}
catch (Exception e)
{
// expected
}
try
{
cache.addCacheListener(Fqn.ROOT, new Listener());
fail("Fqn-based cache listener operation should throw an exception");
}
catch (Exception e)
{
// expected
}
try
{
cache.removeCacheListener(Fqn.ROOT, new Listener());
fail("Fqn-based cache listener operation should throw an exception");
}
catch (Exception e)
{
// expected
}
}
/**
* All cache operations should happen on a {@link Node} - I.e., you look up a {@link Node} and perform data operations
* on this {@link Node}. For convenience and familiarity with JBoss Cache 1.x, we provide some helpers in {@link Cache}
* which dives you direct data access to nodes.
* <p/>
* This test exercises these.
*/
public void testConvenienceMethods()
{
Fqn<String> fqn = Fqn.fromString("/test/fqn");
String key = "key", value = "value";
Map<String, String> data = new HashMap<String, String>();
data.put(key, value);
assertNull(cache.get(fqn, key));
cache.put(fqn, key, value);
assertEquals(value, cache.get(fqn, key));
cache.remove(fqn, key);
assertNull(cache.get(fqn, key));
cache.put(fqn, data);
assertEquals(value, cache.get(fqn, key));
}
/**
* Another convenience method that tests node removal
*/
public void testNodeConvenienceNodeRemoval()
{
// this fqn is relative, but since it is from the root it may as well be absolute
Fqn<String> fqn = Fqn.fromString("/test/fqn");
cache.getRoot().addChild(fqn);
assertTrue(cache.getRoot().hasChild(fqn));
assertEquals(true, cache.removeNode(fqn));
assertFalse(cache.getRoot().hasChild(fqn));
assertEquals(false, cache.removeNode(fqn));
System.out.println("Cache: " + CachePrinter.printCacheDetails(cache));
// Check that it's removed if it has a child
Fqn<String> child = Fqn.fromString("/test/fqn/child");
cache.getRoot().addChild(child);
assertTrue(cache.getRoot().hasChild(child));
assertEquals(true, cache.removeNode(fqn));
assertFalse(cache.getRoot().hasChild(fqn));
assertEquals(false, cache.removeNode(fqn));
}
/**
* Tests basic eviction
*/
public void testEvict()
{
Fqn<String> one = Fqn.fromString("/one");
Fqn<String> two = Fqn.fromString("/one/two");
String key = "key", value = "value";
cache.getRoot().addChild(one).put(key, value);
cache.getRoot().addChild(two).put(key, value);
assertTrue(cache.getRoot().hasChild(one));
assertFalse(cache.getRoot().getChild(one).getData().isEmpty());
assertTrue(cache.getRoot().hasChild(two));
assertFalse(cache.getRoot().getChild(two).getData().isEmpty());
// evict two
cache.evict(two, false);
assertTrue(cache.getRoot().hasChild(one));
assertTrue(cache.getRoot().getChild(one).getKeys().contains(key));
assertFalse(cache.getRoot().hasChild(two));
// now add 2 again...
cache.getRoot().addChild(two).put(key, value);
// now evict one, NOT recursive
cache.evict(one, false);
// one will NOT be removed, just emptied.
assertTrue(cache.getRoot().hasChild(one));
assertFalse(cache.getRoot().getChild(one).getKeys().contains(key));
// two will be unaffected
assertTrue(cache.getRoot().hasChild(two));
assertTrue(cache.getRoot().getChild(two).getKeys().contains(key));
}
/**
* Tests recursive eviction
*/
public void testEvictRecursive()
{
Fqn<String> one = Fqn.fromString("/one");
Fqn<String> two = Fqn.fromString("/one/two");
String key = "key", value = "value";
cache.getRoot().addChild(one).put(key, value);
cache.getRoot().addChild(two).put(key, value);
assertTrue(cache.getRoot().hasChild(one));
assertFalse(cache.getRoot().getChild(one).getData().isEmpty());
assertTrue(cache.getRoot().hasChild(two));
assertFalse(cache.getRoot().getChild(two).getData().isEmpty());
// evict two
cache.evict(two, true);
assertTrue(cache.getRoot().hasChild(one));
assertFalse(cache.getRoot().getChild(one).getData().isEmpty());
assertFalse(cache.getRoot().hasChild(two));
// now add 2 again...
cache.getRoot().addChild(two).put(key, value);
// now evict one, recursive
cache.evict(one, true);
assertFalse(cache.getRoot().hasChild(one));
assertFalse(cache.getRoot().hasChild(two));
}
/**
* Again, see org.jboss.cache for more extensive tests on Regions. This just tests the getRegion API on cache.
*/
public void testRegion()
{
Region rootRegion = cache.getRegion(Fqn.ROOT, true);
assertNotNull(rootRegion);// guaranteed never to return null if createIfAbsent is true.
assertSame(rootRegion, cache.getRegion(Fqn.ROOT, true));
Region otherRegion = cache.getRegion(Fqn.fromString("/other/region"), true);
assertNotNull(otherRegion);
assertSame(otherRegion, cache.getRegion(Fqn.fromString("/other/region"), true));
}
/**
* Again, see org.jboss.cache for more extensive tests on Regions. This just tests the getRegion API on cache.
*/
public void testParentRegion1()
{
Region rootRegion = cache.getRegion(Fqn.ROOT, true);
assertNotNull(rootRegion);// guaranteed never to return null if createIfAbsent is true.
assertSame(rootRegion, cache.getRegion(Fqn.ROOT, false));
Region otherRegion = cache.getRegion(Fqn.fromString("/other/region"), false);
// should return the same parent region as root.
assertSame(otherRegion, rootRegion);
}
/**
* Again, see org.jboss.cache for more extensive tests on Regions. This just tests the getRegion API on cache.
*/
public void testParentRegion2()
{
Region rootRegion = cache.getRegion(Fqn.ROOT, true);
Region parentRegion = cache.getRegion(Fqn.fromString("/parent"), true);
assertNotSame("parentRegion should be a new region in its own right", rootRegion, parentRegion);
Region childRegion = cache.getRegion(Fqn.fromString("/parent/region"), false);
assertSame("Expecting the same region as parentRegion", childRegion, parentRegion);
}
/**
* Again, see org.jboss.cache for more extensive tests on Regions. This just tests the getRegion API on cache.
*/
public void testNullRegion()
{
Region myRegion = cache.getRegion(Fqn.fromString("/myregion"), true);
assertNotNull(myRegion);// guaranteed never to return null if createIfAbsent is true.
assertSame(myRegion, cache.getRegion(Fqn.fromString("/myregion"), false));
Region otherRegion = cache.getRegion(Fqn.fromString("/other/region"), false);
// should return the default region
assertNotNull(otherRegion);
assertEquals(Fqn.ROOT, otherRegion.getFqn());
}
public void testStopClearsData() throws Exception
{
Fqn a = Fqn.fromString("/a");
Fqn b = Fqn.fromString("/a/b");
String key = "key", value = "value";
cache.getRoot().addChild(a).put(key, value);
cache.getRoot().addChild(b).put(key, value);
cache.getRoot().put(key, value);
assertEquals(value, cache.getRoot().get(key));
assertEquals(value, cache.getRoot().getChild(a).get(key));
assertEquals(value, cache.getRoot().getChild(b).get(key));
cache.stop();
cache.start();
assertNull(cache.getRoot().get(key));
assertTrue(cache.getRoot().getData().isEmpty());
assertTrue(cache.getRoot().getChildren().isEmpty());
}
public void testPhantomStructuralNodesOnRemove()
{
CacheSPI spi = (CacheSPI) cache;
assert spi.peek(Fqn.fromString("/a/b/c"), true, true) == null;
assert !spi.removeNode("/a/b/c");
assert spi.peek(Fqn.fromString("/a/b/c"), true, true) == null;
assert spi.peek(Fqn.fromString("/a/b"), true, true) == null;
assert spi.peek(Fqn.fromString("/a"), true, true) == null;
}
public void testPhantomStructuralNodesOnRemoveTransactional() throws Exception
{
CacheSPI spi = (CacheSPI) cache;
TransactionManager tm = spi.getTransactionManager();
assert spi.peek(Fqn.fromString("/a/b/c"), true, true) == null;
tm.begin();
assert !spi.removeNode("/a/b/c");
tm.commit();
assert spi.peek(Fqn.fromString("/a/b/c"), true, true) == null;
assert spi.peek(Fqn.fromString("/a/b"), true, true) == null;
assert spi.peek(Fqn.fromString("/a"), true, true) == null;
}
public void testRpcManagerElements()
{
assertEquals("CacheMode.LOCAL cache has no address", null, cache.getLocalAddress());
assertEquals("CacheMode.LOCAL cache has no members list", null, cache.getMembers());
}
@CacheListener
public class Listener
{
@NodeCreated
public void nodeCreated(Event e)
{
if (e.isPre()) events.add("Created");
}
}
}