/*
* JBoss, Home of Professional Open Source
* Copyright 2009 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.api.tree;
import org.infinispan.Cache;
import org.infinispan.atomic.AtomicMap;
import org.infinispan.atomic.AtomicMapLookup;
import org.infinispan.config.Configuration;
import org.infinispan.config.ConfigurationException;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.test.CacheManagerCallable;
import org.infinispan.test.SingleCacheManagerTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.tree.Fqn;
import org.infinispan.tree.Node;
import org.infinispan.tree.NodeKey;
import org.infinispan.tree.TreeCache;
import org.infinispan.tree.TreeCacheFactory;
import org.infinispan.tree.TreeCacheImpl;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import org.testng.annotations.Test;
import javax.transaction.TransactionManager;
import java.util.HashMap;
import java.util.Map;
import static org.infinispan.test.TestingUtil.withCacheManager;
import static org.testng.AssertJUnit.*;
/**
* Tests the {@link TreeCache} public API at a high level
*
* @author <a href="mailto:manik AT jboss DOT org">Manik Surtani</a>
*/
@Test(groups = "functional", testName = "api.tree.TreeCacheAPITest")
public class TreeCacheAPITest extends SingleCacheManagerTest {
private TreeCache<String, String> cache;
private TransactionManager tm;
private Log log = LogFactory.getLog(TreeCacheAPITest.class);
@Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
// start a single cache instance
Configuration c = new Configuration();
c.setInvocationBatchingEnabled(true);
EmbeddedCacheManager cm = TestCacheManagerFactory.createCacheManager(c);
Cache flatcache = cm.getCache();
cache = new TreeCacheImpl(flatcache);
tm = TestingUtil.getTransactionManager(flatcache);
return cm;
}
public void testGetData() {
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key1","TRADE1");
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key2","TRADE2");
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key3","TRADE3");
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key4","TRADE4");
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key5","TRADE5");
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key6","TRADE6");
cache.put(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key7","TRADE7");
Object object = cache.get(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")),"key7");
assertNotNull(object);
Map<String, String> data = cache.getData(Fqn.fromRelativeFqn(Fqn.fromString("STATUS"), Fqn.fromString("TRADE")));
assertNotNull(data);
}
public void testConvenienceMethods() {
Fqn 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 fqn = Fqn.fromString("/test/fqn");
cache.getRoot().addChild(fqn);
assertTrue(cache.getRoot().hasChild(fqn));
assertEquals(true, cache.removeNode(fqn));
assertFalse(cache.getRoot().hasChild(fqn));
// remove should REALLY remove though and not just mark as deleted/invalid.
Node n = cache.getNode(fqn);
assert n == null;
assertEquals(false, cache.removeNode(fqn));
// remove should REALLY remove though and not just mark as deleted/invalid.
n = cache.getNode(fqn);
assert n == null;
// Check that it's removed if it has a child
Fqn child = Fqn.fromString("/test/fqn/child");
log.error("TEST: Adding child " + child);
cache.getRoot().addChild(child);
assertStructure(cache, "/test/fqn/child");
assertEquals(true, cache.removeNode(fqn));
assertFalse(cache.getRoot().hasChild(fqn));
assertEquals(false, cache.removeNode(fqn));
}
private void assertStructure(TreeCache tc, String fqnStr) {
// make sure structure nodes are properly built and maintained
Cache c = tc.getCache();
Fqn fqn = Fqn.fromString(fqnStr);
// loop thru the Fqn, starting at its root, and make sure all of its children exist in proper NodeKeys
for (int i = 0; i < fqn.size(); i++) {
Fqn parent = fqn.getSubFqn(0, i);
Object childName = fqn.get(i);
// make sure a data key exists in the cache
assert c.containsKey(new NodeKey(parent, NodeKey.Type.DATA)) : "Node [" + parent + "] does not have a Data atomic map!";
assert c.containsKey(new NodeKey(parent, NodeKey.Type.STRUCTURE)) : "Node [" + parent + "] does not have a Structure atomic map!";
AtomicMap<Object, Fqn> am = AtomicMapLookup.getAtomicMap(c, new NodeKey(parent, NodeKey.Type.STRUCTURE));
boolean hasChild = am.containsKey(childName);
assert hasChild : "Node [" + parent + "] does not have a child [" + childName + "] in its Structure atomic map!";
}
}
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() {
assert cache.getNode(Fqn.fromString("/a/b/c")) == null;
assert !cache.removeNode("/a/b/c");
assert cache.getNode(Fqn.fromString("/a/b/c")) == null;
assert cache.getNode(Fqn.fromString("/a/b")) == null;
assert cache.getNode(Fqn.fromString("/a")) == null;
}
public void testPhantomStructuralNodesOnRemoveTransactional() throws Exception {
assert cache.getNode(Fqn.fromString("/a/b/c")) == null;
tm.begin();
assert !cache.removeNode("/a/b/c");
tm.commit();
assert cache.getNode(Fqn.fromString("/a/b/c")) == null;
assert cache.getNode(Fqn.fromString("/a/b")) == null;
assert cache.getNode(Fqn.fromString("/a")) == null;
}
public void testRpcManagerElements() {
assertEquals("CacheMode.LOCAL cache has no address", null, manager(cache.getCache()).getAddress());
assertEquals("CacheMode.LOCAL cache has no members list", null, manager(cache.getCache()).getMembers());
}
public void testTreeCacheFactory() throws Exception {
withCacheManager(new CacheManagerCallable(new DefaultCacheManager(new ConfigurationBuilder().invocationBatching().enable().build())) {
@Override
public void call() throws Exception {
TreeCacheFactory tcf = new TreeCacheFactory();
tcf.createTreeCache(cm.getCache());
}
});
}
@Test(expectedExceptions=ConfigurationException.class)
public void testFactoryNoBatching() throws Exception {
withCacheManager(new CacheManagerCallable(new DefaultCacheManager(new ConfigurationBuilder().build())) {
@Override
public void call() throws Exception {
TreeCacheFactory tcf = new TreeCacheFactory();
tcf.createTreeCache(cm.getCache());
}
});
}
}