Index: src/main/java/org/apache/jackrabbit/core/state/ChangeLog.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/ChangeLog.java (revision 788664) +++ src/main/java/org/apache/jackrabbit/core/state/ChangeLog.java (working copy) @@ -160,6 +160,18 @@ } /** + * Returns a flag indicating whether a given item state is marked as + * modified in this log. + * + * @param id the id of the item. + * @return true if the item state is marked as modified in this + * log; false otherwise. + */ + public boolean isModified(ItemId id) { + return modifiedStates.containsKey(id); + } + + /** * Return a node references object given its id. Returns * null if the node reference is not in the modified * section. Index: src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java (revision 788664) +++ src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java (working copy) @@ -411,9 +411,7 @@ cache.cache(local); } } - if (local != null) { - dispatcher.notifyStateCreated(created); - } + dispatcher.notifyStateCreated(created); } /** Index: src/main/java/org/apache/jackrabbit/core/state/NodeStateMerger.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/NodeStateMerger.java (revision 788664) +++ src/main/java/org/apache/jackrabbit/core/state/NodeStateMerger.java (working copy) @@ -102,7 +102,7 @@ for (ChildNodeEntry cne : state.getAddedChildNodeEntries()) { - if (context.isAdded(cne.getId())) { + if (context.isAdded(cne.getId()) || context.isModified(cne.getId())) { // a new child node entry has been added to this state; // check for name collisions with other state if (overlayedState.hasChildNodeEntry(cne.getName())) { @@ -117,13 +117,17 @@ } added.add(cne); + } else { + // externally added } } for (ChildNodeEntry cne : state.getRemovedChildNodeEntries()) { - if (context.isDeleted(cne.getId())) { + if (context.isDeleted(cne.getId()) || context.isModified(cne.getId())) { // a child node entry has been removed from this node state removed.add(cne); + } else { + // externally removed } } @@ -148,14 +152,6 @@ PropertyId propId = new PropertyId(state.getNodeId(), name); if (context.isAdded(propId)) { - // a new property name has been added to this state; - // check for name collisions - if (overlayedState.hasPropertyName(name) - || overlayedState.hasChildNodeEntry(name)) { - // conflicting names - return false; - } - added.add(name); } } @@ -195,6 +191,7 @@ static interface MergeContext { boolean isAdded(ItemId id); boolean isDeleted(ItemId id); + boolean isModified(ItemId id); boolean allowsSameNameSiblings(NodeId id); } } Index: src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java (revision 788664) +++ src/main/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java (working copy) @@ -787,9 +787,23 @@ // local state was created ItemState transientState = transientStore.get(created.getId()); if (transientState != null) { - // underlying state has been permanently created - transientState.pull(); - transientState.setStatus(ItemState.STATUS_EXISTING); + if (transientState.hasOverlayedState()) { + // underlying state has been permanently created + transientState.pull(); + transientState.setStatus(ItemState.STATUS_EXISTING); + } else { + // this is a notification from another session + try { + ItemState local = stateMgr.getItemState(created.getId()); + transientState.connect(local); + // update mod count + transientState.setModCount(local.getModCount()); + transientState.setStatus(ItemState.STATUS_EXISTING_MODIFIED); + } catch (ItemStateException e) { + // something went wrong, mark as stale + transientState.setStatus(ItemState.STATUS_STALE_MODIFIED); + } + } visibleState = transientState; } } @@ -823,6 +837,12 @@ return atticStore.contains(id); } + public boolean isModified(ItemId id) { + ItemState is = transientStore.get(id); + return is != null + && is.getStatus() == ItemState.STATUS_EXISTING_MODIFIED; + } + public boolean allowsSameNameSiblings(NodeId id) { NodeState ns; try { @@ -867,6 +887,13 @@ if (transientState != null) { transientState.setStatus(ItemState.STATUS_STALE_DESTROYED); visibleState = transientState; + } else { + // check attic + transientState = atticStore.get(destroyed.getId()); + if (transientState != null) { + atticStore.remove(destroyed.getId()); + transientState.onDisposed(); + } } } dispatcher.notifyStateDestroyed(visibleState); Index: src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (revision 788664) +++ src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (working copy) @@ -618,6 +618,10 @@ return local.deleted(id); } + public boolean isModified(ItemId id) { + return local.isModified(id); + } + public boolean allowsSameNameSiblings(NodeId id) { NodeState ns; try { Index: src/test/java/org/apache/jackrabbit/core/ConcurrentAddRemoveMoveTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentAddRemoveMoveTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentAddRemoveMoveTest.java (revision 0) @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.InvalidItemStateException; +import javax.jcr.Node; + +public final class ConcurrentAddRemoveMoveTest extends ConcurrentModificationBase { + + /** + * {@inheritDoc} + */ + public void setUp() throws Exception { + super.setUp(); + testRootNode.addNode("A").addNode("B"); + testRootNode.addNode("C"); + testRootNode.getSession().save(); + } + + public void testAddWithMoveFrom() throws Exception { + testRootNode.getNode("A").addNode("D"); + session.move(testRoot + "/A/B", testRoot + "/C/B"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testAddWithMoveTo() throws Exception { + testRootNode.getNode("A").addNode("D"); + session.move(testRoot + "/C", testRoot + "/A/C"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testRemoveWithMoveFrom() throws Exception { + Node d = testRootNode.getNode("A").addNode("D"); + superuser.save(); + d.remove(); + session.move(testRoot + "/A/B", testRoot + "/C/B"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testRemoveWithMoveTo() throws Exception { + Node d = testRootNode.getNode("A").addNode("D"); + superuser.save(); + d.remove(); + session.move(testRoot + "/C", testRoot + "/A/C"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testMoveFromWithAdd() throws Exception { + superuser.move(testRoot + "/A/B", testRoot + "/C/B"); + session.getNode(testRoot).getNode("A").addNode("D"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testMoveToWithAdd() throws Exception { + superuser.move(testRoot + "/C", testRoot + "/A/C"); + session.getNode(testRoot).getNode("A").addNode("D"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testMoveFromWithRemove() throws Exception { + Node d = session.getNode(testRoot).getNode("A").addNode("D"); + session.save(); + + superuser.move(testRoot + "/A/B", testRoot + "/C/B"); + d.remove(); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + public void testMoveToWithRemove() throws Exception { + Node d = session.getNode(testRoot).getNode("A").addNode("D"); + session.save(); + + superuser.move(testRoot + "/C", testRoot + "/A/C"); + d.remove(); + + testRootNode.getSession().save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + //-------------------------< concurrent add >------------------------------- + + public void testAddAdd() throws Exception { + testRootNode.getNode("A").addNode("D"); + session.getNode(testRoot).getNode("A").addNode("E"); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } + + //-------------------------< concurrent remove >---------------------------- + + public void testRemoveRemove() throws Exception { + Node d = testRootNode.getNode("A").addNode("D"); + superuser.save(); + d.remove(); + session.getNode(testRoot).getNode("A").getNode("B").remove(); + + superuser.save(); + + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw exception"); + } + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentAddRemoveMoveTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/ConcurrentAddRemovePropertyTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentAddRemovePropertyTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentAddRemovePropertyTest.java (revision 0) @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.Node; +import javax.jcr.InvalidItemStateException; + +/** + * ConcurrentAddRemovePropertyTest checks if concurrently adding + * and removing properties does not throw an InvalidItemStateException. + */ +public class ConcurrentAddRemovePropertyTest extends ConcurrentModificationBase { + + public void testAdd() throws Exception { + Node n = testRootNode.addNode(nodeName1); + superuser.save(); + n.setProperty(propertyName1, "foo"); + session.getNode(testRoot).getNode(nodeName1).setProperty(propertyName2, "bar"); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } + + public void testAddSameName() throws Exception { + Node n = testRootNode.addNode(nodeName1); + superuser.save(); + n.setProperty(propertyName1, "foo"); + session.getNode(testRoot).getNode(nodeName1).setProperty(propertyName1, "bar"); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + assertEquals("bar", n.getProperty(propertyName1).getString()); + } + + public void testRemove() throws Exception { + Node n = testRootNode.addNode(nodeName1); + n.setProperty(propertyName1, "foo"); + n.setProperty(propertyName2, "bar"); + superuser.save(); + n.getProperty(propertyName1).remove(); + session.getNode(testRoot).getNode(nodeName1).getProperty(propertyName2).remove(); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } + + public void testRemoveSameName() throws Exception { + Node n = testRootNode.addNode(nodeName1); + n.setProperty(propertyName1, "foo"); + superuser.save(); + n.getProperty(propertyName1).remove(); + session.getNode(testRoot).getNode(nodeName1).getProperty(propertyName1).remove(); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentAddRemovePropertyTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/ConcurrentMixinModificationTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentMixinModificationTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentMixinModificationTest.java (revision 0) @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.Node; +import javax.jcr.InvalidItemStateException; + +/** + * ConcurrentMixinModificationTest checks if concurrent + * modifications of mixins trigger an InvalidItemStateException. + */ +public class ConcurrentMixinModificationTest extends ConcurrentModificationBase { + + public void testMixin() throws Exception { + Node n = testRootNode.addNode(nodeName1); + superuser.save(); + n.addMixin(mixReferenceable); + session.getNode(testRoot).getNode(nodeName1).addMixin(mixLockable); + superuser.save(); + try { + session.save(); + fail("InvalidItemStateException expected"); + } catch (InvalidItemStateException e) { + // expected + } + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentMixinModificationTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/ConcurrentModificationBase.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentModificationBase.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentModificationBase.java (revision 0) @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.Session; + +import org.apache.jackrabbit.test.AbstractJCRTest; + +/** + * ConcurrentModificationBase is a base class for concurrent + * modification tests. + */ +public abstract class ConcurrentModificationBase extends AbstractJCRTest { + + protected Session session; + + protected void setUp() throws Exception { + super.setUp(); + session = helper.getSuperuserSession(); + } + + protected void tearDown() throws Exception { + if (session != null) { + session.logout(); + session = null; + } + super.tearDown(); + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentModificationBase.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/ConcurrentModificationWithSNSTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentModificationWithSNSTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentModificationWithSNSTest.java (revision 0) @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.InvalidItemStateException; +import javax.jcr.Node; + +/** + * ConcurrentModificationWithSNSTest checks if interleaving node + * modifications with same name siblings do not throw InvalidItemStateException. + */ +public class ConcurrentModificationWithSNSTest extends ConcurrentModificationBase { + + protected void setUp() throws Exception { + super.setUp(); + testRootNode.addNode("A"); + testRootNode.addNode("A"); + testRootNode.addNode("A"); + superuser.save(); + } + + public void testAddAdd() throws Exception { + testRootNode.addNode("A"); + session.getNode(testRoot).addNode("A"); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } + + public void testAddRemove() throws Exception { + testRootNode.addNode("A"); + session.getNode(testRoot).getNode("A[2]").remove(); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } + + public void testRemoveAdd() throws Exception { + testRootNode.getNode("A[2]").remove(); + session.getNode(testRoot).addNode("A"); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } + + public void testRemoveRemove() throws Exception { + testRootNode.getNode("A[1]").remove(); + session.getNode(testRoot).getNode("A[3]").remove(); + superuser.save(); + try { + session.save(); + } catch (InvalidItemStateException e) { + fail("must not throw InvalidItemStateException"); + } + } + + public void testSNSNotAllowed() throws Exception { + cleanUpTestRoot(superuser); + Node f = testRootNode.addNode("folder", "nt:folder"); + superuser.save(); + f.addNode("A", "nt:folder"); + session.getNode(f.getPath()).addNode("A", "nt:folder"); + superuser.save(); + try { + session.save(); + fail("InvalidItemStateException expected"); + } catch (InvalidItemStateException e) { + // expected + } + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentModificationWithSNSTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/ConcurrentMoveTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentMoveTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentMoveTest.java (revision 0) @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.InvalidItemStateException; + +/** + * ConcurrentMoveTest... + */ +public class ConcurrentMoveTest extends ConcurrentModificationBase { + + protected String srcAbsPath; + + protected String destAbsPath1; + + protected String destAbsPath2; + + protected void setUp() throws Exception { + super.setUp(); + srcAbsPath = testRootNode.addNode("A").getPath(); + destAbsPath1 = testRootNode.addNode("B").getPath() + "/D"; + destAbsPath2 = testRootNode.addNode("C").getPath() + "/D"; + superuser.save(); + } + + public void testMove() throws Exception { + superuser.move(srcAbsPath, destAbsPath1); + session.move(srcAbsPath, destAbsPath2); + superuser.save(); + try { + session.save(); + fail("InvalidItemStateException expected"); + } catch (InvalidItemStateException e) { + // expected + } + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentMoveTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/ConcurrentNodeModificationTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentNodeModificationTest.java (revision 788664) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentNodeModificationTest.java (working copy) @@ -120,11 +120,21 @@ state = "adding property to subnode " + i; n1.setProperty("testprop", "xxx"); if (i % 10 == 0) { - state = "saving pending subnodes"; + state = "saving pending (added) subnodes"; session.save(); } randomSleep(); } + + for (int i = 0; i < NUM_NODES; i++) { + state = "removing subnode " + i; + n.getNode("x" + identity + i).remove(); + if (i % 10 == 0) { + state = "saving pending (removed) subnodes"; + session.save(); + } + randomSleep(); + } session.save(); } catch (Exception e) { log.println("Exception while " + state + ": " + e.getMessage()); Index: src/test/java/org/apache/jackrabbit/core/ConcurrentReorderTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/ConcurrentReorderTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/ConcurrentReorderTest.java (revision 0) @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core; + +import javax.jcr.InvalidItemStateException; + +/** + * ConcurrentReorderTest checks if a reorder interleaved with + * a modification by another session throws an InvalidItemStateException. + */ +public class ConcurrentReorderTest extends ConcurrentModificationBase { + + protected void setUp() throws Exception { + super.setUp(); + testRootNode.addNode("A"); + testRootNode.addNode("B"); + testRootNode.addNode("C"); + superuser.save(); + } + + public void testReorderWithAdd() throws Exception { + testRootNode.orderBefore("C", "A"); + session.getNode(testRoot).addNode("D"); + session.save(); + try { + superuser.save(); + fail("must throw InvalidItemStateException"); + } catch (InvalidItemStateException e) { + // expected + } + } + + public void testAddWithReorder() throws Exception { + testRootNode.addNode("D"); + session.getNode(testRoot).orderBefore("C", "A"); + session.save(); + try { + superuser.save(); + fail("must throw InvalidItemStateException"); + } catch (InvalidItemStateException e) { + // expected + } + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\ConcurrentReorderTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/TestAll.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/TestAll.java (revision 788664) +++ src/test/java/org/apache/jackrabbit/core/TestAll.java (working copy) @@ -42,6 +42,14 @@ suite.addTestSuite(InvalidDateTest.class); suite.addTestSuite(SessionGarbageCollectedTest.class); + // test related to NodeStateMerger + suite.addTestSuite(ConcurrentAddRemoveMoveTest.class); + suite.addTestSuite(ConcurrentAddRemovePropertyTest.class); + suite.addTestSuite(ConcurrentMixinModificationTest.class); + suite.addTestSuite(ConcurrentModificationWithSNSTest.class); + suite.addTestSuite(ConcurrentMoveTest.class); + suite.addTestSuite(ConcurrentReorderTest.class); + return suite; } }