Reproduce bug 4359 78/27678/4
authorMoiz Raja <moraja@cisco.com>
Wed, 30 Sep 2015 16:49:22 +0000 (09:49 -0700)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 8 Oct 2015 19:28:26 +0000 (19:28 +0000)
Added a couple of unit tests which demonstrates the problem
described in bug 4359 where upon recovery a node which
is previously deleted reappears on reapplying the
candidates

For some reason the problem is reproducible only when the
car is added and deleted twice and not once. I haven't
investigated why yet.

Change-Id: I5f5a656ef6fdc017a3342c8b409576a8b121b7f1
Signed-off-by: Moiz Raja <moraja@cisco.com>
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardDataTreeTest.java

index 81844fd554db7eeb1ddc0d77fe00efa33a78bae6..26787f63d6a79bc569823b4ac96d3a69b6710170 100644 (file)
@@ -11,6 +11,9 @@ package org.opendaylight.controller.cluster.datastore;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
@@ -18,6 +21,8 @@ import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
 import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -80,4 +85,109 @@ public class ShardDataTreeTest {
 
     }
 
+    @Test
+    public void bug4359AddRemoveCarOnce() throws ExecutionException, InterruptedException {
+        ShardDataTree shardDataTree = new ShardDataTree(fullSchema);
+
+        List<DataTreeCandidateTip> candidates = new ArrayList<>();
+        candidates.add(addCar(shardDataTree));
+        candidates.add(removeCar(shardDataTree));
+
+        NormalizedNode<?, ?> expected = getCars(shardDataTree);
+
+        applyCandidates(shardDataTree, candidates);
+
+        NormalizedNode<?, ?> actual = getCars(shardDataTree);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void bug4359AddRemoveCarTwice() throws ExecutionException, InterruptedException {
+        ShardDataTree shardDataTree = new ShardDataTree(fullSchema);
+
+        List<DataTreeCandidateTip> candidates = new ArrayList<>();
+        candidates.add(addCar(shardDataTree));
+        candidates.add(removeCar(shardDataTree));
+        candidates.add(addCar(shardDataTree));
+        candidates.add(removeCar(shardDataTree));
+
+        NormalizedNode<?, ?> expected = getCars(shardDataTree);
+
+        applyCandidates(shardDataTree, candidates);
+
+        NormalizedNode<?, ?> actual = getCars(shardDataTree);
+
+        assertEquals(expected, actual);
+    }
+
+    private NormalizedNode<?, ?> getCars(ShardDataTree shardDataTree) {
+        ReadOnlyShardDataTreeTransaction readOnlyShardDataTreeTransaction = shardDataTree.newReadOnlyTransaction("txn-2", null);
+        DataTreeSnapshot snapshot1 = readOnlyShardDataTreeTransaction.getSnapshot();
+
+        Optional<NormalizedNode<?, ?>> optional = snapshot1.readNode(CarsModel.BASE_PATH);
+
+        assertEquals(true, optional.isPresent());
+
+        System.out.println(optional.get());
+
+        return optional.get();
+    }
+
+    private DataTreeCandidateTip addCar(ShardDataTree shardDataTree) throws ExecutionException, InterruptedException {
+        return doTransaction(shardDataTree, new DataTreeOperation() {
+            @Override
+            public void execute(DataTreeModification snapshot) {
+                snapshot.merge(CarsModel.BASE_PATH, CarsModel.emptyContainer());
+                snapshot.merge(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode());
+                snapshot.write(CarsModel.newCarPath("altima"), CarsModel.newCarEntry("altima", new BigInteger("100")));
+            }
+        });
+    }
+
+    private DataTreeCandidateTip removeCar(ShardDataTree shardDataTree) throws ExecutionException, InterruptedException {
+        return doTransaction(shardDataTree, new DataTreeOperation() {
+            @Override
+            public void execute(DataTreeModification snapshot) {
+                snapshot.delete(CarsModel.newCarPath("altima"));
+            }
+        });
+    }
+
+    private abstract static class DataTreeOperation {
+        public abstract void execute(DataTreeModification snapshot);
+    }
+
+    private DataTreeCandidateTip doTransaction(ShardDataTree shardDataTree, DataTreeOperation operation)
+            throws ExecutionException, InterruptedException {
+        ReadWriteShardDataTreeTransaction transaction = shardDataTree.newReadWriteTransaction("txn-1", null);
+        DataTreeModification snapshot = transaction.getSnapshot();
+        operation.execute(snapshot);
+        ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction);
+
+        cohort.canCommit().get();
+        cohort.preCommit().get();
+        DataTreeCandidateTip candidate = cohort.getCandidate();
+        cohort.commit().get();
+
+        return candidate;
+    }
+
+    private DataTreeCandidateTip applyCandidates(ShardDataTree shardDataTree, List<DataTreeCandidateTip> candidates)
+            throws ExecutionException, InterruptedException {
+        ReadWriteShardDataTreeTransaction transaction = shardDataTree.newReadWriteTransaction("txn-1", null);
+        DataTreeModification snapshot = transaction.getSnapshot();
+        for(DataTreeCandidateTip candidateTip : candidates){
+            DataTreeCandidates.applyToModification(snapshot, candidateTip);
+        }
+        ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction);
+
+        cohort.canCommit().get();
+        cohort.preCommit().get();
+        DataTreeCandidateTip candidate = cohort.getCandidate();
+        cohort.commit().get();
+
+        return candidate;
+    }
+
 }
\ No newline at end of file