You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2008/03/19 08:53:00 UTC

svn commit: r638734 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/BatchedItemOperations.java test/java/org/apache/jackrabbit/core/ShareableNodeTest.java

Author: dpfister
Date: Wed Mar 19 00:52:55 2008
New Revision: 638734

URL: http://svn.apache.org/viewvc?rev=638734&view=rev
Log:
JCR-1104 - JSR 283 support
- shareble nodes (work in progress)

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=638734&r1=638733&r2=638734&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java Wed Mar 19 00:52:55 2008
@@ -268,7 +268,17 @@
             throw new RepositoryException(msg);
         }
         
-        // 4. do clone operation (modify and store affected states)
+        // 4. detect share cycle
+        NodeId srcId = srcState.getNodeId();
+        NodeId destParentId = destParentState.getNodeId();
+        if (destParentId.equals(srcId) || 
+                hierMgr.isAncestor(srcId, destParentId)) {
+            String msg = "This would create a share cycle.";
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+        
+        // 5. do clone operation (modify and store affected states)
         if (!srcState.addShare(destParentState.getNodeId())) {
             String msg = "Adding a shareable node twice to the same parent is not supported.";
             log.debug(msg);

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java?rev=638734&r1=638733&r2=638734&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java Wed Mar 19 00:52:55 2008
@@ -20,11 +20,18 @@
 
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.Workspace;
 import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
 
+import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.jackrabbit.test.AbstractJCRTest;
 
 /**
@@ -32,16 +39,18 @@
  */
 public class ShareableNodeTest extends AbstractJCRTest {
 
+    //------------------------------------------------------ specification tests
+    
     /**
-     * Add a child to a shareable node and verify that another node in the
-     * same shared set has the same child and is modified when the first
-     * one is.
+     * Verifies that Node.getIndex returns the correct index in a shareable 
+     * node (6.13).
      */
-    public void testAddChild() throws Exception {
+    public void testGetIndex() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
         Node b1 = a1.addNode("b1");
+        a2.addNode("b");
         testRootNode.save();
         
         // add mixin
@@ -51,7 +60,7 @@
         // clone
         Workspace workspace = b1.getSession().getWorkspace();
         workspace.clone(workspace.getName(), b1.getPath(), 
-                a2.getPath() + "/b2", true);
+                a2.getPath() + "/b", true);
 
         ArrayList list = new ArrayList();
 
@@ -59,33 +68,53 @@
         while (iter.hasNext()) {
             list.add(iter.nextNode());
         }
+        
         assertEquals(list.size(), 2);
         b1 = (Node) list.get(0);
         Node b2 = (Node) list.get(1);
-        
-        b1.addNode("c");
-        assertTrue(b2.isModified());
-        assertTrue(b2.hasNode("c"));
-        b1.save();
+        assertEquals(b1.getIndex(), 1);
+        assertEquals(b2.getIndex(), 2);
     }
     
     /**
-     * Adds the mix:shareable mixin to a node.
+     * Verifies that Node.getName returns the correct name in a shareable node
+     * (6.13).
      */
-    public void testAddMixin() throws Exception {
-        // setup parent node and first child 
-        Node a = testRootNode.addNode("a");
-        Node b = a.addNode("b");
+    public void testGetName() throws Exception {
+        // setup parent nodes and first child 
+        Node a1 = testRootNode.addNode("a1");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
         testRootNode.save();
         
-        b.addMixin("mix:shareable");
-        b.save();
+        // add mixin
+        b1.addMixin("mix:shareable");
+        b1.save();
+        
+        // clone
+        Workspace workspace = b1.getSession().getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(), 
+                a2.getPath() + "/b2", true);
+
+        ArrayList list = new ArrayList();
+
+        NodeIterator iter = ((NodeImpl) b1).getSharedSet();
+        while (iter.hasNext()) {
+            list.add(iter.nextNode());
+        }
+        
+        assertEquals(list.size(), 2);
+        b1 = (Node) list.get(0);
+        Node b2 = (Node) list.get(1);
+        assertEquals(b1.getName(), "b1");
+        assertEquals(b2.getName(), "b2");
     }
     
     /**
-     * Clones a mix:shareable node to the same workspace.
+     * Verifies that Node.getPath returns the correct path in a shareable 
+     * node (6.13).
      */
-    public void testClone() throws Exception {
+    public void testGetPath() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
@@ -100,16 +129,29 @@
         Workspace workspace = b1.getSession().getWorkspace();
         workspace.clone(workspace.getName(), b1.getPath(), 
                 a2.getPath() + "/b2", true);
+
+        ArrayList list = new ArrayList();
+
+        NodeIterator iter = ((NodeImpl) b1).getSharedSet();
+        while (iter.hasNext()) {
+            list.add(iter.nextNode());
+        }
+        
+        assertEquals(list.size(), 2);
+        b1 = (Node) list.get(0);
+        Node b2 = (Node) list.get(1);
+        assertEquals(b1.getPath(), "/testroot/a1/b1");
+        assertEquals(b2.getPath(), "/testroot/a2/b2");
     }
-    
+
     /**
-     * Clones a mix:shareable node to the same workspace, with the same
-     * parent. This is unsupported in Jackrabbit.
+     * Checks new API Node.getSharedSet() (6.13.1)
      */
-    public void testCloneToSameParent() throws Exception {
+    public void testIterateSharedSet() throws Exception {
         // setup parent nodes and first child 
-        Node a = testRootNode.addNode("a");
-        Node b1 = a.addNode("b1");
+        Node a1 = testRootNode.addNode("a1");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
         testRootNode.save();
         
         // add mixin
@@ -118,25 +160,39 @@
         
         // clone
         Workspace workspace = b1.getSession().getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(), 
+                a2.getPath() + "/b2", true);
         
-        try {
-            workspace.clone(workspace.getName(), b1.getPath(), 
-                    a.getPath() + "/b2", true);
-            fail("Cloning inside same parent should fail.");
-        } catch (UnsupportedRepositoryOperationException e) {
-            // expected
+        NodeIterator iter = ((NodeImpl) b1).getSharedSet();
+        int items = 0;
+        while (iter.hasNext()) {
+            iter.nextNode();
+            items++;
         }
+        assertEquals(items, 2);
     }
 
     /**
-     * Verifies that Node.getIndex returns the correct index in a shareable node.
+     * Adds the mix:shareable mixin to a node (6.13.2).
      */
-    public void testGetIndex() throws Exception {
+    public void testAddMixin() throws Exception {
+        // setup parent node and first child 
+        Node a = testRootNode.addNode("a");
+        Node b = a.addNode("b");
+        testRootNode.save();
+        
+        b.addMixin("mix:shareable");
+        b.save();
+    }
+    
+    /**
+     * Checks new API Node.removeShare() (6.13.4).
+     */
+    public void testRemoveShare() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
         Node b1 = a1.addNode("b1");
-        a2.addNode("b");
         testRootNode.save();
         
         // add mixin
@@ -146,7 +202,7 @@
         // clone
         Workspace workspace = b1.getSession().getWorkspace();
         workspace.clone(workspace.getName(), b1.getPath(), 
-                a2.getPath() + "/b", true);
+                a2.getPath() + "/b2", true);
 
         ArrayList list = new ArrayList();
 
@@ -158,14 +214,17 @@
         assertEquals(list.size(), 2);
         b1 = (Node) list.get(0);
         Node b2 = (Node) list.get(1);
-        assertEquals(b1.getIndex(), 1);
-        assertEquals(b2.getIndex(), 2);
+        assertTrue(b1.isSame(b2));
+        assertTrue(b2.isSame(b1));
+        
+        ((NodeImpl) b1).removeShare();
+        a1.save();
     }
-    
+
     /**
-     * Verifies that Node.getName returns the correct name in a shareable node.
+     * Checks new API Node.removeSharedSet() (6.13.4).
      */
-    public void testGetName() throws Exception {
+    public void testRemoveSharedSet() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
@@ -181,24 +240,46 @@
         workspace.clone(workspace.getName(), b1.getPath(), 
                 a2.getPath() + "/b2", true);
 
-        ArrayList list = new ArrayList();
+        ((NodeImpl) b1).removeSharedSet();
+        testRootNode.save();
+    }
+    
+    /**
+     * Invokes Node.removeSharedSet(), but saves only one of the parent nodes
+     * of the shared set. This doesn't need to be supported according to the
+     * specification (6.13.4).
+     */
+    public void testRemoveSharedSetSaveOneParentOnly() throws Exception {
+        // setup parent nodes and first child 
+        Node a1 = testRootNode.addNode("a1");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
+        testRootNode.save();
+        
+        // add mixin
+        b1.addMixin("mix:shareable");
+        b1.save();
+        
+        // clone
+        Workspace workspace = b1.getSession().getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(), 
+                a2.getPath() + "/b2", true);
 
-        NodeIterator iter = ((NodeImpl) b1).getSharedSet();
-        while (iter.hasNext()) {
-            list.add(iter.nextNode());
-        }
+        ((NodeImpl) b1).removeSharedSet();
         
-        assertEquals(list.size(), 2);
-        b1 = (Node) list.get(0);
-        Node b2 = (Node) list.get(1);
-        assertEquals(b1.getName(), "b1");
-        assertEquals(b2.getName(), "b2");
+        try {
+            a1.save();
+            fail("Removing a shared set requires saving all parents.");
+        } catch (ConstraintViolationException e) {
+            // expected 
+        }
     }
-    
+
     /**
-     * Verifies that Node.getPath returns the correct path in a shareable node.
+     * Verifies that shareable nodes in the same shared set have the same
+     * jcr:uuid (6.13.10).
      */
-    public void testGetPath() throws Exception {
+    public void testSameUUID() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
@@ -224,15 +305,15 @@
         assertEquals(list.size(), 2);
         b1 = (Node) list.get(0);
         Node b2 = (Node) list.get(1);
-        assertEquals(b1.getPath(), "/testroot/a1/b1");
-        assertEquals(b2.getPath(), "/testroot/a2/b2");
+        assertTrue(b1.getUUID().equals(b2.getUUID()));
     }
 
     /**
-     * Verifies that Node.isSame returns <code>true</code> for shareable nodes
-     * in the same shared set.
+     * Add a child to a shareable node and verify that another node in the
+     * same shared set has the same child and is modified when the first
+     * one is (6.13.11).
      */
-    public void testIsSame() throws Exception {
+    public void testAddChild() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
@@ -254,21 +335,22 @@
         while (iter.hasNext()) {
             list.add(iter.nextNode());
         }
-        
         assertEquals(list.size(), 2);
         b1 = (Node) list.get(0);
         Node b2 = (Node) list.get(1);
-        assertTrue(b1.isSame(b2));
-        assertTrue(b2.isSame(b1));
+        
+        b1.addNode("c");
+        assertTrue(b2.isModified());
+        assertTrue(b2.hasNode("c"));
+        b1.save();
     }
     
     /**
-     * Checks Node.removeShare().
+     * Verify that a share cycle is detected (6.13.13).
      */
-    public void testRemoveShare() throws Exception {
+    public void testShareCycle() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
-        Node a2 = testRootNode.addNode("a2");
         Node b1 = a1.addNode("b1");
         testRootNode.save();
         
@@ -276,11 +358,125 @@
         b1.addMixin("mix:shareable");
         b1.save();
         
+        // clone underneath b1: this must fail
+        Workspace workspace = b1.getSession().getWorkspace();
+        
+        try {
+            workspace.clone(workspace.getName(), b1.getPath(), 
+                    b1.getPath() + "/c", true);
+            fail("Cloning should create a share cycle.");
+        } catch (RepositoryException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verifies that observation events are sent only once (6.13.15).
+     */
+    public void testObservation() throws Exception {
+        // setup parent nodes and first child 
+        Node a1 = testRootNode.addNode("a1");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
+        testRootNode.save();
+        
+        // add mixin
+        b1.addMixin("mix:shareable");
+        b1.save();
+
         // clone
         Workspace workspace = b1.getSession().getWorkspace();
         workspace.clone(workspace.getName(), b1.getPath(), 
                 a2.getPath() + "/b2", true);
 
+        class EventCounter implements SynchronousEventListener {
+            
+            private int count;
+            
+            public void onEvent(EventIterator events) {
+                while (events.hasNext()) {
+                    events.nextEvent();
+                    count++;
+                }
+            }
+            
+            public int getEventCount() {
+                return count;
+            }
+            
+            public void resetCount() {
+                count = 0;
+            }
+        };
+        
+        EventCounter el = new EventCounter();
+        ObservationManager om = superuser.getWorkspace().getObservationManager(); 
+
+        om.addEventListener(el, Event.NODE_ADDED, testRootNode.getPath(), 
+                true, null, null, false);
+        b1.addNode("c");
+        b1.save();
+        superuser.getWorkspace().getObservationManager().removeEventListener(el);
+        assertEquals(el.getEventCount(), 1);
+        
+        el.resetCount();
+        om.addEventListener(el, Event.NODE_REMOVED, testRootNode.getPath(), 
+                true, null, null, false);
+        b1.getNode("c").remove();
+        b1.save();
+        superuser.getWorkspace().getObservationManager().removeEventListener(el);
+        assertEquals(el.getEventCount(), 1);
+
+        el.resetCount();
+        om.addEventListener(el, Event.PROPERTY_ADDED, testRootNode.getPath(), 
+                true, null, null, false);
+        b1.setProperty("c", "1");
+        b1.save();
+        superuser.getWorkspace().getObservationManager().removeEventListener(el);
+        assertEquals(el.getEventCount(), 1);
+
+        el.resetCount();
+        om.addEventListener(el, Event.PROPERTY_CHANGED, testRootNode.getPath(), 
+                true, null, null, false);
+        b1.setProperty("c", "2");
+        b1.save();
+        superuser.getWorkspace().getObservationManager().removeEventListener(el);
+        assertEquals(el.getEventCount(), 1);
+
+        el.resetCount();
+        om.addEventListener(el, Event.PROPERTY_REMOVED, testRootNode.getPath(), 
+                true, null, null, false);
+        b1.getProperty("c").remove();
+        b1.save();
+        superuser.getWorkspace().getObservationManager().removeEventListener(el);
+        assertEquals(el.getEventCount(), 1);
+    }
+    
+    /**
+     * Verifies that a lock applies to all nodes in a shared set (6.13.16).
+     */
+    public void testLock() throws Exception {
+        // setup parent nodes and first child 
+        Node a1 = testRootNode.addNode("a1");
+        a1.addMixin("mix:lockable");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
+        testRootNode.save();
+        
+        // add mixin
+        b1.addMixin("mix:shareable");
+        b1.addMixin("mix:lockable");
+        b1.save();
+
+        // add child c
+        Node c = b1.addNode("c");
+        b1.save();
+        
+        // clone
+        Workspace workspace = b1.getSession().getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(), 
+                a2.getPath() + "/b2", true);
+        
         ArrayList list = new ArrayList();
 
         NodeIterator iter = ((NodeImpl) b1).getSharedSet();
@@ -291,41 +487,53 @@
         assertEquals(list.size(), 2);
         b1 = (Node) list.get(0);
         Node b2 = (Node) list.get(1);
-        assertTrue(b1.isSame(b2));
-        assertTrue(b2.isSame(b1));
         
-        ((NodeImpl) b1).removeShare();
-        a1.save();
+        // lock shareable node -> all nodes in shared set are locked
+        b1.lock(false, true);
+        assertTrue(b2.isLocked());
+        b1.unlock();
+        
+        // deep-lock parent -> locks (common) child node
+        a1.lock(true, true);
+        assertTrue(c.isLocked());
+        a1.unlock();
     }
-
+    
     /**
-     * Checks Node.removeSharedSet().
+     * Clones a mix:shareable node to the same workspace (6.13.20). Verifies
+     * that cloning without mix:shareable fails.
      */
-    public void testRemoveSharedSet() throws Exception {
+    public void testClone() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
         Node b1 = a1.addNode("b1");
         testRootNode.save();
         
+        // clone (1st attempt, without mix:shareable)
+        Workspace workspace = b1.getSession().getWorkspace();
+        try {
+            workspace.clone(workspace.getName(), b1.getPath(), 
+                    a2.getPath() + "/b2", true);
+            fail("Cloning a node into the same workspace should fail.");
+        } catch (RepositoryException e) {
+            // expected
+        }
+        
         // add mixin
         b1.addMixin("mix:shareable");
         b1.save();
         
-        // clone
-        Workspace workspace = b1.getSession().getWorkspace();
+        // clone (2nd attempt, with mix:shareable)
         workspace.clone(workspace.getName(), b1.getPath(), 
                 a2.getPath() + "/b2", true);
-
-        ((NodeImpl) b1).removeSharedSet();
-        testRootNode.save();
     }
     
     /**
-     * Invokes Node.removeSharedSet(), but saves only of the parent nodes of
-     * the shared set. This is illegal according to the specification (6.13.4).
+     * Verifies that Node.isSame returns <code>true</code> for shareable nodes
+     * in the same shared set (6.13.21)
      */
-    public void testRemoveSharedSetSaveOneParentOnly() throws Exception {
+    public void testIsSame() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
@@ -341,20 +549,49 @@
         workspace.clone(workspace.getName(), b1.getPath(), 
                 a2.getPath() + "/b2", true);
 
-        ((NodeImpl) b1).removeSharedSet();
+        ArrayList list = new ArrayList();
+
+        NodeIterator iter = ((NodeImpl) b1).getSharedSet();
+        while (iter.hasNext()) {
+            list.add(iter.nextNode());
+        }
+        
+        assertEquals(list.size(), 2);
+        b1 = (Node) list.get(0);
+        Node b2 = (Node) list.get(1);
+        assertTrue(b1.isSame(b2));
+        assertTrue(b2.isSame(b1));
+    }
+    
+    /**
+     * Removes mix:shareable from a shareable node. This is unsupported in
+     * Jackrabbit (6.13.22).
+     */
+    public void testRemoveMixin() throws Exception {
+        // setup parent node and first child 
+        Node a = testRootNode.addNode("a");
+        Node b = a.addNode("b");
+        testRootNode.save();
+        
+        // add mixin
+        b.addMixin("mix:shareable");
+        b.save();
         
+        // remove mixin
         try {
-            a1.save();
-            fail("Removing a shared set requires saving all parents.");
-        } catch (ConstraintViolationException e) {
-            // expected 
+            b.removeMixin("mix:shareable");
+            b.save();
+            fail("Removing mix:shareable should fail.");
+        } catch (UnsupportedRepositoryOperationException e) {
+            // expected
         }
     }
 
     /**
-     * Checks Node.getSharedSet().
+     * Verifies that a descendant of a shareable node appears once in the
+     * result set (6.13.23)
      */
-    public void testIterateSharedSet() throws Exception {
+    public void testSearch() throws Exception {
         // setup parent nodes and first child 
         Node a1 = testRootNode.addNode("a1");
         Node a2 = testRootNode.addNode("a2");
@@ -364,19 +601,56 @@
         // add mixin
         b1.addMixin("mix:shareable");
         b1.save();
-        
+
         // clone
         Workspace workspace = b1.getSession().getWorkspace();
         workspace.clone(workspace.getName(), b1.getPath(), 
                 a2.getPath() + "/b2", true);
         
-        NodeIterator iter = ((NodeImpl) b1).getSharedSet();
-        int items = 0;
+        // add new referenceable child
+        Node c = b1.addNode("c");
+        c.addMixin(mixReferenceable);
+        b1.save();
+        
+        String sql = "SELECT * FROM nt:unstructured WHERE jcr:uuid = '"+c.getUUID()+"'";
+        QueryResult res = workspace.getQueryManager().createQuery(sql, Query.SQL).execute();
+
+        ArrayList list = new ArrayList();
+
+        NodeIterator iter = res.getNodes();
         while (iter.hasNext()) {
-            iter.nextNode();
-            items++;
+            list.add(iter.nextNode());
+        }
+        assertEquals(list.size(), 1);
+        assertTrue(((NodeImpl) list.get(0)).isSame(c));
+    }
+
+    //--------------------------------------------------------- limitation tests
+    
+    /**
+     * Clones a mix:shareable node to the same workspace, with the same
+     * parent. This is unsupported in Jackrabbit.
+     */
+    public void testCloneToSameParent() throws Exception {
+        // setup parent nodes and first child 
+        Node a = testRootNode.addNode("a");
+        Node b1 = a.addNode("b1");
+        testRootNode.save();
+        
+        // add mixin
+        b1.addMixin("mix:shareable");
+        b1.save();
+        
+        // clone
+        Workspace workspace = b1.getSession().getWorkspace();
+        
+        try {
+            workspace.clone(workspace.getName(), b1.getPath(), 
+                    a.getPath() + "/b2", true);
+            fail("Cloning inside same parent should fail.");
+        } catch (UnsupportedRepositoryOperationException e) {
+            // expected
         }
-        assertEquals(items, 2);
     }
 
     /**
@@ -426,30 +700,6 @@
             session.move(b.getPath(), a2.getPath() + "/b");
             session.save();
             fail("Moving a mix:shareable should fail.");
-        } catch (UnsupportedRepositoryOperationException e) {
-            // expected
-        }
-    }
-
-    /**
-     * Removes mix:shareable from a shareable node. This is unsupported in
-     * Jackrabbit.
-     */
-    public void testRemoveMixin() throws Exception {
-        // setup parent node and first child 
-        Node a = testRootNode.addNode("a");
-        Node b = a.addNode("b");
-        testRootNode.save();
-        
-        // add mixin
-        b.addMixin("mix:shareable");
-        b.save();
-        
-        // remove mixin
-        try {
-            b.removeMixin("mix:shareable");
-            b.save();
-            fail("Removing mix:shareable should fail.");
         } catch (UnsupportedRepositoryOperationException e) {
             // expected
         }