Unit test for RestconfInvokeOperationsUtil class 27/47127/1
authorIvan Hrasko <ivan.hrasko@pantheon.tech>
Wed, 19 Oct 2016 13:15:42 +0000 (15:15 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Wed, 19 Oct 2016 13:15:42 +0000 (15:15 +0200)
Fixed so it add rpcError to the result when there is one.

Change-Id: I5e3e924a0e80970f2f754e2ec39d58e4b0a06984
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfInvokeOperationsUtil.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/RestconfInvokeOperationsUtilTest.java [new file with mode: 0644]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/TestData.java [new file with mode: 0644]

index a4dbe6fa23d420012a563578d66953801abf06df..01760376b95ba9c037685f3a99deb34f78044568 100644 (file)
@@ -10,9 +10,15 @@ package org.opendaylight.restconf.restful.utils;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,7 +52,7 @@ final class FutureCallbackTx {
             @Override
             public void onFailure(final Throwable t) {
                 responseWaiter.countDown();
-                handlingLoggerAndValues(t, txType, null, null);
+                handlingLoggerAndValues(t, txType, null, dataFactory);
             }
 
             @Override
@@ -85,7 +91,13 @@ final class FutureCallbackTx {
             final T result, final FutureDataFactory<T> dataFactory) {
         if (t != null) {
             LOG.warn("Transaction({}) FAILED!", txType, t);
-            throw new RestconfDocumentedException("  Transaction(" + txType + ") not committed correctly", t);
+            if (t instanceof DOMRpcException) {
+                final List<RpcError> rpcErrorList = new ArrayList<>();
+                rpcErrorList.add(RpcResultBuilder.newError(RpcError.ErrorType.RPC, "operation-failed", t.getMessage()));
+                dataFactory.setResult((T) new DefaultDOMRpcResult(rpcErrorList));
+            } else {
+                throw new RestconfDocumentedException("  Transaction(" + txType + ") not committed correctly", t);
+            }
         } else {
             LOG.trace("Transaction({}) SUCCESSFUL!", txType);
             dataFactory.setResult(result);
index 39f5890043518634f9ee32edb28f922dd4bfbf2d..023e70dd53458af384810bccca7732500875cc53 100644 (file)
@@ -94,7 +94,7 @@ public class RestconfInvokeOperationsUtil {
             return null;
         }
         try {
-            if ((response.getErrors() == null) || response.getErrors().isEmpty()) {
+            if (response.getErrors().isEmpty()) {
                 return response;
             }
             LOG.debug("RpcError message", response.getErrors());
diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/RestconfInvokeOperationsUtilTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/RestconfInvokeOperationsUtilTest.java
new file mode 100644 (file)
index 0000000..7935895
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 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.restconf.restful.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.doReturn;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import java.util.Collection;
+import java.util.Collections;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.restconf.handlers.RpcServiceHandler;
+import org.opendaylight.yangtools.yang.common.RpcError;
+
+public class RestconfInvokeOperationsUtilTest {
+
+    private static final TestData data = new TestData();
+
+    private RpcServiceHandler serviceHandler;
+    @Mock
+    private DOMRpcService rpcService;
+    @Mock
+    private DOMMountPoint moutPoint;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        serviceHandler = new RpcServiceHandler(rpcService);
+    }
+
+    @Test
+    public void invokeRpcTest() {
+        final DOMRpcResult mockResult = new DefaultDOMRpcResult(data.output, Collections.emptyList());
+        doReturn(Futures.immediateCheckedFuture(mockResult)).when(rpcService).invokeRpc(data.rpc, data.input);
+        final DOMRpcResult rpcResult = RestconfInvokeOperationsUtil.invokeRpc(data.input, data.rpc, serviceHandler);
+        Assert.assertTrue(rpcResult.getErrors().isEmpty());
+        assertEquals(data.output, rpcResult.getResult());
+    }
+
+    @Test(expected = RestconfDocumentedException.class)
+    public void invokeRpcErrorsAndCheckTestTest() {
+        final DOMRpcException exception = new DOMRpcImplementationNotAvailableException("No implementation of RPC " + data.errorRpc.toString() + " availible");
+        doReturn(Futures.immediateFailedCheckedFuture(exception)).when(rpcService).invokeRpc(data.errorRpc, data.input);
+        final DOMRpcResult rpcResult = RestconfInvokeOperationsUtil.invokeRpc(data.input, data.errorRpc, serviceHandler);
+        assertNull(rpcResult.getResult());
+        final Collection<RpcError> errorList = rpcResult.getErrors();
+        assertEquals(1, errorList.size());
+        final RpcError actual = errorList.iterator().next();
+        assertEquals("No implementation of RPC " + data.errorRpc.toString() + " availible", actual.getMessage());
+        assertEquals("operation-failed", actual.getTag());
+        assertEquals(RpcError.ErrorType.RPC, actual.getErrorType());
+        RestconfInvokeOperationsUtil.checkResponse(rpcResult);
+    }
+
+    @Test
+    public void invokeRpcViaMountPointTest() {
+        doReturn(Optional.fromNullable(rpcService)).when(moutPoint).getService(DOMRpcService.class);
+        final DOMRpcResult mockResult = new DefaultDOMRpcResult(data.output, Collections.emptyList());
+        doReturn(Futures.immediateCheckedFuture(mockResult)).when(rpcService).invokeRpc(data.rpc, data.input);
+        final DOMRpcResult rpcResult = RestconfInvokeOperationsUtil.invokeRpcViaMountPoint(moutPoint, data.input, data.rpc);
+        Assert.assertTrue(rpcResult.getErrors().isEmpty());
+        assertEquals(data.output, rpcResult.getResult());
+    }
+
+    @Test(expected = RestconfDocumentedException.class)
+    public void invokeRpcMissingMountPointServiceTest() {
+        doReturn(Optional.absent()).when(moutPoint).getService(DOMRpcService.class);
+        final DOMRpcResult mockResult = new DefaultDOMRpcResult(data.output, Collections.emptyList());
+        doReturn(Futures.immediateCheckedFuture(mockResult)).when(rpcService).invokeRpc(data.rpc, data.input);
+        final DOMRpcResult rpcResult = RestconfInvokeOperationsUtil.invokeRpcViaMountPoint(moutPoint, data.input, data.rpc);
+    }
+
+    @Test
+    public void checkResponseTest() {
+        final DOMRpcResult mockResult = new DefaultDOMRpcResult(data.output, Collections.emptyList());
+        doReturn(Futures.immediateCheckedFuture(mockResult)).when(rpcService).invokeRpc(data.rpc, data.input);
+        final DOMRpcResult rpcResult = RestconfInvokeOperationsUtil.invokeRpc(data.input, data.rpc, serviceHandler);
+        Assert.assertTrue(rpcResult.getErrors().isEmpty());
+        assertEquals(data.output, rpcResult.getResult());
+        assertNotNull(RestconfInvokeOperationsUtil.checkResponse(rpcResult));
+    }
+
+}
diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/TestData.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/TestData.java
new file mode 100644 (file)
index 0000000..265acea
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016 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.restconf.restful.utils;
+
+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.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+class TestData {
+
+    final YangInstanceIdentifier path;
+    final YangInstanceIdentifier path2;
+    final YangInstanceIdentifier path3;
+    final MapEntryNode data;
+    final MapEntryNode data2;
+    final ContainerNode data3;
+    final ContainerNode data4;
+    final MapNode listData;
+    final MapNode listData2;
+    final UnkeyedListEntryNode unkeyedListEntryNode;
+    final LeafNode contentLeaf;
+    final LeafNode contentLeaf2;
+    final MapEntryNode checkData;
+    final SchemaPath rpc;
+    final SchemaPath errorRpc;
+    final ContainerNode input;
+    final ContainerNode output;
+
+    TestData() {
+        final QName base = QName.create("ns", "2016-02-28", "base");
+        final QName listQname = QName.create(base, "list");
+        final QName listKeyQName = QName.create(base, "list-key");
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeWithKey =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(listQname, listKeyQName, "keyValue");
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeWithKey2 =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(listQname, listKeyQName, "keyValue2");
+        final LeafNode<Object> content = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "leaf-content")))
+                .withValue("content")
+                .build();
+        final LeafNode<Object> content2 = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "leaf-content-different")))
+                .withValue("content-different")
+                .build();
+        final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataContainer = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "identifier")))
+                .withValue("id")
+                .build();
+        unkeyedListEntryNode = Builders.unkeyedListEntryBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "list")))
+                .withChild(dataContainer)
+                .build();
+        data = Builders.mapEntryBuilder()
+                .withNodeIdentifier(nodeWithKey)
+                .withChild(content)
+                .build();
+        data2 = Builders.mapEntryBuilder()
+                .withNodeIdentifier(nodeWithKey)
+                .withChild(content2)
+                .build();
+        checkData = Builders.mapEntryBuilder()
+                .withNodeIdentifier(nodeWithKey)
+                .withChild(content2)
+                .withChild(content)
+                .build();
+        listData = Builders.mapBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "list")))
+                .withChild(data)
+                .build();
+        listData2 = Builders.mapBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "list")))
+                .withChild(data)
+                .withChild(data2)
+                .build();
+        path = YangInstanceIdentifier.builder()
+                .node(QName.create(base, "cont"))
+                .node(listQname)
+                .node(nodeWithKey)
+                .build();
+        path2 = YangInstanceIdentifier.builder()
+                .node(QName.create(base, "cont"))
+                .node(listQname)
+                .node(nodeWithKey2)
+                .build();
+        path3 = YangInstanceIdentifier.builder()
+                .node(QName.create(base, "cont"))
+                .node(listQname)
+                .build();
+        contentLeaf = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "content")))
+                .withValue("test")
+                .build();
+        contentLeaf2 = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "content2")))
+                .withValue("test2")
+                .build();
+        data3 = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "container")))
+                .withChild(contentLeaf)
+                .build();
+        data4 = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "container2")))
+                .withChild(contentLeaf2)
+                .build();
+
+
+        final QName rpcQname = QName.create("ns", "2015-02-28", "test-rpc");
+        final QName errorRpcQname = QName.create(rpcQname, "error-rpc");
+        rpc = SchemaPath.create(true, rpcQname);
+        errorRpc = SchemaPath.create(true, errorRpcQname);
+        final LeafNode contentLeafNode = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(rpcQname, "content")))
+                .withValue("test")
+                .build();
+        input = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(rpcQname, "input")))
+                .withChild(contentLeafNode)
+                .build();
+        final LeafNode resultLeafNode = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(rpcQname, "content")))
+                .withValue("operation result")
+                .build();
+        output = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(rpcQname, "output")))
+                .withChild(resultLeafNode)
+                .build();
+    }
+}
\ No newline at end of file