[jbosscache-commits] JBoss Cache SVN: r7227 - in core/branches/flat/src: test/java/org/jboss/starobrno/api and 4 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Thu Nov 27 22:39:39 EST 2008


Author: manik.surtani at jboss.com
Date: 2008-11-27 22:39:39 -0500 (Thu, 27 Nov 2008)
New Revision: 7227

Added:
   core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeMoveAPITest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeReplicatedMoveTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTxTest.java
Modified:
   core/branches/flat/src/main/java/org/jboss/starobrno/tree/NodeImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCache.java
   core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCacheImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeStructureSupport.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeAPITest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/TreeCacheAPITest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/util/TestingUtil.java
Log:
Tree related stuff, move impl, etc

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/tree/NodeImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/tree/NodeImpl.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/tree/NodeImpl.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -393,4 +393,12 @@
    {
       return (fqn != null ? fqn.hashCode() : 0);
    }
+
+   @Override
+   public String toString()
+   {
+      return "NodeImpl{" +
+            "fqn=" + fqn +
+            '}';
+   }
 }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCache.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCache.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCache.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -500,7 +500,7 @@
 
    Configuration getConfiguration();
 
-   Cache getCache();
+   Cache<K, V> getCache();
 
    boolean exists(String fqn);
 

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCacheImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCacheImpl.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeCacheImpl.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -192,7 +192,45 @@
 
    public void move(Fqn nodeToMove, Fqn newParent) throws NodeNotExistsException
    {
-      //TODO: Autogenerated.  Implement me properly
+      if (nodeToMove == null || newParent == null) throw new NullPointerException("Cannot accept null parameters!");
+
+      if (nodeToMove.getParent().equals(newParent))
+      {
+         // moving onto self!  Do nothing!
+         return;
+      }
+
+      // Depth first.  Lets start with getting the node we want.
+      startAtomic();
+      try
+      {
+         Node node = getNode(nodeToMove);
+         if (node == null) return; // nothing to do here!
+         if (!exists(newParent))
+         {
+            // then we need to silently create the new parent
+            createNodeInCache(newParent);
+         }
+
+         // create an empty node for this new parent
+         Fqn newFqn = Fqn.fromRelativeElements(newParent, nodeToMove.getLastElement());
+         createNodeInCache(newFqn);
+         Node newNode = getNode(newFqn);
+         Map oldData = node.getData();
+         if (oldData != null && !oldData.isEmpty()) newNode.putAll(oldData);
+         for (Object child : node.getChildrenNames())
+         {
+            // move kids
+            Fqn oldChildFqn = Fqn.fromRelativeElements(nodeToMove, child);
+            move(oldChildFqn, newFqn);
+         }
+
+         removeNode(nodeToMove);
+      }
+      finally
+      {
+         endAtomic();
+      }
    }
 
    public void move(String nodeToMove, String newParent) throws NodeNotExistsException

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeStructureSupport.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeStructureSupport.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/tree/TreeStructureSupport.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -94,4 +94,36 @@
       return lockManager.isLocked(new NodeKey(fqn, NodeKey.Type.STRUCTURE)) &&
             lockManager.isLocked(new NodeKey(fqn, NodeKey.Type.DATA));
    }
+
+   /**
+    * Visual representation of a tree
+    * @param cache cache to dump
+    * @return String rep
+    */
+   public static String printTree(TreeCache<?, ?> cache, boolean details)
+   {
+      StringBuilder sb = new StringBuilder();
+//      sb.append("Raw keys: " + cache.getCache().keySet());
+      sb.append("\n\n");
+
+      // walk tree
+      sb.append("+ ").append(Fqn.SEPARATOR);
+      if (details) sb.append("  ").append(cache.getRoot().getData()); 
+      sb.append("\n");
+      addChildren(cache.getRoot(), 1, sb, details);
+      return sb.toString();
+   }
+
+   private static void addChildren(Node<?, ?> node, int depth, StringBuilder sb, boolean details)
+   {
+      for (Node<?, ?> child: node.getChildren())
+      {
+         for (int i=0; i<depth; i++) sb.append("  "); // indentations
+         sb.append("+ ");
+         sb.append(child.getFqn().getLastElementAsString()).append(Fqn.SEPARATOR);
+         if (details) sb.append("  ").append(child.getData());
+         sb.append("\n");
+         addChildren(child, depth + 1, sb, details);
+      }      
+   }
 }

Modified: core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -1,8 +1,11 @@
 package org.jboss.starobrno.api;
 
 import org.jboss.cache.CacheFactory;
-import org.jboss.cache.transaction.GenericTransactionManagerLookup;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.transaction.DummyTransactionManager;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
 import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.UnitTestCacheFactory;
 import org.jboss.starobrno.config.Configuration;
 import org.jboss.starobrno.config.ConfigurationException;
 import org.jboss.starobrno.util.TestingUtil;
@@ -14,7 +17,6 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import org.jboss.starobrno.UnitTestCacheFactory;
 
 /**
  * Tests the {@link org.jboss.cache.Cache} public API at a high level
@@ -23,7 +25,7 @@
  */
 
 @Test(groups = {"functional", "pessimistic"})
