Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/ConcurrentAddMoveRemoveTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/ConcurrentAddMoveRemoveTest.java	(revision )
+++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/ConcurrentAddMoveRemoveTest.java	(revision )
@@ -0,0 +1,175 @@
+package org.apache.jackrabbit.core.integration.daily;
+
+import java.util.Random;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.core.AbstractConcurrencyTest;
+import org.apache.jackrabbit.core.TestHelper;
+import org.apache.jackrabbit.core.integration.random.operation.Operation;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyReport;
+import org.apache.jackrabbit.core.persistence.check.ReportItem;
+
+public class ConcurrentAddMoveRemoveTest extends AbstractConcurrencyTest {
+
+    private static final int RUN_NUM_SECONDS = 20;
+
+    private long end;
+
+    private String folder1Path;
+    private String folder2Path;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        end = System.currentTimeMillis() + RUN_NUM_SECONDS * 1000;
+        folder1Path = testRootNode.addNode("folder1").getPath();
+        folder2Path = testRootNode.addNode("folder2").getPath();
+        testRootNode.getSession().save();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        ConsistencyReport consistencyReport = TestHelper.checkConsistency(testRootNode.getSession(), false, null);
+        for (ReportItem item : consistencyReport.getItems()) {
+            System.out.println(item.getMessage());
+        }
+        assertTrue(consistencyReport.getItems().size() == 0);
+        super.tearDown();
+    }
+
+    public void testRandomOperations() throws RepositoryException {
+        runTask(new AddMoveRemoveTask(end, folder1Path, folder2Path), 5, testRootNode.getPath());
+    }
+
+    public static class AddMoveRemoveTask implements Task {
+
+        private final long end;
+        private final String folder1Path;
+        private final String folder2Path;
+
+        private final Random random = new Random();
+
+        public AddMoveRemoveTask(long end, String folder1Path, String folder2Path) {
+            this.end = end;
+            this.folder1Path = folder1Path;
+            this.folder2Path = folder2Path;
+        }
+
+        public void execute(final Session session, final Node test) {
+            while (end > System.currentTimeMillis()) {
+                try {
+                    getRandomOperation(session).execute();
+                } catch (Exception e) {
+                    try {
+                        session.refresh(false);
+                    } catch (RepositoryException e1) {
+                        System.err.println("Operation failed in failure");
+                    }
+                    String exception = e.getClass().getName() + ": " + e.getMessage();
+                    System.out.println(exception);
+                }
+            }
+        }
+
+        private Operation getRandomOperation(Session session) throws RepositoryException {
+            switch (random.nextInt(3)) {
+                case 0:
+                    return new Add(session, getRandomParent());
+                case 1: {
+                    String folderPath = getRandomParent();
+                    return new WorkspaceMove(session, getRandomChild(session, folderPath), folderPath.equals(folder1Path) ? folder2Path : folder1Path);
+                }
+                default: {
+                    String folderPath = getRandomParent();
+                    return new Remove(session, getRandomChild(session, folderPath));
+                }
+            }
+        }
+
+        private String getRandomChild(Session session, String parentPath) throws RepositoryException {
+            Node parent = session.getNode(parentPath);
+            NodeIterator nodes = parent.getNodes();
+            int size = (int)nodes.getSize();
+            if (size > 0) {
+                int i = 1;
+                int offset = random.nextInt(size);
+                while (nodes.hasNext()) {
+                    if (i == offset) {
+                        return nodes.nextNode().getPath();
+                    }
+                    nodes.nextNode();
+                    i++;
+                }
+            }
+            return null;
+        }
+
+        private String getRandomParent() {
+            switch (random.nextInt(2)) {
+                case 0: return folder1Path;
+                default: return folder2Path;
+            }
+        }
+
+        private class Add extends Operation {
+
+            private final String name;
+
+            public Add(Session s, String folderPath) {
+                super(s, folderPath);
+                this.name = getRandomText(4);
+            }
+
+            @Override
+            public NodeIterator execute() throws Exception {
+                getNode().addNode(name);
+//                System.err.println("Added " + node.getPath());
+                getSession().save();
+                return null;
+            }
+        }
+
+        private class Remove extends Operation {
+
+            public Remove(Session s, String path) {
+                super(s, path);
+            }
+
+            @Override
+            public NodeIterator execute() throws Exception {
+                if (getPath() != null) {
+                    getNode().remove();
+//                    System.err.println("Removed " + getPath());
+                    getSession().save();
+                }
+                return null;
+            }
+
+        }
+
+        private class WorkspaceMove extends Operation {
+
+            private final String folderPath;
+
+            public WorkspaceMove(Session s, String path, String folderPath) {
+                super(s, path);
+                this.folderPath = folderPath;
+            }
+
+            @Override
+            public NodeIterator execute() throws Exception {
+                if (getPath() != null) {
+                    String destination = folderPath + "/" + getRandomText(4);
+                    getSession().getWorkspace().move(getPath(), destination);
+//                    System.err.println("Moved " + getPath() + " to " + destination);
+                }
+                return null;
+            }
+
+        }
+    }
+
+}
