Bug 3868: Added support for bounding producers 36/26236/5
authorTony Tkacik <ttkacik@cisco.com>
Mon, 31 Aug 2015 14:01:29 +0000 (16:01 +0200)
committerRobert Varga <nite@hq.sk>
Tue, 15 Sep 2015 13:30:52 +0000 (13:30 +0000)
ShardedDOMDataTree and ShardedDOMDataTreeProducer are updated
to support bounding of producers to listeners.

- Added simple loop detection for listener to not directly
listen on subtrees it is bound to.y

Change-Id: I1328a01a9629d4c7e7cab36acaf6082ba4bacb3d
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTree.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeListenerContext.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/MockingUtilities.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerTest.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerWithProducerTest.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeProducerSingleShardTest.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/TestCommitCohort.java [new file with mode: 0644]

index df02cd07a30b11dc2fc62e3f0956423768ec7b5e..06e7e849722f658e8a445b9e566dccb0d99da01a 100644 (file)
@@ -13,11 +13,13 @@ import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.TreeMap;
 import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
@@ -180,13 +182,23 @@ public final class ShardedDOMDataTree implements DOMDataTreeService, DOMDataTree
     }
 
     @Override
-    public synchronized <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener, final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges, final Collection<DOMDataTreeProducer> producers) {
+    public synchronized <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener,
+            final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges,
+            final Collection<DOMDataTreeProducer> producers) throws DOMDataTreeLoopException {
         Preconditions.checkNotNull(listener, "listener");
         Preconditions.checkArgument(!subtrees.isEmpty(), "Subtrees must not be empty.");
         final ShardedDOMDataTreeListenerContext<T> listenerContext =
                 ShardedDOMDataTreeListenerContext.create(listener, subtrees, allowRxMerges);
         try {
             // FIXME: Add attachment of producers
+            for (DOMDataTreeProducer producer : producers) {
+                Preconditions.checkArgument(producer instanceof ShardedDOMDataTreeProducer);
+                ShardedDOMDataTreeProducer castedProducer = ((ShardedDOMDataTreeProducer) producer);
+                simpleLoopCheck(subtrees, castedProducer.getSubtrees());
+                // FIXME: We should also unbound listeners
+                castedProducer.boundToListener(listenerContext);
+            }
+
             for (DOMDataTreeIdentifier subtree : subtrees) {
                 DOMDataTreeShard shard = lookupShard(subtree).getRegistration().getInstance();
                 // FIXME: What should we do if listener is wildcard? And shards are on per
@@ -208,6 +220,23 @@ public final class ShardedDOMDataTree implements DOMDataTreeService, DOMDataTree
         };
     }
 
+    private static void simpleLoopCheck(Collection<DOMDataTreeIdentifier> listen, Set<DOMDataTreeIdentifier> writes)
+            throws DOMDataTreeLoopException {
+        for(DOMDataTreeIdentifier listenPath : listen) {
+            for (DOMDataTreeIdentifier writePath : writes) {
+                if (listenPath.contains(writePath)) {
+                    throw new DOMDataTreeLoopException(String.format(
+                            "Listener must not listen on parent (%s), and also writes child (%s)", listenPath,
+                            writePath));
+                } else if (writePath.contains(listenPath)) {
+                    throw new DOMDataTreeLoopException(
+                            String.format("Listener must not write parent (%s), and also listen on child (%s)",
+                                    writePath, listenPath));
+                }
+            }
+        }
+    }
+
     void removeListener(ShardedDOMDataTreeListenerContext<?> listener) {
         // FIXME: detach producers
         listener.close();
index 1ed95e9d34e36f619911476fa7660a25941b478d..0c0b337f26f047cd9141687dc8796699801ed3cf 100644 (file)
@@ -55,7 +55,6 @@ class ShardedDOMDataTreeListenerContext<T extends DOMDataTreeListener> implement
         Collection<DataTreeCandidate> changesToNotify = unreported;
         unreported = new ArrayList<>();
         listener.onDataTreeChanged(changesToNotify, currentData);
-
     }
 
     void register(DOMDataTreeIdentifier subtree, DOMStoreTreeChangePublisher shard) {
@@ -112,4 +111,8 @@ class ShardedDOMDataTreeListenerContext<T extends DOMDataTreeListener> implement
             reg.close();
         }
     }
+
+    DOMDataTreeListener getListener() {
+        return listener;
+    }
 }
