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>
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;
@Override
public void onFailure(final Throwable t) {
responseWaiter.countDown();
- handlingLoggerAndValues(t, txType, null, null);
+ handlingLoggerAndValues(t, txType, null, dataFactory);
}
@Override
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);
return null;
}
try {
- if ((response.getErrors() == null) || response.getErrors().isEmpty()) {
+ if (response.getErrors().isEmpty()) {
return response;
}
LOG.debug("RpcError message", response.getErrors());
--- /dev/null
+/*
+ * 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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