summaryrefslogtreecommitdiffstats
path: root/v3po/impl/src/test
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-04-12 10:13:02 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-04-12 10:13:02 +0200
commit5947a575539402344e450fd34b03f555b84523be (patch)
tree595ab3fc05ecc28d08b4b1d625e4e20980a33b6b /v3po/impl/src/test
parent9ac68bac54d95b0342cab52bf39a4321f1f42d79 (diff)
HONEYCOMB-9: Exception handling for VPP APIs
Change-Id: Ic71a2ac3d01e88cb38596a24a12a7bf8ebf54da5 Signed-off-by: Marek Gradzki <mgradzki@cisco.com> Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po/impl/src/test')
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java84
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java79
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java53
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java189
4 files changed, 357 insertions, 48 deletions
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java
index 963df735b..8719a5356 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java
@@ -44,8 +44,6 @@ import org.mockito.Mock;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
@@ -58,7 +56,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
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.data.api.schema.tree.DataValidationFailedException;
public class VPPConfigDataTreeTest {
@@ -89,7 +86,8 @@ public class VPPConfigDataTreeTest {
doReturn(node).when(snapshot).readNode(path);
final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot();
- final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future = vppDataTreeSnapshot.read(path);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
+ vppDataTreeSnapshot.read(path);
verify(dataTree).takeSnapshot();
verify(snapshot).readNode(path);
@@ -132,9 +130,9 @@ public class VPPConfigDataTreeTest {
// Verify all changes were processed:
verify(vppWriter).update(
- mapOf(dataBefore, Ethernet.class),
- mapOf(dataAfter, Ethernet.class),
- any(WriteContext.class));
+ mapOf(dataBefore, Ethernet.class),
+ mapOf(dataAfter, Ethernet.class),
+ any(WriteContext.class));
// Verify modification was validated
verify(dataTree).validate(modification);
@@ -142,7 +140,8 @@ public class VPPConfigDataTreeTest {
private Map<InstanceIdentifier<?>, DataObject> mapOf(final DataObject dataBefore, final Class<Ethernet> type) {
return eq(
- Collections.<InstanceIdentifier<?>, DataObject>singletonMap(InstanceIdentifier.create(type), dataBefore));
+ Collections.<InstanceIdentifier<?>, DataObject>singletonMap(InstanceIdentifier.create(type),
+ dataBefore));
}
private DataObject mockDataObject(final String name, final Class<? extends DataObject> classToMock) {
@@ -154,79 +153,77 @@ public class VPPConfigDataTreeTest {
@Test
public void testCommitUndoSuccessful() throws Exception {
// Prepare data changes:
- final DataObject dataBefore1 = mockDataObject("before", Ethernet.class);
- final DataObject dataAfter1 = mockDataObject("after", Ethernet.class);
-
- final DataObject dataBefore2 = mockDataObject("before", Vxlan.class);
- final DataObject dataAfter2 = mockDataObject("after", Vxlan.class);
+ final DataObject dataBefore = mockDataObject("before", Ethernet.class);
+ final DataObject dataAfter = mockDataObject("after", Ethernet.class);
- final DataObject dataBefore3 = mockDataObject("before", L2.class);
- final DataObject dataAfter3 = mockDataObject("after", L2.class);
+ final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class);
- // reject third applied change
- final WriterRegistry.Revert revert = mock(WriterRegistry.Revert.class);
- doThrow(new WriterRegistry.BulkUpdateException(InstanceIdentifier.create(L2.class), new RuntimeException(),
- revert)).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class));
+ // Fail on update:
+ final VppException failedOnUpdateException = new VppException("update failed");
+ doThrow(new WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter,
+ failedOnUpdateException)).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class));
// Prepare modification:
final DataTreeCandidateNode rootNode = mockRootNode();
// data before:
- final ContainerNode nodeBefore = mockContainerNode(dataBefore1, dataBefore2, dataBefore3);
+ final ContainerNode nodeBefore = mockContainerNode(dataBefore);
when(rootNode.getDataBefore()).thenReturn(Optional.<NormalizedNode<?, ?>>fromNullable(nodeBefore));
// data after:
- final ContainerNode nodeAfter = mockContainerNode(dataAfter1, dataAfter2, dataAfter3);
+ final ContainerNode nodeAfter = mockContainerNode(dataAfter);
when(rootNode.getDataAfter()).thenReturn(Optional.<NormalizedNode<?, ?>>fromNullable(nodeAfter));
// Run the test
try {
proxy.commit(modification);
- } catch (DataValidationFailedException | VppException e) {
+ } catch (WriterRegistry.BulkUpdateException e) {
verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class));
- verify(revert).revert();
+ verify(reverter).revert();
+ assertEquals(failedOnUpdateException, e.getCause());
return;
}
- fail("DataValidationFailedException was expected");
+ fail("WriterRegistry.BulkUpdateException was expected");
}
@Test
public void testCommitUndoFailed() throws Exception {
// Prepare data changes:
- final DataObject dataBefore1 = mockDataObject("before", Ethernet.class);
- final DataObject dataAfter1 = mockDataObject("after", Ethernet.class);
+ final DataObject dataBefore = mockDataObject("before", Ethernet.class);
+ final DataObject dataAfter = mockDataObject("after", Ethernet.class);
- final DataObject dataBefore2 = mockDataObject("before", Vxlan.class);
- final DataObject dataAfter2 = mockDataObject("after", Vxlan.class);
+ final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class);
- final DataObject dataBefore3 = mockDataObject("before", L2.class);
- final DataObject dataAfter3 = mockDataObject("after", L2.class);
+ // Fail on update:
+ doThrow(new WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter,
+ new VppException("update failed"))).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class));
- // reject third applied change
- final WriterRegistry.Revert revert = mock(WriterRegistry.Revert.class);
- doThrow(new RuntimeException("revert failed")).when(revert).revert();
- doThrow(new WriterRegistry.BulkUpdateException(InstanceIdentifier.create(L2.class), new RuntimeException(),
- revert)).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class));
+ // Fail on revert:
+ final VppException failedOnRevertException = new VppException("update failed");
+ final WriterRegistry.Reverter.RevertFailedException revertFailedException =
+ new WriterRegistry.Reverter.RevertFailedException(Collections.<InstanceIdentifier<?>>emptyList(),
+ failedOnRevertException);
+ doThrow(revertFailedException).when(reverter).revert();
// Prepare modification:
final DataTreeCandidateNode rootNode = mockRootNode();
// data before:
- final ContainerNode nodeBefore = mockContainerNode(dataBefore1, dataBefore2, dataBefore3);
+ final ContainerNode nodeBefore = mockContainerNode(dataBefore);
when(rootNode.getDataBefore()).thenReturn(Optional.<NormalizedNode<?, ?>>fromNullable(nodeBefore));
// data after:
- final ContainerNode nodeAfter = mockContainerNode(dataAfter1, dataAfter2, dataAfter3);
+ final ContainerNode nodeAfter = mockContainerNode(dataAfter);
when(rootNode.getDataAfter()).thenReturn(Optional.<NormalizedNode<?, ?>>fromNullable(nodeAfter));
// Run the test
try {
proxy.commit(modification);
- } catch (DataValidationFailedException | VppException e) {
- // FIXME the behavior with successful and failed revert is the same from outside world
+ } catch (WriterRegistry.Reverter.RevertFailedException e) {
verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class));
- verify(revert).revert();
+ verify(reverter).revert();
+ assertEquals(failedOnRevertException, e.getCause());
return;
}
- fail("DataValidationFailedException was expected");
+ fail("RevertFailedException was expected");
}
private DataTreeCandidateNode mockRootNode() {
@@ -256,9 +253,9 @@ public class VPPConfigDataTreeTest {
when(child.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class));
list.add(child);
- final Map.Entry entry = mock(Map.Entry.class);
+ final Map.Entry entry = mock(Map.Entry.class);
final Class<? extends DataObject> implementedInterface =
- (Class<? extends DataObject>) modification.getImplementedInterface();
+ (Class<? extends DataObject>) modification.getImplementedInterface();
final InstanceIdentifier<?> id = InstanceIdentifier.create(implementedInterface);
doReturn(id).when(entry).getKey();
@@ -267,5 +264,4 @@ public class VPPConfigDataTreeTest {
}
return node;
}
-
}
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
index f4b2faa3e..8939f8f52 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
@@ -16,16 +16,22 @@
package io.fd.honeycomb.v3po.impl.data;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.CheckedFuture;
import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
import java.util.Map;
@@ -34,10 +40,12 @@ import org.junit.Test;
import org.mockito.Mock;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
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.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
@@ -65,16 +73,16 @@ public class VppOperationalDataTreeTest {
public void setUp() {
initMocks(this);
operationalData = new VppOperationalDataTree(serializer, globalContext, reader);
+ doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class));
}
@Test
- public void testRead() throws Exception {
+ public void testReadNode() throws Exception {
final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class);
final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class);
doReturn(pArg).when(yangId).getLastPathArgument();
doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType();
- doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class));
doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId);
final DataObject dataObject = mock(DataObject.class);
@@ -91,6 +99,69 @@ public class VppOperationalDataTreeTest {
final Optional<NormalizedNode<?, ?>> result = future.get();
assertTrue(result.isPresent());
assertEquals(expectedValue, result.get());
+ }
+
+ @Test
+ public void testReadNonExistingNode() throws Exception {
+ final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class);
+ doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId);
+ doReturn(Optional.absent()).when(reader).read(id);
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future = operationalData.read(yangId);
+
+ verify(serializer).fromYangInstanceIdentifier(yangId);
+ verify(reader).read(id);
+ final Optional<NormalizedNode<?, ?>> result = future.get();
+ assertFalse(result.isPresent());
+ }
+
+ @Test
+ public void testReadFailed() throws Exception{
+ doThrow(io.fd.honeycomb.v3po.impl.trans.ReadFailedException.class).when(reader).readAll();
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
+ operationalData.read( YangInstanceIdentifier.EMPTY);
+
+ try {
+ future.checkedGet();
+ } catch (ReadFailedException e) {
+ assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.impl.trans.ReadFailedException);
+ return;
+ }
+ fail("ReadFailedException was expected");
+ }
+
+ @Test
+ public void testReadRootWithOneNonListElement() throws Exception {
+ // Prepare data
+ final InstanceIdentifier<VppState> vppStateII = InstanceIdentifier.create(VppState.class);
+ final VppState vppState = mock(VppState.class);
+ Multimap<InstanceIdentifier<?>, DataObject> dataObjects = LinkedListMultimap.create();
+ dataObjects.put(vppStateII, vppState);
+ doReturn(dataObjects).when(reader).readAll();
+
+ // Init serializer
+ final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(VppState.QNAME).build();
+ when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId);
+ when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry);
+ final DataContainerChild<?, ?> vppStateContainer = mock(DataContainerChild.class);
+ doReturn(vppStateContainer).when(entry).getValue();
+ doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier();
+
+ // Read root
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
+ operationalData.read(YangInstanceIdentifier.EMPTY);
+
+ verify(reader).readAll();
+ verify(serializer).toYangInstanceIdentifier(vppStateII);
+ verify(serializer).toNormalizedNode(vppStateII, vppState);
+
+ // Check the result is an ContainerNode with only one child
+ final Optional<NormalizedNode<?, ?>> result = future.get();
+ assertTrue(result.isPresent());
+ final ContainerNode rootNode = (ContainerNode) result.get();
+ assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType());
+ assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue()));
}
} \ No newline at end of file
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java
new file mode 100644
index 000000000..b815434a8
--- /dev/null
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed 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 io.fd.honeycomb.v3po.impl.trans;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class ReadFailedExceptionTest {
+
+ @Test
+ public void testInstantiation() {
+ final InstanceIdentifier<BridgeDomain> id = InstanceIdentifier.create(BridgeDomain.class);
+ ReadFailedException e = new ReadFailedException(id);
+ assertEquals(id, e.getFailedId());
+ assertNull(e.getCause());
+ assertTrue(e.getMessage().contains(id.toString()));
+ }
+
+ @Test
+ public void testInstantiationWithCause() {
+ final InstanceIdentifier<Interface> id = InstanceIdentifier.create(Interface.class);
+ final RuntimeException cause = new RuntimeException();
+ ReadFailedException e = new ReadFailedException(id, cause);
+ assertEquals(id, e.getFailedId());
+ assertEquals(cause, e.getCause());
+ assertTrue(e.getMessage().contains(id.toString()));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testInstantiationFailed() {
+ new ReadFailedException(null);
+ }
+} \ No newline at end of file
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java
new file mode 100644
index 000000000..26f63f40f
--- /dev/null
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed 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 io.fd.honeycomb.v3po.impl.trans.w.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import io.fd.honeycomb.v3po.impl.trans.VppException;
+import io.fd.honeycomb.v3po.impl.trans.w.VppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.WriteContext;
+import io.fd.honeycomb.v3po.impl.trans.w.WriterRegistry;
+import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class DelegatingWriterRegistryTest {
+
+ private final InstanceIdentifier<Vpp> vppId;
+ private final InstanceIdentifier<VppState> vppStateId;
+ private final InstanceIdentifier<Interfaces> interfaceId;
+
+ private WriteContext ctx;
+ private CompositeRootVppWriter<Vpp> vppWriter;
+ private CompositeRootVppWriter<VppState> vppStateWriter;
+ private CompositeRootVppWriter<Interfaces> interfacesWriter;
+
+ private DelegatingWriterRegistry registry;
+
+ public DelegatingWriterRegistryTest() {
+ vppId = InstanceIdentifier.create(Vpp.class);
+ vppStateId = InstanceIdentifier.create(VppState.class);
+ interfaceId = InstanceIdentifier.create(Interfaces.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <D extends DataObject> CompositeRootVppWriter<D> mockWriter(Class<D> clazz) {
+ final CompositeRootVppWriter<D> mock = (CompositeRootVppWriter<D>) Mockito.mock(CompositeRootVppWriter.class);
+ doReturn(InstanceIdentifier.create(clazz)).when(mock).getManagedDataObjectType();
+ return mock;
+ }
+
+ private DataObject mockDataObject(final String name, final Class<? extends DataObject> classToMock) {
+ final DataObject dataBefore = mock(classToMock, name);
+ doReturn(classToMock).when(dataBefore).getImplementedInterface();
+ return dataBefore;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map<InstanceIdentifier<?>, DataObject> asMap(DataObject... objects) {
+ final Map<InstanceIdentifier<?>, DataObject> map = new HashMap<>();
+ for (DataObject object : objects) {
+ final Class<? extends DataObject> implementedInterface =
+ (Class<? extends DataObject>) object.getImplementedInterface();
+ final InstanceIdentifier<?> id = InstanceIdentifier.create(implementedInterface);
+ map.put(id, object);
+ }
+ return map;
+ }
+
+ @Before
+ public void setUp() {
+ ctx = mock(WriteContext.class);
+ vppWriter = mockWriter(Vpp.class);
+ vppStateWriter = mockWriter(VppState.class);
+ interfacesWriter = mockWriter(Interfaces.class);
+
+ final List<VppWriter<? extends DataObject>> writers = new ArrayList<>();
+ writers.add(vppWriter);
+ writers.add(vppStateWriter);
+ writers.add(interfacesWriter);
+
+ registry = new DelegatingWriterRegistry(writers);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetManagedDataObjectType() {
+ registry.getManagedDataObjectType();
+ }
+
+ @Test
+ public void testBulkUpdateRevert() throws Exception {
+ // Prepare data changes:
+ final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class);
+ final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class);
+
+ final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class);
+ final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class);
+
+ // Fail on update
+ doThrow(new VppException("vpp failed")).when(vppStateWriter)
+ .update(vppStateId, dataBefore2, dataAfter2, ctx);
+
+ // Run the test
+ try {
+ registry.update(asMap(dataBefore1, dataBefore2), asMap(dataAfter1, dataAfter2), ctx);
+ } catch (WriterRegistry.BulkUpdateException e) {
+ // Check second update failed
+ assertEquals(vppStateId, e.getFailedId());
+ verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx);
+ verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx);
+
+ // Try to revert changes
+ e.revertChanges();
+
+ // Check revert was successful
+ verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx);
+ verify(vppStateWriter, never()).update(vppStateId, dataAfter2, dataBefore2, ctx);
+
+ return;
+ }
+ fail("BulkUpdateException expected");
+ }
+
+ @Test
+ public void testBulkUpdateRevertFail() throws Exception {
+ // Prepare data changes:
+ final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class);
+ final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class);
+
+ final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class);
+ final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class);
+
+ final DataObject dataBefore3 = mockDataObject("Interfaces before", Interfaces.class);
+ final DataObject dataAfter3 = mockDataObject("Interfaces after", Interfaces.class);
+
+ // Fail on the third update
+ doThrow(new VppException("vpp failed")).when(interfacesWriter)
+ .update(interfaceId, dataBefore3, dataAfter3, ctx);
+
+ // Fail on the second revert
+ doThrow(new VppException("vpp failed again")).when(vppWriter)
+ .update(vppId, dataAfter1, dataBefore1, ctx);
+
+ // Run the test
+ try {
+ registry.update(asMap(dataBefore1, dataBefore2, dataBefore3), asMap(dataAfter1, dataAfter2, dataAfter3), ctx);
+ } catch (WriterRegistry.BulkUpdateException e) {
+ // Check third update failed
+ assertEquals(interfaceId, e.getFailedId());
+ verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx);
+ verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx);
+ verify(interfacesWriter).update(interfaceId, dataBefore3, dataAfter3, ctx);
+
+ // Try to revert changes
+ try {
+ e.revertChanges();
+ } catch (WriterRegistry.Reverter.RevertFailedException e2) {
+ // Check second revert failed
+ assertEquals(Collections.singletonList(vppId), e2.getNotRevertedChanges());
+ verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx);
+ verify(vppStateWriter).update(vppStateId, dataAfter2, dataBefore2, ctx);
+ verify(interfacesWriter, never()).update(interfaceId, dataAfter3, dataBefore3, ctx);
+ return;
+ }
+ fail("WriterRegistry.Revert.RevertFailedException expected");
+ }
+ fail("BulkUpdateException expected");
+ }
+} \ No newline at end of file