index d11ea898dec1806595e79363c7fc5ff201c46869..c19f87af0802bdfe1656bca23d67eaec2e6d807c 100644 (file)
@@ -47,6 +47,9 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer {
     @GuardedBy("this")
     private boolean closed;
 
+    @GuardedBy("this")
+    private ShardedDOMDataTreeListenerContext<?> attachedListener;
+
     ShardedDOMDataTreeProducer(final ShardedDOMDataTree dataTree, final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap, final Set<DOMDataTreeShard> shards) {
         this.dataTree = Preconditions.checkNotNull(dataTree);
 
@@ -219,4 +222,12 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer {
         Preconditions.checkState(openTx.equals(transaction));
         openTx = null;
     }
+
+    synchronized void boundToListener(ShardedDOMDataTreeListenerContext<?> listener) {
+        // FIXME: Add option to dettach
+        Preconditions.checkState(this.attachedListener == null,
+                "Producer %s is already attached to other listener.",
+                listener.getListener());
+        this.attachedListener = listener;
+    }
 }
diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/MockingUtilities.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/MockingUtilities.java
new file mode 100644 (file)
index 0000000..f106086
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.broker.test;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+class MockingUtilities {
+
+    private MockingUtilities() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
+    public static <T> T mock(Class<T> type, String toString) {
+        T mock = Mockito.mock(type);
+        Mockito.doReturn(toString).when(mock).toString();
+        return mock;
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T, F extends T> ArgumentCaptor<F> captorFor(Class<T> rawClass) {
+        return (ArgumentCaptor) ArgumentCaptor.forClass(rawClass);
+    }
+}
index 9e7189a29a74a23b8a7502e391f8043ac430409a..391ad6684704e4d6d3d1dfd59377af35a1e46ce8 100644 (file)
@@ -16,6 +16,7 @@ import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.opendaylight.mdsal.dom.broker.test.MockingUtilities.captorFor;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -125,7 +126,6 @@ public class ShardedDOMDataTreeListenerTest {
     public void receiveChangeEvent() throws DOMDataTreeLoopException {
         ArgumentCaptor<DOMDataTreeChangeListener> storeListener =
                 ArgumentCaptor.forClass(DOMDataTreeChangeListener.class);
-
         treeService.registerListener(listener, SUBTREES_TEST, true, Collections.<DOMDataTreeProducer>emptyList());
         verify(rootShard, times(1)).registerTreeChangeListener(eq(TEST_ID.getRootIdentifier()),
                 storeListener.capture());
@@ -153,9 +153,4 @@ public class ShardedDOMDataTreeListenerTest {
         assertEquals(TEST_CONTAINER, receivedMap.get(TEST_ID));
     }
 
-    @SuppressWarnings("unchecked")
-    private static <T, F extends T> ArgumentCaptor<F> captorFor(Class<T> rawClass) {
-        return (ArgumentCaptor) ArgumentCaptor.forClass(rawClass);
-    }
-
 }
diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerWithProducerTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerWithProducerTest.java
new file mode 100644 (file)
index 0000000..3a27f04
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.broker.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.mdsal.dom.broker.test.MockingUtilities.captorFor;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeShardingConflictException;
+import org.opendaylight.mdsal.dom.broker.ShardedDOMDataTree;
+import org.opendaylight.mdsal.dom.broker.test.util.TestModel;
+import org.opendaylight.mdsal.dom.spi.store.DOMStore;
+import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
+import org.opendaylight.mdsal.dom.spi.store.DOMStoreTreeChangePublisher;
+import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+
+public class ShardedDOMDataTreeListenerWithProducerTest {
+
+
+    private static final DOMDataTreeIdentifier ROOT_ID = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
+            YangInstanceIdentifier.EMPTY);
+    private static final DOMDataTreeIdentifier TEST_ID = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
+            TestModel.TEST_PATH);
+
+    private static final DOMDataTreeIdentifier TEST2_ID = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
+            TestModel.TEST2_PATH);
+
+
+    private static final Collection<DOMDataTreeIdentifier> SUBTREES_ROOT = Collections.singleton(ROOT_ID);
+    private static final Collection<DOMDataTreeIdentifier> SUBTREES_TEST = Collections.singleton(TEST_ID);
+    private static final Collection<DOMDataTreeIdentifier> SUBTREES_TEST2 = Collections.singleton(TEST2_ID);
+    private static final ContainerNode TEST_CONTAINER = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+
+    private interface ListenableShard extends DOMDataTreeShard, DOMStoreTreeChangePublisher, DOMStore {
+
+
+    }
+
+    @Mock(name = "rootShard")
+    private ListenableShard rootShard;
+
+    @Mock(name = "childShard")
+    private ListenableShard childShard;
+
+    @Mock
+    private ListenerRegistration<?> storeListenerReg;
+
+    @Mock(name = "storeWriteTx")
+    private DOMStoreWriteTransaction writeTxMock;
+
+    @Mock(name = "storeTxChain")
+    private DOMStoreTransactionChain txChainMock;
+
+    private DOMDataTreeService treeService;
+
+    private ListenerRegistration<ListenableShard> shardReg;
+
+    @Before
+    public void setUp() throws DOMDataTreeShardingConflictException {
+        MockitoAnnotations.initMocks(this);
+        final ShardedDOMDataTree impl = new ShardedDOMDataTree();
+        treeService = impl;
+        shardReg = impl.registerDataTreeShard(ROOT_ID, rootShard);
+        doReturn("rootShard").when(rootShard).toString();
+        doReturn("childShard").when(childShard).toString();
+
+        doReturn(txChainMock).when(rootShard).createTransactionChain();
+        doReturn(writeTxMock).when(txChainMock).newWriteOnlyTransaction();
+        doReturn(TestCommitCohort.ALLWAYS_SUCCESS).when(writeTxMock).ready();
+
+        doReturn(storeListenerReg).when(rootShard).registerTreeChangeListener(any(YangInstanceIdentifier.class),
+                any(DOMDataTreeChangeListener.class));
+        doNothing().when(storeListenerReg).close();
+    }
+
+    @Test
+    public void registerListenerWithOneProducer() throws DOMDataTreeLoopException {
+        DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
+        DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST2);
+        treeService.registerListener(listener, SUBTREES_TEST, true, Collections.singleton(producer));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void registerListenerWithAlreadyBoundProducer() throws DOMDataTreeLoopException {
+        DOMDataTreeListener listener1 = MockingUtilities.mock(DOMDataTreeListener.class, "listener1");
+        DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST2);
+        treeService.registerListener(listener1, SUBTREES_TEST, true, Collections.singleton(producer));
+
+        DOMDataTreeListener listener2 = MockingUtilities.mock(DOMDataTreeListener.class, "listener2");
+        treeService.registerListener(listener2, SUBTREES_TEST, true, Collections.singleton(producer));
+    }
+
+    @Test(expected = DOMDataTreeLoopException.class)
+    public void loopSameSubtree() throws DOMDataTreeLoopException {
+        DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
+        DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST);
+        treeService.registerListener(listener, SUBTREES_TEST, true, Collections.singleton(producer));
+    }
+
+    @Test(expected = DOMDataTreeLoopException.class)
+    public void loopListenParentWritesChild() throws DOMDataTreeLoopException {
+        DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
+        DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST);
+        treeService.registerListener(listener, SUBTREES_ROOT, true, Collections.singleton(producer));
+    }
+
+    @Test(expected = DOMDataTreeLoopException.class)
+    public void loopListenChildWritesParent() throws DOMDataTreeLoopException {
+        DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
+        DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_ROOT);
+        treeService.registerListener(listener, SUBTREES_ROOT, true, Collections.singleton(producer));
+    }
+
+    @Test
+    public void receiveChangeEvent() throws DOMDataTreeLoopException {
+        DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
+        ArgumentCaptor<DOMDataTreeChangeListener> storeListener =
+                ArgumentCaptor.forClass(DOMDataTreeChangeListener.class);
+        treeService.registerListener(listener, SUBTREES_TEST, true, Collections.<DOMDataTreeProducer>emptyList());
+        verify(rootShard, times(1)).registerTreeChangeListener(eq(TEST_ID.getRootIdentifier()),
+                storeListener.capture());
+
+        DataTreeCandidate sentStoreCandidate =
+                DataTreeCandidates.fromNormalizedNode(TEST_ID.getRootIdentifier(), TEST_CONTAINER);
+        Collection<DataTreeCandidate> changes = Collections.singleton(sentStoreCandidate);
+
+        doNothing().when(listener).onDataTreeChanged(Mockito.<Collection<DataTreeCandidate>>any(), Mockito.anyMap());
+        storeListener.getValue().onDataTreeChanged(changes);
+
+        ArgumentCaptor<Collection<DataTreeCandidate>> candidateCapture = captorFor(Collection.class);
+        ArgumentCaptor<Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>>> mapCapture = captorFor(Map.class);
+        verify(listener, times(1)).onDataTreeChanged(candidateCapture.capture(), mapCapture.capture());
+
+        Collection<DataTreeCandidate> receivedCandidate = candidateCapture.getValue();
+        Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>> receivedMap = mapCapture.getValue();
+
+        assertNotNull("receivedCandidate", receivedCandidate);
+        assertNotNull("receivedMap", receivedMap);
+        assertFalse("candidate collection must not be empty", receivedCandidate.isEmpty());
+        assertEquals(1, receivedCandidate.size());
+        DataTreeCandidate firstItem = receivedCandidate.iterator().next();
+        assertEquals(TEST_ID.getRootIdentifier(), firstItem.getRootPath());
+        assertEquals(TEST_CONTAINER, receivedMap.get(TEST_ID));
+    }
+
+}
index 7f81e1d5fb6a2e60ff3c4e722a12135ee29ceba4..0c03511b1770d25b1e17a337a27d0537003f2b7f 100644 (file)
@@ -11,8 +11,6 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doReturn;
 
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collection;
 import java.util.Collections;
 import org.junit.Before;
