Author: thomasm
Date: Wed Dec  4 15:26:50 2013
New Revision: 1547822

URL: http://svn.apache.org/r1547822
Log:
OAK-1260 Using multiple cluster nodes can corrupt the data (test cases)

Added:
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java?rev=1547822&r1=1547821&r2=1547822&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
 Wed Dec  4 15:26:50 2013
@@ -359,7 +359,7 @@ public final class MongoNodeStore
     }
 
     @Nonnull
-    DocumentStore getDocumentStore() {
+    public DocumentStore getDocumentStore() {
         return store;
     }
 

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java?rev=1547822&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
 Wed Dec  4 15:26:50 2013
@@ -0,0 +1,70 @@
+/*
+ * 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.oak.plugins.mongomk;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.jackrabbit.mk.blobs.MemoryBlobStore;
+import org.junit.Test;
+
+/**
+ * A set of simple cluster tests.
+ */
+public class ClusterTest2 {
+    
+    @Test
+    public void twoNodes() throws Exception {
+        MemoryDocumentStore ds = new MemoryDocumentStore();
+        MemoryBlobStore bs = new MemoryBlobStore();
+        MongoMK.Builder builder;
+        
+        builder = new MongoMK.Builder();
+        builder.setDocumentStore(ds).setBlobStore(bs);
+        MongoMK mk1 = builder.setClusterId(1).open();
+        builder = new MongoMK.Builder();
+        builder.setDocumentStore(ds).setBlobStore(bs);
+        MongoMK mk2 = builder.setClusterId(2).open();
+
+        mk1.commit("/", "+\"test\":{\"x\": 1}", null, null);
+        mk1.backgroundWrite();
+        
+        mk2.backgroundRead();
+        String b1 = mk2.branch(mk2.getHeadRevision());
+        mk2.commit("/", "-\"test\"", b1, null);
+        String b2 = mk2.branch(mk2.getHeadRevision());
+        String b2b = mk2.commit("/", "-\"test\"", b2, null);
+        mk2.merge(b2b, null);
+        mk2.backgroundWrite();
+        
+        mk1.backgroundRead();
+        mk1.commit("/", "+\"test\":{\"x\": 1}", null, null);
+        mk1.backgroundWrite();
+        
+        mk2.backgroundRead();
+
+        String n1 = mk1.getNodes("/test", mk1.getHeadRevision(), 0, 0, 10, 
null);
+        String n2 = mk2.getNodes("/test", mk2.getHeadRevision(), 0, 0, 10, 
null);
+
+        // mk1 now sees both changes
+        assertEquals("{\"x\":1,\":childNodeCount\":0}", n1);
+        assertEquals("{\"x\":1,\":childNodeCount\":0}", n2);
+
+        mk1.dispose();
+        mk2.dispose();
+    }
+
+}

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java?rev=1547822&r1=1547821&r2=1547822&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
 Wed Dec  4 15:26:50 2013
@@ -44,6 +44,15 @@ import org.junit.runners.Parameterized;
 @Ignore("This abstract base class does not have any tests")
 public abstract class AbstractRepositoryTest {
 
+    protected NodeStoreFixture fixture;
+    private NodeStore nodeStore;
+    private Repository repository;
+    private Session adminSession;
+
+    public AbstractRepositoryTest(NodeStoreFixture fixture) {
+        this.fixture = fixture;
+    }
+
     @Parameterized.Parameters
     public static Collection<Object[]> fixtures() {
         Object[][] fixtures = new Object[][] {
@@ -55,17 +64,8 @@ public abstract class AbstractRepository
         return Arrays.asList(fixtures);
     }
 
-    protected NodeStoreFixture fixture;
-    private NodeStore nodeStore = null;
-    private Repository repository = null;
-    private Session adminSession = null;
-
-    public AbstractRepositoryTest(NodeStoreFixture fixture) {
-        this.fixture = fixture;
-    }
-
     @After
-    public void logout() throws RepositoryException {
+    public void logout() {
         // release session field
         if (adminSession != null) {
             adminSession.logout();
@@ -78,7 +78,7 @@ public abstract class AbstractRepository
         }
     }
 
-    protected Repository getRepository() throws RepositoryException {
+    protected Repository getRepository() {
         if (repository == null) {
             nodeStore = fixture.createNodeStore();
             repository  = new Jcr(nodeStore).createRepository();

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java?rev=1547822&r1=1547821&r2=1547822&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
 Wed Dec  4 15:26:50 2013
@@ -25,10 +25,13 @@ import org.apache.jackrabbit.mk.core.Mic
 import org.apache.jackrabbit.oak.plugins.mongomk.MongoMK;
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.plugins.mongomk.MongoNodeStore;
+import org.apache.jackrabbit.oak.plugins.mongomk.util.MongoConnection;
 import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore;
 import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 
+import com.mongodb.DB;
+
 /**
  * NodeStore fixture for parametrized tests.
  */
@@ -50,6 +53,23 @@ public abstract class NodeStoreFixture {
         public NodeStore createNodeStore() {
             return new CloseableNodeStore(new MongoMK.Builder().open());
         }
+        
+        @Override
+        public NodeStore createNodeStore(int clusterNodeId) {
+            String host = "localhost";
+            int port = 27017;
+            String db = "oak";
+            MongoConnection connection;
+            try {
+                connection = new MongoConnection(host, port, db);
+                DB mongoDB = connection.getDB();
+                MongoMK mk = new MongoMK.Builder()
+                                .setMongoDB(mongoDB).open();
+                return new CloseableNodeStore(mk);
+            } catch (Exception e) {
+                return null;
+            }
+        }
 
         @Override
         public void dispose(NodeStore nodeStore) {
@@ -68,6 +88,22 @@ public abstract class NodeStoreFixture {
         public NodeStore createNodeStore() {
             return new MongoMK.Builder().getNodeStore();
         }
+        
+        @Override
+        public NodeStore createNodeStore(int clusterNodeId) {
+            String host = "localhost";
+            int port = 27017;
+            String db = "oak";
+            MongoConnection connection;
+            try {
+                connection = new MongoConnection(host, port, db);
+                DB mongoDB = connection.getDB();
+                return new MongoMK.Builder()
+                                .setMongoDB(mongoDB).getNodeStore();
+            } catch (Exception e) {
+                return null;
+            }
+        }
 
         @Override
         public void dispose(NodeStore nodeStore) {
@@ -90,6 +126,16 @@ public abstract class NodeStoreFixture {
 
     public abstract NodeStore createNodeStore();
 
+    /**
+     * Create a new cluster node that is attached to the same backend storage.
+     * 
+     * @param clusterNodeId the cluster node id
+     * @return the node store, or null if clustering is not supported
+     */
+    public NodeStore createNodeStore(int clusterNodeId) {
+        return null;
+    }
+
     public abstract void dispose(NodeStore nodeStore);
 
     private static class CloseableNodeStore

Added: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java?rev=1547822&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
 Wed Dec  4 15:26:50 2013
@@ -0,0 +1,120 @@
+/*
+ * 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.oak.jcr.cluster;
+
+import java.util.Iterator;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import junit.framework.Assert;
+
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.jcr.NodeStoreFixture;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * A base class for MongoMK cluster tests.
+ */
+public class AbstractClusterTest {
+
+    protected NodeStoreFixture fixture = NodeStoreFixture.MONGO_MK;
+    protected NodeStore ns1, ns2;
+    protected Repository r1, r2;
+    protected Session s1, s2;
+    
+    @After
+    public void logout() {
+        if (s1 != null) {
+            s1.logout();
+            s1 = null;
+        }
+        if (s2 != null) {
+            s2.logout();
+            s2 = null;
+        }
+        r1 = r2 = null;
+        if (ns1 != null) {
+            fixture.dispose(ns1);
+        }
+        if (ns2 != null) {
+            fixture.dispose(ns2);
+        }
+    }
+
+    @Before
+    public void login() throws RepositoryException {
+        ns1 = fixture.createNodeStore(1);
+        if (ns1 == null) {
+            return;
+        }
+        r1  = new Jcr(ns1).createRepository();
+        s1 = r1.login(new SimpleCredentials("admin", "admin".toCharArray()));
+        ns2 = fixture.createNodeStore(2);
+        r2  = new Jcr(ns2).createRepository();
+        s2 = r2.login(new SimpleCredentials("admin", "admin".toCharArray()));
+    }
+    
+    static Iterable<Integer> seconds(final int max) {
+        return new Iterable<Integer>() {
+
+            @Override
+            public Iterator<Integer> iterator() {
+                return new Iterator<Integer>() {
+                    
+                    long start = System.currentTimeMillis();
+                    int x;
+
+                    @Override
+                    public boolean hasNext() {
+                        long time = System.currentTimeMillis() - start;
+                        if (x > 0 && time >= (max * 1000)) {
+                            Assert.fail("Retry loop timed out after " + x + 
+                                    " repetitions and " + time + " 
milliseconds");
+                        }
+                        return true;
+                    }
+
+                    @Override
+                    public Integer next() {
+                        hasNext();
+                        if (x > 0) {
+                            try {
+                                Thread.sleep(10);
+                            } catch (InterruptedException e) {
+                                // ignore
+                            }
+                        }
+                        return x++;
+                    }
+                    
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                    
+                };
+            }
+            
+        };
+    }
+    
+}

Added: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java?rev=1547822&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
 Wed Dec  4 15:26:50 2013
@@ -0,0 +1,63 @@
+/*
+ * 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.oak.jcr.cluster;
+
+import org.junit.Test;
+
+/**
+ * A simple cluster test.
+ */
+public class SimpleTestIT extends AbstractClusterTest {
+    
+    @SuppressWarnings("unused")
+    @Test 
+    public void test() throws Exception {
+        if (s1 == null) {
+            return;
+        }
+        if (s1.getRootNode().hasNode("test")) {
+            s1.getRootNode().getNode("test").remove();
+        }
+        s1.getRootNode().addNode("test");
+        s1.save();
+        for (int x : seconds(5)) {
+            s2.refresh(false);
+            if (s2.getRootNode().hasNode("test")) {
+                break;
+            }
+        }
+        s2.getRootNode().getNode("test").remove();
+        s2.save();
+        for (int x : seconds(5)) {
+            s1.refresh(false);
+            if (!s1.getRootNode().hasNode("test")) {
+                break;
+            }
+        }
+        s1.getRootNode().addNode("test");
+        s1.save();
+        for (int x : seconds(5)) {
+            s2.refresh(false);
+            if (s2.getRootNode().hasNode("test")) {
+                break;
+            }
+        }
+        s2.getRootNode().getNode("test").remove();
+        s2.save();
+    }
+    
+}


Reply via email to