From 7f6484ef9fe7698bc235ee597354ac54c0cc29f1 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Mon, 31 Aug 2015 16:01:29 +0200 Subject: [PATCH] Bug 3868: Added support for bounding producers 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 --- .../mdsal/dom/broker/ShardedDOMDataTree.java | 31 ++- .../ShardedDOMDataTreeListenerContext.java | 5 +- .../broker/ShardedDOMDataTreeProducer.java | 11 ++ .../dom/broker/test/MockingUtilities.java | 29 +++ .../test/ShardedDOMDataTreeListenerTest.java | 7 +- ...edDOMDataTreeListenerWithProducerTest.java | 182 ++++++++++++++++++ ...dedDOMDataTreeProducerSingleShardTest.java | 34 +--- .../dom/broker/test/TestCommitCohort.java | 62 ++++++ 8 files changed, 320 insertions(+), 41 deletions(-) create mode 100644 dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/MockingUtilities.java create mode 100644 dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerWithProducerTest.java create mode 100644 dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/TestCommitCohort.java diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTree.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTree.java index df02cd07a3..06e7e84972 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTree.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTree.java @@ -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 ListenerRegistration registerListener(final T listener, final Collection subtrees, final boolean allowRxMerges, final Collection producers) { + public synchronized ListenerRegistration registerListener(final T listener, + final Collection subtrees, final boolean allowRxMerges, + final Collection producers) throws DOMDataTreeLoopException { Preconditions.checkNotNull(listener, "listener"); Preconditions.checkArgument(!subtrees.isEmpty(), "Subtrees must not be empty."); final ShardedDOMDataTreeListenerContext 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 listen, Set 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(); diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeListenerContext.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeListenerContext.java index 1ed95e9d34..0c0b337f26 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeListenerContext.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeListenerContext.java @@ -55,7 +55,6 @@ class ShardedDOMDataTreeListenerContext implement Collection changesToNotify = unreported; unreported = new ArrayList<>(); listener.onDataTreeChanged(changesToNotify, currentData); - } void register(DOMDataTreeIdentifier subtree, DOMStoreTreeChangePublisher shard) { @@ -112,4 +111,8 @@ class ShardedDOMDataTreeListenerContext implement reg.close(); } } + + DOMDataTreeListener getListener() { + return listener; + } } diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java index d11ea898de..c19f87af08 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java @@ -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 shardMap, final Set 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 index 0000000000..f106086d09 --- /dev/null +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/MockingUtilities.java @@ -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 mock(Class type, String toString) { + T mock = Mockito.mock(type); + Mockito.doReturn(toString).when(mock).toString(); + return mock; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static ArgumentCaptor captorFor(Class rawClass) { + return (ArgumentCaptor) ArgumentCaptor.forClass(rawClass); + } +} diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerTest.java index 9e7189a29a..391ad66847 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerTest.java @@ -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 storeListener = ArgumentCaptor.forClass(DOMDataTreeChangeListener.class); - treeService.registerListener(listener, SUBTREES_TEST, true, Collections.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 ArgumentCaptor captorFor(Class 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 index 0000000000..3a27f04894 --- /dev/null +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeListenerWithProducerTest.java @@ -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 SUBTREES_ROOT = Collections.singleton(ROOT_ID); + private static final Collection SUBTREES_TEST = Collections.singleton(TEST_ID); + private static final Collection 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 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 storeListener = + ArgumentCaptor.forClass(DOMDataTreeChangeListener.class); + treeService.registerListener(listener, SUBTREES_TEST, true, Collections.emptyList()); + verify(rootShard, times(1)).registerTreeChangeListener(eq(TEST_ID.getRootIdentifier()), + storeListener.capture()); + + DataTreeCandidate sentStoreCandidate = + DataTreeCandidates.fromNormalizedNode(TEST_ID.getRootIdentifier(), TEST_CONTAINER); + Collection changes = Collections.singleton(sentStoreCandidate); + + doNothing().when(listener).onDataTreeChanged(Mockito.>any(), Mockito.anyMap()); + storeListener.getValue().onDataTreeChanged(changes); + + ArgumentCaptor> candidateCapture = captorFor(Collection.class); + ArgumentCaptor>> mapCapture = captorFor(Map.class); + verify(listener, times(1)).onDataTreeChanged(candidateCapture.capture(), mapCapture.capture()); + + Collection receivedCandidate = candidateCapture.getValue(); + Map> 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)); + } + +} diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeProducerSingleShardTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeProducerSingleShardTest.java index 7f81e1d5fb..0c03511b17 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeProducerSingleShardTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/ShardedDOMDataTreeProducerSingleShardTest.java @@ -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 SUBTREES_ROOT = Collections.singleton(ROOT_ID); private static final Collection SUBTREES_TEST = Collections.singleton(TEST_ID); - private static final DOMStoreThreePhaseCommitCohort ALLWAYS_SUCCESS = new DOMStoreThreePhaseCommitCohort() { - - @Override - public ListenableFuture preCommit() { - return Futures.immediateFuture(null); - } - - @Override - public ListenableFuture commit() { - return Futures.immediateFuture(null); - } - - @Override - public ListenableFuture canCommit() { - return Futures.immediateFuture(Boolean.TRUE); - } - - @Override - public ListenableFuture 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 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 index 0000000000..f6e2f5cf6d --- /dev/null +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/test/TestCommitCohort.java @@ -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 canCommit; + private final ListenableFuture preCommit; + private final ListenableFuture commit; + private final ListenableFuture abort; + + @Override + public ListenableFuture canCommit() { + return canCommit; + } + + @Override + public ListenableFuture preCommit() { + return preCommit; + } + + @Override + public ListenableFuture abort() { + return abort; + } + + @Override + public ListenableFuture commit() { + return commit; + } + + private static ListenableFuture immediate(boolean isSuccess, Exception e) { + return isSuccess ? Futures.immediateFuture(null) : Futures.immediateFailedFuture(e); + } + + + +} -- 2.36.6