@@ -31,7 +29,6 @@ import org.opendaylight.mdsal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.mdsal.dom.broker.ShardedDOMDataTree;
 import org.opendaylight.mdsal.dom.broker.test.util.TestModel;
 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
-import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -49,34 +46,10 @@ public class ShardedDOMDataTreeProducerSingleShardTest {
     private static final Collection<DOMDataTreeIdentifier> SUBTREES_ROOT = Collections.singleton(ROOT_ID);
     private static final Collection<DOMDataTreeIdentifier> SUBTREES_TEST = Collections.singleton(TEST_ID);
 
-    private static final DOMStoreThreePhaseCommitCohort ALLWAYS_SUCCESS = new DOMStoreThreePhaseCommitCohort() {
-
-        @Override
-        public ListenableFuture<Void> preCommit() {
-            return Futures.immediateFuture(null);
-        }
-
-        @Override
-        public ListenableFuture<Void> commit() {
-            return Futures.immediateFuture(null);
-        }
-
-        @Override
-        public ListenableFuture<Boolean> canCommit() {
-            return Futures.immediateFuture(Boolean.TRUE);
-        }
-
-        @Override
-        public ListenableFuture<Void> abort() {
-            return Futures.immediateFuture(null);
-        }
-    };
-
     interface MockTestShard extends DOMDataTreeShard, DOMStore {
 
     }
 
-
     @Mock(name = "rootShard")
     private MockTestShard rootShard;
 
@@ -87,15 +60,10 @@ public class ShardedDOMDataTreeProducerSingleShardTest {
     @Mock(name = "storeTxChain")
     private DOMStoreTransactionChain txChainMock;
 
-
-
     private DOMDataTreeService treeService;
     private ListenerRegistration<MockTestShard> shardReg;
     private DOMDataTreeProducer producer;
 
-
-
-
     @Before
     public void setUp() throws DOMDataTreeShardingConflictException {
         MockitoAnnotations.initMocks(this);
@@ -106,7 +74,7 @@ public class ShardedDOMDataTreeProducerSingleShardTest {
         doReturn("rootShard").when(rootShard).toString();
         doReturn(txChainMock).when(rootShard).createTransactionChain();
         doReturn(writeTxMock).when(txChainMock).newWriteOnlyTransaction();
-        doReturn(ALLWAYS_SUCCESS).when(writeTxMock).ready();
+        doReturn(TestCommitCohort.ALLWAYS_SUCCESS).when(writeTxMock).ready();
 
         producer = treeService.createProducer(SUBTREES_ROOT);
     }
diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/TestCommitCohort.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/TestCommitCohort.java
new file mode 100644 (file)
index 0000000..f6e2f5c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.broker.test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
+
+public enum TestCommitCohort implements DOMStoreThreePhaseCommitCohort {
+
+
+    ALLWAYS_SUCCESS(true, true, true, true), CAN_COMMIT_FAILED(false, false, false, true), PRE_COMMIT_FAILED(true,
+            false, false, true), COMMIT_FAILED(true, true, false, true);
+    ;
+
+
+
+    private TestCommitCohort(boolean canCommit, boolean preCommit, boolean commit, boolean abort) {
+        this.canCommit = Futures.immediateFuture(canCommit);
+        this.preCommit = immediate(canCommit, new IllegalStateException());
+        this.commit = immediate(commit, new IllegalStateException());
+        this.abort = immediate(abort, new IllegalStateException());
+    }
+
+
+    private final ListenableFuture<Boolean> canCommit;
+    private final ListenableFuture<Void> preCommit;
+    private final ListenableFuture<Void> commit;
+    private final ListenableFuture<Void> abort;
+
+    @Override
+    public ListenableFuture<Boolean> canCommit() {
+        return canCommit;
+    }
+
+    @Override
+    public ListenableFuture<Void> preCommit() {
+        return preCommit;
+    }
+
+    @Override
+    public ListenableFuture<Void> abort() {
+        return abort;
+    }
+
+    @Override
+    public ListenableFuture<Void> commit() {
+        return commit;
+    }
+
+    private static ListenableFuture<Void> immediate(boolean isSuccess, Exception e) {
+        return isSuccess ? Futures.<Void>immediateFuture(null) : Futures.<Void>immediateFailedFuture(e);
+    }
+
+
+
+}