-public class CacheAPITest
+public abstract class CacheAPITest
 {
    private ThreadLocal<CacheSPI<String, String>> cacheTL = new ThreadLocal<CacheSPI<String, String>>();
 
@@ -31,19 +33,16 @@
    public void setUp() throws Exception
    {
       // start a single cache instance
+      Configuration c = new Configuration();
+      c.setIsolationLevel(getIsolationLevel());
+      c.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
       CacheFactory<String, String> cf = new UnitTestCacheFactory<String, String>();
-      CacheSPI<String, String> cache = (CacheSPI<String, String>) cf.createCache("configs/local-tx.xml", false);
-      cache.getConfiguration().setEvictionConfig(null);
-      configure(cache.getConfiguration());
-      cache.start();
+      CacheSPI<String, String> cache = (CacheSPI<String, String>) cf.createCache(c.clone());
       cacheTL.set(cache);
    }
 
-   protected void configure(Configuration c)
-   {
-   }
+   protected abstract IsolationLevel getIsolationLevel();
 
-
    @AfterMethod(alwaysRun = true)
    public void tearDown()
    {
@@ -60,7 +59,7 @@
       CacheSPI<String, String> cache = cacheTL.get();
       Configuration c = cache.getConfiguration();
       assertEquals(Configuration.CacheMode.LOCAL, c.getCacheMode());
-      assertEquals(GenericTransactionManagerLookup.class.getName(), c.getTransactionManagerLookupClass());
+      assertEquals(DummyTransactionManagerLookup.class.getName(), c.getTransactionManagerLookupClass());
 
       // note that certain values should be immutable.  E.g., CacheMode cannot be changed on the fly.
       try
@@ -80,7 +79,7 @@
    public void testGetMembersInLocalMode()
    {
       CacheSPI<String, String> cache = cacheTL.get();
-      assert cache.getRPCManager() == null : "Cache members should be null if running in LOCAL mode";
+      assert cache.getRPCManager().getLocalAddress() == null : "Cache members should be null if running in LOCAL mode";
    }
 
    /**
@@ -155,4 +154,73 @@
       assert !cache.containsKey(key);
       assert cache.isEmpty();
    }
+
+   public void testRollbackAfterPut() throws Exception
+   {
+      CacheSPI<String, String> cache = cacheTL.get();
+      String key = "key", value = "value";
+      cache.put(key, value);
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+
+      DummyTransactionManager.getInstance().begin();
+      cache.put("key2", "value2");
+      assert cache.get("key2").equals("value2");
+      DummyTransactionManager.getInstance().rollback();
+
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+   }
+
+   public void testRollbackAfterOverwrite() throws Exception
+   {
+      CacheSPI<String, String> cache = cacheTL.get();
+      String key = "key", value = "value";
+      cache.put(key, value);
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+
+      DummyTransactionManager.getInstance().begin();
+      cache.put(key, "value2");
+      assert cache.get(key).equals("value2");
+      assert 1 == cache.size();
+      DummyTransactionManager.getInstance().rollback();
+
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+   }
+
+   public void testRollbackAfterRemove() throws Exception
+   {
+      CacheSPI<String, String> cache = cacheTL.get();
+      String key = "key", value = "value";
+      cache.put(key, value);
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+
+      DummyTransactionManager.getInstance().begin();
+      cache.remove(key);
+      assert cache.get(key) == null;
+      DummyTransactionManager.getInstance().rollback();
+
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+   }
+
+   public void testRollbackAfterClear() throws Exception
+   {
+      CacheSPI<String, String> cache = cacheTL.get();
+      String key = "key", value = "value";
+      cache.put(key, value);
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+
+      DummyTransactionManager.getInstance().begin();
+      cache.clear();
+      assert cache.get(key) == null;
+      DummyTransactionManager.getInstance().rollback();
+
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+   }
 }

Modified: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -2,7 +2,6 @@
 
 import org.jboss.cache.lock.IsolationLevel;
 import org.jboss.starobrno.api.CacheAPITest;
-import org.jboss.starobrno.config.Configuration;
 import org.testng.annotations.Test;
 
 /**
@@ -12,9 +11,8 @@
 public class CacheAPIMVCCTest extends CacheAPITest
 {
    @Override
-   protected void configure(Configuration c)
+   protected IsolationLevel getIsolationLevel()
    {
-      super.configure(c);
-      c.setIsolationLevel(IsolationLevel.READ_COMMITTED);
+      return IsolationLevel.READ_COMMITTED;
    }
 }
\ No newline at end of file

Modified: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -2,7 +2,6 @@
 
 import org.jboss.cache.lock.IsolationLevel;
 import org.jboss.starobrno.api.CacheAPITest;
-import org.jboss.starobrno.config.Configuration;
 import org.testng.annotations.Test;
 
 /**
@@ -12,9 +11,8 @@
 public class CacheAPIMVCCTest extends CacheAPITest
 {
    @Override
-   protected void configure(Configuration c)
+   protected IsolationLevel getIsolationLevel()
    {
-      super.configure(c);
-      c.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
+      return IsolationLevel.READ_COMMITTED;
    }
 }
\ No newline at end of file

Modified: core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeAPITest.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeAPITest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -53,7 +53,7 @@
    public void tearDown()
    {
       TreeCache<Object, Object> cache = cacheTL.get();
-      TestingUtil.killCaches(cache.getCache());
+      TestingUtil.killTreeCaches(cache);
       cacheTL.set(null);
    }
 

Added: core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeMoveAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeMoveAPITest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeMoveAPITest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -0,0 +1,667 @@
+package org.jboss.starobrno.tree.api;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.NodeNotExistsException;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.UnitTestCacheFactory;
+import org.jboss.starobrno.api.mvcc.LockAssert;
+import org.jboss.starobrno.config.CacheLoaderConfig;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.parsing.XmlConfigHelper;
+import org.jboss.starobrno.config.parsing.element.LoadersElementParser;
+import org.jboss.starobrno.factories.ComponentRegistry;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.tree.*;
+import org.jboss.starobrno.util.TestingUtil;
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.w3c.dom.Element;
+
+import javax.transaction.TransactionManager;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Excercises and tests the new move() api
+ *
+ * @author <a href="mailto:manik AT jboss DOT org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+ at Test(groups = {"functional", "pessimistic"}, testName = "api.NodeMoveAPITest")
+public class NodeMoveAPITest
+{
+   protected final Log log = LogFactory.getLog(getClass());
+
+   protected static final Fqn A = Fqn.fromString("/a"), B = Fqn.fromString("/b"), C = Fqn.fromString("/c"), D = Fqn.fromString("/d"), E = Fqn.fromString("/e");
+   static final Fqn A_B = Fqn.fromRelativeFqn(A, B);
+   static final Fqn A_B_C = Fqn.fromRelativeFqn(A_B, C);
+   static final Fqn A_B_C_E = Fqn.fromRelativeFqn(A_B_C, E);
+   static final Fqn A_B_D = Fqn.fromRelativeFqn(A_B, D);
+   static final Fqn C_E = Fqn.fromRelativeFqn(C, E);
+   static final Fqn D_B = Fqn.fromRelativeFqn(D, B);
+   static final Fqn D_B_C = Fqn.fromRelativeFqn(D_B, C);
+   protected static final Object k = "key", vA = "valueA", vB = "valueB", vC = "valueC", vD = "valueD", vE = "valueE";
+
+   protected ThreadLocal<TreeCache<Object, Object>> cacheTL = new ThreadLocal<TreeCache<Object, Object>>();
+   protected ThreadLocal<TransactionManager> tmTL = new ThreadLocal<TransactionManager>();
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp() throws Exception
+   {
+      // start a single cache instance
+      Configuration c = new Configuration();
+      c.setFetchInMemoryState(false);
+      c.setInvocationBatchingEnabled(true);
+      CacheSPI<Object, Object> cache = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(c);
+
+      cacheTL.set(new TreeCacheImpl<Object, Object>(cache));
+      tmTL.set(cache.getTransactionManager());
+   }
+
+   @AfterMethod(alwaysRun = true)
+   public void tearDown()
+   {
+      TestingUtil.killTreeCaches(cacheTL.get());
+      cacheTL.set(null);
+   }
+
+   public void testBasicMove()
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      TransactionManager tm = tmTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      nodeA.put(k, vA);
+      Node<Object, Object> nodeB = rootNode.addChild(B);
+      nodeB.put(k, vB);
+      Node<Object, Object> nodeC = nodeA.addChild(C);
+      nodeC.put(k, vC);
+      /*
+        /a/c
+        /b
+      */
+
+      assertTrue(rootNode.hasChild(A));
+      assertTrue(rootNode.hasChild(B));
+      assertFalse(rootNode.hasChild(C));
+      assertTrue(nodeA.hasChild(C));
+
+      // test data
+      assertEquals("" + nodeA, vA, nodeA.get(k));
+      assertEquals(vB, nodeB.get(k));
+      assertEquals(vC, nodeC.get(k));
+
+      // parentage
+      assertEquals(nodeA, nodeC.getParent());
+
+      log.info("BEFORE MOVE " + cache);
+      // move
+      cache.move(nodeC.getFqn(), nodeB.getFqn());
+
+      // re-fetch nodeC
+      nodeC = cache.getNode(Fqn.fromRelativeFqn(nodeB.getFqn(), C));
+
+      log.info("POST MOVE " + cache);
+      log.info("HC " + nodeC + " " + System.identityHashCode(nodeC));
+      Node x = cache.getRoot().getChild(Fqn.fromString("b/c"));
+      log.info("HC " + x + " " + System.identityHashCode(x));
+      /*
+         /a
+         /b/c
+      */
+      assertEquals("NODE C " + nodeC, "/b/c", nodeC.getFqn().toString());
+
+      assertTrue(rootNode.hasChild(A));
+      assertTrue(rootNode.hasChild(B));
+      assertFalse(rootNode.hasChild(C));
+      assertFalse(nodeA.hasChild(C));
+      assertTrue(nodeB.hasChild(C));
+
+      // test data
+      assertEquals(vA, nodeA.get(k));
+      assertEquals(vB, nodeB.get(k));
+      assertEquals(vC, nodeC.get(k));
+
+      // parentage
+      assertEquals("B is parent of C: " + nodeB, nodeB, nodeC.getParent());
+   }
+
+   @SuppressWarnings("unchecked")
+   private Node<Object, Object> genericize(Node node)
+   {
+      return (Node<Object, Object>) node;
+   }
+
+   public void testMoveWithChildren()
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      TransactionManager tm = tmTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      nodeA.put(k, vA);
+      Node<Object, Object> nodeB = rootNode.addChild(B);
+      nodeB.put(k, vB);
+      Node<Object, Object> nodeC = nodeA.addChild(C);
+      nodeC.put(k, vC);
+      Node<Object, Object> nodeD = nodeC.addChild(D);
+      nodeD.put(k, vD);
+      Node<Object, Object> nodeE = nodeD.addChild(E);
+      nodeE.put(k, vE);
+
+      assertTrue(rootNode.hasChild(A));
+      assertTrue(rootNode.hasChild(B));
+      assertFalse(rootNode.hasChild(C));
+      assertTrue(nodeA.hasChild(C));
+      assertTrue(nodeC.hasChild(D));
+      assertTrue(nodeD.hasChild(E));
+
+      // test data
+      assertEquals(vA, nodeA.get(k));
+      assertEquals(vB, nodeB.get(k));
+      assertEquals(vC, nodeC.get(k));
+      assertEquals(vD, nodeD.get(k));
+      assertEquals(vE, nodeE.get(k));
+
+      // parentage
+      assertEquals(rootNode, nodeA.getParent());
+      assertEquals(rootNode, nodeB.getParent());
+      assertEquals(nodeA, nodeC.getParent());
+      assertEquals(nodeC, nodeD.getParent());
+      assertEquals(nodeD, nodeE.getParent());
+
+      // move
+      log.info("move " + nodeC + " to " + nodeB);
+      cache.move(nodeC.getFqn(), nodeB.getFqn());
+      //System.out.println("nodeB " + nodeB);
+      //System.out.println("nodeC " + nodeC);
+
+      // child nodes will need refreshing, since existing pointers will be stale.
+      nodeC = nodeB.getChild(C);
+      nodeD = nodeC.getChild(D);
+      nodeE = nodeD.getChild(E);
+
+      assertTrue(rootNode.hasChild(A));
+      assertTrue(rootNode.hasChild(B));
+      assertFalse(rootNode.hasChild(C));
+      assertFalse(nodeA.hasChild(C));
+      assertTrue(nodeB.hasChild(C));
+      assertTrue(nodeC.hasChild(D));
+      assertTrue(nodeD.hasChild(E));
+
+      // test data
+      assertEquals(vA, nodeA.get(k));
+      assertEquals(vB, nodeB.get(k));
+      assertEquals(vC, nodeC.get(k));
+      assertEquals(vD, nodeD.get(k));
+      assertEquals(vE, nodeE.get(k));
+
+      // parentage
+      assertEquals(rootNode, nodeA.getParent());
+      assertEquals(rootNode, nodeB.getParent());
+      assertEquals(nodeB, nodeC.getParent());
+      assertEquals(nodeC, nodeD.getParent());
+      assertEquals(nodeD, nodeE.getParent());
+   }
+
+   public void testTxCommit() throws Exception
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      TransactionManager tm = tmTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+
+      assertEquals(rootNode, nodeA.getParent());
+      assertEquals(nodeA, nodeB.getParent());
+      assertEquals(nodeA, rootNode.getChildren().iterator().next());
+      assertEquals(nodeB, nodeA.getChildren().iterator().next());
+
+      tm.begin();
+      // move node B up to hang off the root
+      cache.move(nodeB.getFqn(), Fqn.ROOT);
+
+      tm.commit();
+
+      nodeB = rootNode.getChild(B);
+
+      assertEquals(rootNode, nodeA.getParent());
+      assertEquals(rootNode, nodeB.getParent());
+
+      assertTrue(rootNode.getChildren().contains(nodeA));
+      assertTrue(rootNode.getChildren().contains(nodeB));
+
+      assertTrue(nodeA.getChildren().isEmpty());
+   }
+
+   public void testTxRollback() throws Exception
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      TransactionManager tm = tmTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+
+      assertEquals(rootNode, nodeA.getParent());
+      assertEquals(nodeA, nodeB.getParent());
+      assertEquals(nodeA, rootNode.getChildren().iterator().next());
+      assertEquals(nodeB, nodeA.getChildren().iterator().next());
+
+
+      tm.begin();
+      // move node B up to hang off the root
+      System.out.println("Before: " + TreeStructureSupport.printTree(cache, true));
+      cache.move(nodeB.getFqn(), Fqn.ROOT);
+      System.out.println("After: " + TreeStructureSupport.printTree(cache, true));
+      tm.rollback();
+      System.out.println("Rolled back: " + TreeStructureSupport.printTree(cache, true));
+
+      nodeA = rootNode.getChild(A);
+      nodeB = nodeA.getChild(B);
+
+      // should revert
+      assertEquals(rootNode, nodeA.getParent());
+      assertEquals(nodeA, nodeB.getParent());
+      assertEquals(nodeA, rootNode.getChildren().iterator().next());
+      assertEquals(nodeB, nodeA.getChildren().iterator().next());
+   }
+
+   /*
+   public void testWithCacheloaders() throws Exception
+   {
+      doCacheLoaderTest(false, false);
+   }
+
+   public void testWithPassivation() throws Exception
+   {
+      doCacheLoaderTest(true, false);
+   }
+
+   public void testWithCacheloadersTx() throws Exception
+   {
+      doCacheLoaderTest(false, true);
+   }
+
+   public void testWithPassivationTx() throws Exception
+   {
+      doCacheLoaderTest(true, true);
+   }
+   */
+
+   /*
+protected void doCacheLoaderTest(boolean pasv, boolean useTx) throws Exception
+{
+TreeCache<Object, Object> cache = cacheTL.get();
+TransactionManager tm = tmTL.get();
+Node<Object, Object> rootNode = cache.getRoot();
+
+cache.destroy();
+cache.getConfiguration().setCacheLoaderConfig(getSingleCacheLoaderConfig(pasv, "/", DummyInMemoryCacheLoader.class.getName(), "debug=true", false, false, false, false));
+cache.start();
+
+DummyInMemoryCacheLoader loader = (DummyInMemoryCacheLoader) cache.getCacheLoaderManager().getCacheLoader();
+
+rootNode.put("key", "value");
+
+if (!pasv)
+{
+Map m = loader.get(Fqn.ROOT);
+assertNotNull("Should not be null", m);
+assertEquals("value", m.get("key"));
+}
+
+Node<Object, Object> nodeA = rootNode.addChild(A);
+nodeA.put(k, vA);
+Node<Object, Object> nodeB = rootNode.addChild(B);
+nodeB.put(k, vB);
+Node<Object, Object> nodeC = nodeA.addChild(C);
+nodeC.put(k, vC);
+Node<Object, Object> nodeD = nodeC.addChild(D);
+nodeD.put(k, vD);
+Node<Object, Object> nodeE = nodeD.addChild(E);
+nodeE.put(k, vE);
+cache.evict(Fqn.ROOT, true);
+
+// move
+if (useTx) tm.begin();
+cache.move(nodeC.getFqn(), nodeB.getFqn());
+if (useTx) tm.commit();
+
+// after eviction, the node objects we hold are probably stale.
+nodeA = rootNode.getChild(A);
+nodeB = rootNode.getChild(B);
+nodeC = nodeB.getChild(C);
+log.info("nodeC get child B ");
+nodeD = nodeC.getChild(D);
+log.info("nodeD get child E ");
+nodeE = nodeD.getChild(E);
+
+Fqn old_C = C;
+Fqn old_D = Fqn.fromRelativeFqn(old_C, D);
+Fqn old_E = Fqn.fromRelativeFqn(old_D, E);
+
+// test data
+assertEquals(vA, nodeA.get(k));
+assertEquals(vB, nodeB.get(k));
+assertEquals(vC, nodeC.get(k));
+assertEquals(vD, nodeD.get(k));
+assertEquals(vE, nodeE.get(k));
+
+// parentage
+assertEquals(rootNode, nodeA.getParent());
+assertEquals(rootNode, nodeB.getParent());
+assertEquals(nodeB, nodeC.getParent());
+assertEquals(nodeC, nodeD.getParent());
+assertEquals(nodeD, nodeE.getParent());
+
+
+if (pasv) cache.evict(Fqn.ROOT, true);
+
+//now inspect the loader.
+assertEquals(vA, loader.get(nodeA.getFqn()).get(k));
+assertEquals(vB, loader.get(nodeB.getFqn()).get(k));
+assertEquals(vC, loader.get(nodeC.getFqn()).get(k));
+assertEquals(vD, loader.get(nodeD.getFqn()).get(k));
+assertEquals(vE, loader.get(nodeE.getFqn()).get(k));
+
+assertNull(loader.get(old_C));
+assertNull(loader.get(old_D));
+assertNull(loader.get(old_E));
+
+}
+   */
+
+   public void testLocksDeepMove() throws Exception
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      TransactionManager tm = tmTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+      Node<Object, Object> nodeD = nodeB.addChild(D);
+      Node<Object, Object> nodeC = rootNode.addChild(C);
+      Node<Object, Object> nodeE = nodeC.addChild(E);
+      assertNoLocks();
+      tm.begin();
+
+      cache.move(nodeC.getFqn(), nodeB.getFqn());
+
+      checkLocksDeep();
+
+
+      tm.commit();
+
+      assertNoLocks();
+   }
+
+   public void testLocks() throws Exception
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      TransactionManager tm = tmTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+      Node<Object, Object> nodeC = rootNode.addChild(C);
+      assertNoLocks();
+      tm.begin();
+
+      cache.move(nodeC.getFqn(), nodeB.getFqn());
+
+      checkLocks();
+
+      tm.commit();
+      assertNoLocks();
+   }
+
+   public void testConcurrency() throws InterruptedException
+   {
+      final TreeCache<Object, Object> cache = cacheTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      final int N = 3;// number of threads
+      final int loops = 1 << 6;// number of loops
+      // tests a tree structure as such:
+      // /a
+      // /b
+      // /c
+      // /d
+      // /e
+      // /x
+      // /y
+
+      // N threads constantly move /x and /y around to hang off either /a ~ /e randomly.
+
+      final Fqn FQN_A = A, FQN_B = B, FQN_C = C, FQN_D = D, FQN_E = E, FQN_X = Fqn.fromString("/x"), FQN_Y = Fqn.fromString("/y");
+
+      // set up the initial structure.
+      final Node[] NODES = {
+            rootNode.addChild(FQN_A), rootNode.addChild(FQN_B),
+            rootNode.addChild(FQN_C), rootNode.addChild(FQN_D), rootNode.addChild(FQN_E)
+      };
+
+      final Node<Object, Object> NODE_X = genericize(NODES[0]).addChild(FQN_X);
+      final Node<Object, Object> NODE_Y = genericize(NODES[1]).addChild(FQN_Y);
+
+      Thread[] movers = new Thread[N];
+      final CountDownLatch latch = new CountDownLatch(1);
+      final Random r = new Random();
+
+      for (int i = 0; i < N; i++)
+      {
+         movers[i] = new Thread("Mover-" + i)
+         {
+            public void run()
+            {
+               try
+               {
+                  latch.await();
+               }
+               catch (InterruptedException e)
+               {
+               }
+
+               for (int counter = 0; counter < loops; counter++)
+               {
+
+                  System.out.println(getName() + ": Attempt " + counter);
+                  try
+                  {
+                     cache.move(NODE_X.getFqn(), NODES[r.nextInt(NODES.length)].getFqn());
+                  }
+                  catch (NodeNotExistsException e)
+                  {
+                     // this may happen ...
+                  }
+                  TestingUtil.sleepRandom(250);
+                  try
+                  {
+                     cache.move(NODE_Y.getFqn(), NODES[r.nextInt(NODES.length)].getFqn());
+                  }
+                  catch (NodeNotExistsException e)
+                  {
+                     // this may happen ...
+                  }
+                  TestingUtil.sleepRandom(250);
+               }
+            }
+         };
+         movers[i].start();
+      }
+
+      latch.countDown();
+
+      for (Thread t : movers)
+      {
+         t.join();
+      }
+
+      assertNoLocks();
+      boolean found_x = false, found_x_again = false;
+      for (Node erased : NODES)
+      {
+         Node<Object, Object> n = genericize(erased);
+         if (!found_x)
+         {
+            found_x = n.hasChild(FQN_X);
+         }
+         else
+         {
+            found_x_again = found_x_again || n.hasChild(FQN_X);
+         }
+      }
+      boolean found_y = false, found_y_again = false;
+      for (Node erased : NODES)
+      {
+         Node<Object, Object> n = genericize(erased);
+         if (!found_y)
+         {
+            found_y = n.hasChild(FQN_Y);
+         }
+         else
+         {
+            found_y_again = found_y_again || n.hasChild(FQN_Y);
+         }
+      }
+
+      assertTrue("Should have found x", found_x);
+      assertTrue("Should have found y", found_y);
+      assertFalse("Should have only found x once", found_x_again);
+      assertFalse("Should have only found y once", found_y_again);
+   }
+
+   public void testMoveInSamePlace()
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      Node<Object, Object> rootNode = cache.getRoot();
+
+      final Fqn FQN_X = Fqn.fromString("/x");
+      // set up the initial structure.
+      Node aNode = rootNode.addChild(A);
+      Node xNode = aNode.addChild(FQN_X);
+      assertEquals(aNode.getChildren().size(), 1);
+
+      System.out.println("Before: " + TreeStructureSupport.printTree(cache, true));
+
+      cache.move(xNode.getFqn(), aNode.getFqn());
+
+      System.out.println("After: " + TreeStructureSupport.printTree(cache, true));
+
+      assertEquals(aNode.getChildren().size(), 1);
+
+      assertNoLocks();
+   }
+
+   protected CacheLoaderConfig getSingleCacheLoaderConfig(boolean passivation, String preload, String cacheloaderClass, String properties, boolean async, boolean fetchPersistentState, boolean shared, boolean purgeOnStartup) throws Exception
+   {
+      String xml =
+            "      <loaders passivation=\"" + passivation + "\" shared=\"" + shared + "\">\n" +
+                  "         <preload>\n" +
+                  "            <node fqn=\"" + preload + "\"/>\n" +
+                  "         </preload>\n" +
+                  "         <loader class=\"" + cacheloaderClass + "\" async=\"" + async + "\" fetchPersistentState=\"" + fetchPersistentState + "\"\n" +
+                  "                     purgeOnStartup=\"" + purgeOnStartup + "\">\n" +
+                  "            <properties>\n" +
+                  properties +
+                  "            </properties>\n" +
+                  "         </loader>\n" +
+                  "      </loaders>";
+      Element element = XmlConfigHelper.stringToElementInCoreNS(xml);
+      LoadersElementParser elementParser = new LoadersElementParser();
+      return elementParser.parseLoadersElement(element);
+   }
+
+   protected void checkLocks()
+   {
+      TreeCache<Object, Object> tree = cacheTL.get();
+      Cache<Object, Object> cache = tree.getCache();
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+      LockManager lm = cr.getComponent(LockManager.class);
+      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
+
+//      assert !TreeStructureSupport.isLocked(cache, A);
+//      assert !TreeStructureSupport.isLocked(cache, Fqn.ROOT);
+
+      assert TreeStructureSupport.isLocked(cache, C);
+      assert TreeStructureSupport.isLocked(cache, A_B);
+      assert TreeStructureSupport.isLocked(cache, A_B_C);
+   }
+
+   protected void checkLocksDeep()
+   {
+      TreeCache<Object, Object> tree = cacheTL.get();
+      Cache<Object, Object> cache = tree.getCache();
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+      LockManager lm = cr.getComponent(LockManager.class);
+      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
+
+//      assert !TreeStructureSupport.isLocked(cache, A);
+//      assert !TreeStructureSupport.isLocked(cache, Fqn.ROOT);
+//      assert !TreeStructureSupport.isLocked(cache, A_B_D);
+
+      // /a/b, /c, /c/e, /a/b/c and /a/b/c/e should all be locked.
+      assert TreeStructureSupport.isLocked(cache, A_B);
+      assert TreeStructureSupport.isLocked(cache, C);
+      assert TreeStructureSupport.isLocked(cache, C_E);
+      assert TreeStructureSupport.isLocked(cache, A_B_C);
+      assert TreeStructureSupport.isLocked(cache, A_B_C_E);
+   }
+
+   protected void assertNoLocks()
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache.getCache());
+      LockManager lm = cr.getComponent(LockManager.class);
+      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
+      LockAssert.assertNoLocks(lm, icc);
+   }
+
+   public void testNonexistentSource()
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      cache.put(A_B_C, "k", "v");
+      assert "v".equals(cache.get(A_B_C, "k"));
+      assert 1 == cache.getNode(A_B).getChildren().size();
+      assert cache.getNode(A_B).getChildrenNames().contains(C.getLastElement());
+      assert !cache.getNode(A_B).getChildrenNames().contains(D.getLastElement());
+
+      cache.move(D, A_B);
+
+      assert "v".equals(cache.get(A_B_C, "k"));
+      assert 1 == cache.getNode(A_B).getChildren().size();
+      assert cache.getNode(A_B).getChildrenNames().contains(C.getLastElement());
+      assert !cache.getNode(A_B).getChildrenNames().contains(D.getLastElement());
+   }
+
+   public void testNonexistentTarget()
+   {
+      TreeCache<Object, Object> cache = cacheTL.get();
+      cache.put(A_B_C, "k", "v");
+      assert "v".equals(cache.get(A_B_C, "k"));
+      assert 1 == cache.getNode(A_B).getChildren().size();
+      assert cache.getNode(A_B).getChildrenNames().contains(C.getLastElement());
+      assert null == cache.getNode(D);
+
+      System.out.println(TreeStructureSupport.printTree(cache, true));
+
+      cache.move(A_B, D);
+
+      System.out.println(TreeStructureSupport.printTree(cache, true));
+
+      assert null == cache.getNode(A_B_C);
+      assert null == cache.getNode(A_B);
+      assert null != cache.getNode(D);
+      assert null != cache.getNode(D_B);
+      assert null != cache.getNode(D_B_C);
+      assert "v".equals(cache.get(D_B_C, "k"));
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeReplicatedMoveTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeReplicatedMoveTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/NodeReplicatedMoveTest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -0,0 +1,159 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.starobrno.tree.api;
+
+import org.jboss.starobrno.UnitTestCacheFactory;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.tree.Fqn;
+import org.jboss.starobrno.tree.Node;
+import org.jboss.starobrno.tree.TreeCache;
+import org.jboss.starobrno.tree.TreeCacheImpl;
+import org.jboss.starobrno.util.TestingUtil;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+
+ at Test(groups = {"functional", "jgroups", "pessimistic"}, testName = "api.NodeReplicatedMoveTest")
+public class NodeReplicatedMoveTest
+{
+   private class NodeReplicatedMoveTestTL
+   {
+      protected TreeCache<Object, Object> cache1;
+      protected TreeCache<Object, Object> cache2;
+      protected TransactionManager tm;
+   }
+
+   protected ThreadLocal<NodeReplicatedMoveTestTL> threadLocal = new ThreadLocal<NodeReplicatedMoveTestTL>();
+
+   protected static final Fqn A = Fqn.fromString("/a"), B = Fqn.fromString("/b"), C = Fqn.fromString("/c"), D = Fqn.fromString("/d"), E = Fqn.fromString("/e");
+   protected static final Object k = "key", vA = "valueA", vB = "valueB", vC = "valueC", vD = "valueD", vE = "valueE";
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp() throws Exception
+   {
+      NodeReplicatedMoveTestTL tl = new NodeReplicatedMoveTestTL();
+      threadLocal.set(tl);
+      Configuration c = new Configuration();
+      c.setInvocationBatchingEnabled(true);
+      c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+      c.setSyncCommitPhase(true);
+      c.setSyncRollbackPhase(true);
+      // start a single cache instance
+      tl.cache1 = new TreeCacheImpl<Object, Object>(new UnitTestCacheFactory<Object, Object>().createCache(c.clone()));
+      tl.cache2 = new TreeCacheImpl<Object, Object>(new UnitTestCacheFactory<Object, Object>().createCache(c.clone()));
+      tl.tm = tl.cache1.getConfiguration().getRuntimeConfig().getTransactionManager();
+
+      TestingUtil.blockUntilViewsReceived(10000, tl.cache1.getCache(),  tl.cache2.getCache());
+   }
+
+   @AfterMethod(alwaysRun = true)
+   public void tearDown()
+   {
+      NodeReplicatedMoveTestTL tl = threadLocal.get();
+      if (tl != null)
+      {
+         TestingUtil.killTreeCaches(tl.cache1, tl.cache2);
+         threadLocal.set(null);
+      }
+   }
+
+
+
+   public void testReplicatability()
+   {
+      NodeReplicatedMoveTestTL tl = threadLocal.get();
+      Node<Object, Object> rootNode = tl.cache1.getRoot();
+
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+
+      nodeA.put(k, vA);
+      nodeB.put(k, vB);
+
+      assertEquals(vA, tl.cache1.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache1.getRoot().getChild(A).getChild(B).get(k));
+
+      assertEquals(vA, tl.cache2.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache2.getRoot().getChild(A).getChild(B).get(k));
+
+      // now move...
+      tl.cache1.move(nodeB.getFqn(), Fqn.ROOT);
+
+      assertEquals(vA, tl.cache1.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache1.getRoot().getChild(B).get(k));
+
+      assertEquals(vA, tl.cache2.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache2.getRoot().getChild(B).get(k));
+   }
+
+   public void testReplTxCommit() throws Exception
+   {
+      NodeReplicatedMoveTestTL tl = threadLocal.get();
+      Node<Object, Object> rootNode = tl.cache1.getRoot();
+      Fqn A_B = Fqn.fromRelativeFqn(A, B);
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+
+      nodeA.put(k, vA);
+      nodeB.put(k, vB);
+
+      assertEquals(vA, tl.cache1.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache1.getRoot().getChild(A).getChild(B).get(k));
+
+      assertEquals(vA, tl.cache2.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache2.getRoot().getChild(A).getChild(B).get(k));
+
+      // now move...
+      tl.tm.begin();
+      tl.cache1.move(nodeB.getFqn(), Fqn.ROOT);
+
+      assertEquals(vA, tl.cache1.get(A, k));
+      assertNull(tl.cache1.get(A_B, k));
+      assertEquals(vB, tl.cache1.get(B, k));
+      tl.tm.commit();
+
+      assertEquals(vA, tl.cache1.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache1.getRoot().getChild(B).get(k));
+      assertEquals(vA, tl.cache2.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache2.getRoot().getChild(B).get(k));
+
+   }
+
+   public void testReplTxRollback() throws Exception
+   {
+      NodeReplicatedMoveTestTL tl = threadLocal.get();
+      Node<Object, Object> rootNode = tl.cache1.getRoot();
+      Node<Object, Object> nodeA = rootNode.addChild(A);
+      Node<Object, Object> nodeB = nodeA.addChild(B);
+
+      nodeA.put(k, vA);
+      nodeB.put(k, vB);
+
+      assertEquals(vA, tl.cache1.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache1.getRoot().getChild(A).getChild(B).get(k));
+      assertEquals(vA, tl.cache2.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache2.getRoot().getChild(A).getChild(B).get(k));
+
+      // now move...
+      tl.tm.begin();
+      tl.cache1.move(nodeB.getFqn(), Fqn.ROOT);
+
+      assertEquals(vA, tl.cache1.get(A, k));
+      assertEquals(vB, tl.cache1.get(B, k));
+
+      tl.tm.rollback();
+
+      assertEquals(vA, tl.cache1.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache1.getRoot().getChild(A).getChild(B).get(k));
+      assertEquals(vA, tl.cache2.getRoot().getChild(A).get(k));
+      assertEquals(vB, tl.cache2.getRoot().getChild(A).getChild(B).get(k));
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -0,0 +1,135 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.starobrno.tree.api;
+
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.UnitTestCacheFactory;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.tree.Fqn;
+import org.jboss.starobrno.tree.Node;
+import org.jboss.starobrno.tree.TreeCache;
+import org.jboss.starobrno.tree.TreeCacheImpl;
+import org.jboss.starobrno.util.TestingUtil;
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:manik AT jboss DOT org">Manik Surtani (manik AT jboss DOT org)</a>
+ */
+ at Test(groups = {"functional", "jgroups", "pessimistic"}, sequential = true, testName = "api.SyncReplTest")
+public class SyncReplTest
+{
+   private CacheSPI<Object, Object> c1, c2;
+   private TreeCache<Object, Object> cache1, cache2;
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp()
+   {
+      System.out.println("*** In setUp()");
+      Configuration c = new Configuration();
+      c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+      c.setInvocationBatchingEnabled(true);
+      c.setFetchInMemoryState(false);
+
+      c1 = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(c.clone());
+      c2 = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(c.clone());
+
+      TestingUtil.blockUntilViewsReceived(new Cache[]{c1, c2}, 5000);
+
+      cache1 = new TreeCacheImpl<Object, Object>(c1);
+      cache2 = new TreeCacheImpl<Object, Object>(c2);
+
+      System.out.println("*** Finished setUp()");
+   }
+
+   @AfterMethod(alwaysRun = true)
+   public void tearDown()
+   {
+      TestingUtil.killCaches(c1, c2);
+      cache1 = null;
+      cache2 = null;      
+   }
+
+   public void testBasicOperation()
+   {
+      assertClusterSize("Should only be 2  caches in the cluster!!!", 2);
+
+      Fqn f = Fqn.fromString("/test/data");
+      String k = "key", v = "value";
+
+      assertNull("Should be null", cache1.getRoot().getChild(f));
+      assertNull("Should be null", cache2.getRoot().getChild(f));
+
+      Node<Object, Object> node = cache1.getRoot().addChild(f);
+
+      assertNotNull("Should not be null", node);
+
+      node.put(k, v);
+
+      assertEquals(v, node.get(k));
+      assertEquals(v, cache1.get(f, k));
+      assert v.equals(cache2.get(f, k));
+   }
+
+   public void testSyncRepl()
+   {
+      assertClusterSize("Should only be 2  caches in the cluster!!!", 2);
+
+      Fqn fqn = Fqn.fromString("/JSESSIONID/1010.10.5:3000/1234567890/1");
+      cache1.getConfiguration().setSyncCommitPhase(true);
+      cache2.getConfiguration().setSyncCommitPhase(true);
+
+
+      cache1.put(fqn, "age", 38);
+      assertEquals("Value should be set", 38, cache1.get(fqn, "age"));
+      assertEquals("Value should have replicated", 38, cache2.get(fqn, "age"));
+   }
+
+   public void testPutMap()
+   {
+      assertClusterSize("Should only be 2  caches in the cluster!!!", 2);
+
+      Fqn fqn = Fqn.fromString("/JSESSIONID/10.10.10.5:3000/1234567890/1");
+      Fqn fqn1 = Fqn.fromString("/JSESSIONID/10.10.10.5:3000/1234567890/2");
+
+      Map<Object, Object> map = new HashMap<Object, Object>();
+      map.put("1", "1");
+      map.put("2", "2");
+      cache1.getInvocationContext().getOptionOverrides().setSuppressLocking(true);
+      cache1.getRoot().addChild(fqn).putAll(map);
+      cache1.getInvocationContext().getOptionOverrides().setSuppressLocking(true);
+      assertEquals("Value should be set", "1", cache1.get(fqn, "1"));
+
+      map = new HashMap<Object, Object>();
+      map.put("3", "3");
+      map.put("4", "4");
+      cache1.getInvocationContext().getOptionOverrides().setSuppressLocking(true);
+      cache1.getRoot().addChild(fqn1).putAll(map);
+
+      cache1.getInvocationContext().getOptionOverrides().setSuppressLocking(true);
+      assertEquals("Value should be set", "2", cache1.get(fqn, "2"));
+   }
+
+
+   private void assertClusterSize(String message, int size)
+   {
+      assertClusterSize(message, size, cache1);
+      assertClusterSize(message, size, cache2);
+   }
+
+   private void assertClusterSize(String message, int size, TreeCache c)
+   {
+      assertEquals(message, size, c.getMembers().size());
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTxTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTxTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/SyncReplTxTest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -0,0 +1,117 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.starobrno.tree.api;
+
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.UnitTestCacheFactory;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.tree.Fqn;
+import org.jboss.starobrno.tree.Node;
+import org.jboss.starobrno.tree.TreeCache;
+import org.jboss.starobrno.tree.TreeCacheImpl;
+import org.jboss.starobrno.util.TestingUtil;
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:manik AT jboss DOT org">Manik Surtani (manik AT jboss DOT org)</a>
+ */
+ at Test(groups = {"functional", "jgroups", "transaction", "pessimistic"}, sequential = true, testName = "api.SyncReplTxTest")
+public class SyncReplTxTest
+{
+   private List<CacheSPI<Object, Object>> flatCaches;
+   private List<TreeCache<Object, Object>> caches;
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp() throws CloneNotSupportedException
+   {
+      System.out.println("*** In setUp()");
+      caches = new ArrayList<TreeCache<Object, Object>>();
+      flatCaches = new ArrayList<CacheSPI<Object, Object>>();
+      Configuration c = new Configuration();
+      c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+      c.setFetchInMemoryState(false);
+      c.setInvocationBatchingEnabled(true);
+      c.setSyncCommitPhase(true);
+      c.setSyncRollbackPhase(true);
+      c.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+
+      CacheSPI<Object, Object> cache1 = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(c.clone());
+      CacheSPI<Object, Object> cache2 = (CacheSPI<Object, Object>) new UnitTestCacheFactory<Object, Object>().createCache(c.clone());
+
+      flatCaches.add(cache1);
+      flatCaches.add(cache2);
+
+      TestingUtil.blockUntilViewsReceived(caches.toArray(new Cache[0]), 10000);
+
+      caches.add(new TreeCacheImpl<Object, Object>(cache1));
+      caches.add(new TreeCacheImpl<Object, Object>(cache2));
+
+      System.out.println("*** Finished setUp()");
+   }
+
+   @AfterMethod(alwaysRun = true)
+   public void tearDown()
+   {
+      System.out.println("*** In tearDown()");
+      TestingUtil.killTreeCaches(caches);
+      caches = null;
+      System.out.println("*** Finished tearDown()");
+   }
+
+   private TransactionManager beginTransaction(Cache<Object, Object> cache) throws NotSupportedException, SystemException
+   {
+      TransactionManager mgr = cache.getConfiguration().getRuntimeConfig().getTransactionManager();
+      mgr.begin();
+      return mgr;
+   }
+
+   public void testBasicOperation() throws SystemException, NotSupportedException, HeuristicMixedException, HeuristicRollbackException, RollbackException
+   {
+      assertClusterSize("Should only be 2  caches in the cluster!!!", 2);
+
+      Fqn f = Fqn.fromString("/test/data");
+      String k = "key", v = "value";
+
+      assertNull("Should be null", caches.get(0).getRoot().getChild(f));
+      assertNull("Should be null", caches.get(1).getRoot().getChild(f));
+
+      Node<Object, Object> node = caches.get(0).getRoot().addChild(f);
+
+      assertNotNull("Should not be null", node);
+
+      TransactionManager tm = beginTransaction(caches.get(0).getCache());
+      node.put(k, v);
+      tm.commit();
+
+      assertEquals(v, node.get(k));
+      assertEquals(v, caches.get(0).get(f, k));
+      assertEquals("Should have replicated", v, caches.get(1).get(f, k));
+   }
+
+   private void assertClusterSize(String message, int size)
+   {
+      for (Cache<Object, Object> c : flatCaches)
+      {
+         assertClusterSize(message, size, c);
+      }
+   }
+
+   private void assertClusterSize(String message, int size, Cache<Object, Object> c)
+   {
+      assertEquals(message, size, c.getMembers().size());
+   }
+}
\ No newline at end of file

Modified: core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/TreeCacheAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/TreeCacheAPITest.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/tree/api/TreeCacheAPITest.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -44,7 +44,7 @@
    @AfterMethod(alwaysRun = true)
    public void tearDown()
    {
-      if (cache != null) TestingUtil.killCaches(cache.getCache());
+      TestingUtil.killTreeCaches(cache);
       cache = null;
    }
 

Modified: core/branches/flat/src/test/java/org/jboss/starobrno/util/TestingUtil.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/util/TestingUtil.java	2008-11-28 01:42:18 UTC (rev 7226)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/util/TestingUtil.java	2008-11-28 03:39:39 UTC (rev 7227)
@@ -17,12 +17,14 @@
 import org.jboss.starobrno.interceptors.InterceptorChain;
 import org.jboss.starobrno.interceptors.base.CommandInterceptor;
 import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.tree.TreeCache;
 import org.jgroups.JChannel;
 
 import javax.transaction.TransactionManager;
 import java.io.File;
 import java.lang.reflect.Field;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Random;
 
@@ -412,6 +414,24 @@
       f.delete();
    }
 
+   public static void killTreeCaches(Collection treeCaches)
+   {
+      if (treeCaches != null) killTreeCaches((TreeCache[]) treeCaches.toArray(new TreeCache[]{}));
+   }
+
+   public static void killCaches(Collection caches)
+   {
+      if (caches != null) killCaches((Cache[]) caches.toArray(new Cache[]{}));
+   }
+
+   public static void killTreeCaches(TreeCache... treeCaches)
+   {
+      for (TreeCache tc: treeCaches)
+      {
+         if (tc != null) killCaches(tc.getCache());
+      }
+   }
+
    /**
     * Kills a cache - stops it, clears any data in any cache loaders, and rolls back any associated txs
     */




More information about the jbosscache-commits mailing list