summaryrefslogtreecommitdiffstats
path: root/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java')
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java344
1 files changed, 344 insertions, 0 deletions
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
new file mode 100644
index 0000000..19386a1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2013, 2015 Brocade Communication Systems, Inc., 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.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.ErrorTags;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class InvokeRpcMethodTest {
+
+ private static UriInfo uriInfo;
+ private static EffectiveModelContext schemaContext;
+
+ private final RestconfImpl restconfImpl;
+ private final ControllerContext controllerContext;
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+
+ public InvokeRpcMethodTest() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs", "/invoke-rpc");
+ final Collection<? extends Module> allModules = schemaContext.getModules();
+ assertNotNull(allModules);
+ final Module module = TestUtils.resolveModule("invoke-rpc-module", allModules);
+ assertNotNull(module);
+
+ uriInfo = mock(UriInfo.class);
+ final MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
+ map.put("prettyPrint", List.of("true"));
+ doReturn(map).when(uriInfo).getQueryParameters(any(Boolean.class));
+ }
+
+ /**
+ * Test method invokeRpc in RestconfImpl class tests if composite node as input parameter of method invokeRpc
+ * (second argument) is wrapped to parent composite node which has QName equals to QName of rpc (resolved from
+ * string - first argument).
+ */
+ @Test
+ public void invokeRpcMethodTest() {
+ controllerContext.findModuleNameByNamespace(XMLNamespace.of("invoke:rpc:module"));
+
+ final NormalizedNodeContext payload = prepareDomPayload();
+
+ final NormalizedNodeContext rpcResponse =
+ restconfImpl.invokeRpc("invoke-rpc-module:rpc-test", payload, uriInfo);
+ assertNotNull(rpcResponse);
+ assertNull(rpcResponse.getData());
+
+ }
+
+ private NormalizedNodeContext prepareDomPayload() {
+ final EffectiveModelContext schema = controllerContext.getGlobalSchema();
+ final Module rpcModule = schema.findModules("invoke-rpc-module").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "rpc-test");
+ RpcDefinition rpcSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcSchemaNode = rpc;
+ break;
+ }
+ }
+ assertNotNull(rpcSchemaNode);
+ final InputSchemaNode rpcInputSchemaNode = rpcSchemaNode.getInput();
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> container =
+ SchemaAwareBuilders.containerBuilder(rpcInputSchemaNode);
+
+ final QName contQName = QName.create(rpcModule.getQNameModule(), "cont");
+ final DataSchemaNode contSchemaNode = rpcInputSchemaNode.getDataChildByName(contQName);
+ assertTrue(contSchemaNode instanceof ContainerSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contNode =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ final QName lfQName = QName.create(rpcModule.getQNameModule(), "lf");
+ final DataSchemaNode lfSchemaNode = ((ContainerSchemaNode) contSchemaNode).getDataChildByName(lfQName);
+ assertTrue(lfSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> lfNode =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) lfSchemaNode).withValue("any value").build();
+ contNode.withChild(lfNode);
+ container.withChild(contNode.build());
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofRpcInput(schema, rpcSchemaNode, null),
+ container.build());
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+
+ doReturn(immediateFailedFluentFuture(new DOMRpcImplementationNotAvailableException("testExeption")))
+ .when(brokerFacade).invokeRpc(eq(qname), any());
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED,
+ Optional.empty(), Optional.empty());
+ }
+
+ void verifyRestconfDocumentedException(final RestconfDocumentedException restDocumentedException, final int index,
+ final ErrorType expErrorType, final ErrorTag expErrorTag, final Optional<String> expErrorMsg,
+ final Optional<String> expAppTag) {
+
+ final List<RestconfError> errors = restDocumentedException.getErrors();
+ assertTrue("RestconfError not found at index " + index, errors.size() > index);
+
+ RestconfError actual = errors.get(index);
+
+ assertEquals("getErrorType", expErrorType, actual.getErrorType());
+ assertEquals("getErrorTag", expErrorTag, actual.getErrorTag());
+ assertNotNull("getErrorMessage is null", actual.getErrorMessage());
+
+ if (expErrorMsg.isPresent()) {
+ assertEquals("getErrorMessage", expErrorMsg.get(), actual.getErrorMessage());
+ }
+
+ if (expAppTag.isPresent()) {
+ assertEquals("getErrorAppTag", expAppTag.get(), actual.getErrorAppTag());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
+ final List<RpcError> rpcErrors = List.of(
+ RpcResultBuilder.newError(ErrorType.TRANSPORT, new ErrorTag("bogusTag"), "foo"),
+ RpcResultBuilder.newWarning(ErrorType.RPC, ErrorTag.IN_USE, "bar", "app-tag", null, null));
+
+ final DOMRpcResult result = new DefaultDOMRpcResult(rpcErrors);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(path), any());
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+
+ // We are performing pass-through here of error-tag, hence the tag remains as specified, but we want to make
+ // sure the HTTP status remains the same as
+ final ErrorTag bogus = new ErrorTag("bogusTag");
+ verifyRestconfDocumentedException(ex, 0, ErrorType.TRANSPORT, bogus, Optional.of("foo"), Optional.empty());
+ assertEquals(ErrorTags.statusOf(ErrorTag.OPERATION_FAILED), ErrorTags.statusOf(bogus));
+
+ verifyRestconfDocumentedException(ex, 1, ErrorType.RPC, ErrorTag.IN_USE, Optional.of("bar"),
+ Optional.of("app-tag"));
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayload_Success() {
+ final NormalizedNode resultObj = null;
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo);
+ assertNotNull(output);
+ assertEquals(null, output.getData());
+ // additional validation in the fact that the restconfImpl does not
+ // throw an exception.
+ }
+
+ @Test
+ public void testInvokeRpcWithEmptyOutput() {
+ final ContainerNode resultObj = mock(ContainerNode.class);
+ doReturn(Set.of()).when(resultObj).body();
+ doCallRealMethod().when(resultObj).isEmpty();
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ WebApplicationException exceptionToBeThrown = assertThrows(WebApplicationException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), exceptionToBeThrown.getResponse().getStatus());
+ }
+
+ @Test
+ public void testInvokeRpcMethodWithBadMethodName() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:bad-method", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT,
+ Optional.empty(), Optional.empty());
+ }
+
+ @Test
+ @Ignore
+ public void testInvokeRpcMethodWithInput() {
+ final DOMRpcResult expResult = mock(DOMRpcResult.class);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast");
+
+ final Module rpcModule = schemaContext.findModules("toaster").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "make-toast");
+
+ RpcDefinition rpcDef = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcDef = rpc;
+ break;
+ }
+ }
+
+ assertNotNull(rpcDef);
+
+ final NormalizedNodeContext payload = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofLocalRpcInput(schemaContext, rpcDef),
+ SchemaAwareBuilders.containerBuilder(rpcDef.getInput()).build());
+
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(path), any(NormalizedNode.class));
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:make-toast", payload, uriInfo);
+ assertNotNull(output);
+ assertEquals(null, output.getData());
+ // additional validation in the fact that the restconfImpl does not
+ // throw an exception.
+ }
+
+ @Test
+ public void testThrowExceptionWhenSlashInModuleName() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster/slash", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ Optional.empty(), Optional.empty());
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadWithOutput_Success() {
+ final SchemaContext schema = controllerContext.getGlobalSchema();
+ final Module rpcModule = schema.findModules("toaster").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "testOutput");
+ final QName rpcOutputQName = QName.create(rpcModule.getQNameModule(),"output");
+
+ RpcDefinition rpcDef = null;
+ ContainerLike rpcOutputSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcOutputSchemaNode = rpc.getOutput();
+ rpcDef = rpc;
+ break;
+ }
+ }
+ assertNotNull(rpcDef);
+ assertNotNull(rpcOutputSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder =
+ SchemaAwareBuilders.containerBuilder(rpcOutputSchemaNode);
+ final DataSchemaNode leafSchema = rpcOutputSchemaNode
+ .getDataChildByName(QName.create(rpcModule.getQNameModule(), "textOut"));
+ assertTrue(leafSchema instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) leafSchema);
+ leafBuilder.withValue("brm");
+ containerBuilder.withChild(leafBuilder.build());
+ final ContainerNode container = containerBuilder.build();
+
+ final DOMRpcResult result = new DefaultDOMRpcResult(container);
+
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(rpcDef.getQName()), any());
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:testOutput", null, uriInfo);
+ assertNotNull(output);
+ assertNotNull(output.getData());
+ assertSame(container, output.getData());
+ assertNotNull(output.getInstanceIdentifierContext());
+ assertNotNull(output.getInstanceIdentifierContext().getSchemaContext());
+ }
+
+ /**
+ * Tests calling of RestConfImpl method invokeRpc. In the method there is searched rpc in remote schema context.
+ * This rpc is then executed.
+ * I wasn't able to simulate calling of rpc on remote device therefore this testing method raise method when rpc is
+ * invoked.
+ */
+ @Test
+ public void testMountedRpcCallNoPayload_Success() throws Exception {
+ // FIXME find how to use mockito for it
+ }
+}