From: Jakub Toth Date: Fri, 14 Oct 2016 08:43:36 +0000 (+0200) Subject: Bug 6935 - RPC in latest draft doesn't work - problem of parsing X-Git-Tag: release/carbon~128 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=c639ecdb0e281f21ac6448f8542abf6e5f902bb5;p=netconf.git Bug 6935 - RPC in latest draft doesn't work - problem of parsing to instance identifier *added parsing of rpc identifier *test for rpc Change-Id: Icfb2108a9087e208f32a62702249662fe9865583 Signed-off-by: Jakub Toth --- diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/parser/builder/YangInstanceIdentifierDeserializer.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/parser/builder/YangInstanceIdentifierDeserializer.java index 89315be515..1328145127 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/parser/builder/YangInstanceIdentifierDeserializer.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/parser/builder/YangInstanceIdentifierDeserializer.java @@ -24,6 +24,7 @@ import org.opendaylight.restconf.utils.schema.context.RestconfSchemaUtil; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; @@ -34,6 +35,7 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; 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.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; @@ -75,7 +77,11 @@ public final class YangInstanceIdentifierDeserializer { if (allCharsConsumed(variables) || (currentChar(variables.getOffset(), variables.getData()) == RestconfConstants.SLASH)) { prepareIdentifier(qname, path, variables); - path.add(variables.getCurrent().getIdentifier()); + if (variables.getCurrent() == null) { + path.add(NodeIdentifier.create(qname)); + } else { + path.add(variables.getCurrent().getIdentifier()); + } } else if (currentChar(variables.getOffset(), variables.getData()) == ParserBuilderConstants.Deserializer.EQUAL) { if (nextContextNode(qname, path, variables).getDataSchemaNode() instanceof ListSchemaNode) { @@ -307,6 +313,9 @@ public final class YangInstanceIdentifierDeserializer { private static void prepareIdentifier(final QName qname, final List path, final MainVarsWrapper variables) { final DataSchemaContextNode currentNode = nextContextNode(qname, path, variables); + if (currentNode == null) { + return; + } checkValid(!currentNode.isKeyedEntry(), "Entry " + qname + " requires key or value predicate to be present", variables.getData(), variables.getOffset()); } @@ -315,6 +324,14 @@ public final class YangInstanceIdentifierDeserializer { final MainVarsWrapper variables) { variables.setCurrent(variables.getCurrent().getChild(qname)); DataSchemaContextNode current = variables.getCurrent(); + if (current == null) { + for (final RpcDefinition rpcDefinition : variables.getSchemaContext() + .findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision()).getRpcs()) { + if (rpcDefinition.getQName().getLocalName().equals(qname.getLocalName())) { + return null; + } + } + } checkValid(current != null, qname + " is not correct schema node identifier.", variables.getData(), variables.getOffset()); while (current.isMixin()) { @@ -405,14 +422,15 @@ public final class YangInstanceIdentifierDeserializer { private final SchemaContext schemaContext; private final String data; + private DataSchemaContextNode current; private int offset; public MainVarsWrapper(final String data, final DataSchemaContextNode current, final int offset, final SchemaContext schemaContext) { this.data = data; - this.setCurrent(current); - this.setOffset(offset); + this.current = current; + this.offset = offset; this.schemaContext = schemaContext; } diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/utils/parser/ParserIdentifier.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/utils/parser/ParserIdentifier.java index fc2703f98b..0ed61c60b6 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/utils/parser/ParserIdentifier.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/utils/parser/ParserIdentifier.java @@ -7,10 +7,6 @@ */ package org.opendaylight.restconf.utils.parser; -import com.google.common.base.Optional; -import com.google.common.base.Splitter; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; import java.text.ParseException; import java.util.Date; import java.util.Iterator; @@ -30,10 +26,15 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; 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.model.api.SchemaNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; /** * Util class for parsing identifier @@ -70,7 +71,7 @@ public final class ParserIdentifier { final String identifier, final SchemaContext schemaContext, final Optional mountPointService) { - if (identifier != null && identifier.contains(RestconfConstants.MOUNT)) { + if ((identifier != null) && identifier.contains(RestconfConstants.MOUNT)) { if (!mountPointService.isPresent()) { throw new RestconfDocumentedException("Mount point service is not available"); } @@ -93,16 +94,37 @@ public final class ParserIdentifier { final DataSchemaContextNode child = DataSchemaContextTree.from( mountPoint.get().getSchemaContext()).getChild(pathYangInstanceIdentifier); - - return new InstanceIdentifierContext( - pathYangInstanceIdentifier, child.getDataSchemaNode(), mountPoint.get(), + if (child != null) { + return new InstanceIdentifierContext(pathYangInstanceIdentifier, child.getDataSchemaNode(), + mountPoint.get(), mountPoint.get().getSchemaContext()); + } + final QName rpcQName = mountYangInstanceIdentifier.getLastPathArgument().getNodeType(); + RpcDefinition def = null; + for (final RpcDefinition rpcDefinition : schemaContext + .findModuleByNamespaceAndRevision(rpcQName.getNamespace(), rpcQName.getRevision()).getRpcs()) { + if (rpcDefinition.getQName().getLocalName().equals(rpcQName.getLocalName())) { + def = rpcDefinition; + break; + } + } + return new InstanceIdentifierContext(mountYangInstanceIdentifier, def, mountPoint.get(), mountPoint.get().getSchemaContext()); } else { final YangInstanceIdentifier deserialize = IdentifierCodec.deserialize(identifier, schemaContext); final DataSchemaContextNode child = DataSchemaContextTree.from(schemaContext).getChild(deserialize); - return new InstanceIdentifierContext( - deserialize, child.getDataSchemaNode(), null, schemaContext); + if(child != null){ + return new InstanceIdentifierContext(deserialize, child.getDataSchemaNode(), null, schemaContext); + } + final QName rpcQName = deserialize.getLastPathArgument().getNodeType(); + RpcDefinition def = null; + for (final RpcDefinition rpcDefinition : schemaContext.findModuleByNamespaceAndRevision(rpcQName.getNamespace(), rpcQName.getRevision()).getRpcs()) { + if (rpcDefinition.getQName().getLocalName().equals(rpcQName.getLocalName())) { + def = rpcDefinition; + break; + } + } + return new InstanceIdentifierContext(deserialize, def, null, schemaContext); } } diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImplTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImplTest.java index 5a57b15d63..4eb01e9397 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImplTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImplTest.java @@ -8,89 +8,77 @@ package org.opendaylight.restconf.restful.services.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.Iterator; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import javax.ws.rs.core.UriInfo; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils; import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext; import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext; import org.opendaylight.restconf.common.references.SchemaContextRef; +import org.opendaylight.restconf.handlers.RpcServiceHandler; import org.opendaylight.restconf.handlers.SchemaContextHandler; 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.LeafNode; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; public class RestconfInvokeOperationsServiceImplTest { - private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/streams"; + private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/invoke-rpc"; - @Test - public void testInvokeRpc() throws Exception { + private RestconfInvokeOperationsServiceImpl invokeOperationsService; + + @Mock + private RpcServiceHandler rpcServiceHandler; + + @Mock + private DOMRpcService rpcService; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); final SchemaContextRef contextRef = new SchemaContextRef(TestRestconfUtils.loadSchemaContext(PATH_FOR_NEW_SCHEMA_CONTEXT)); final SchemaContextHandler schemaContextHandler = new SchemaContextHandler(); schemaContextHandler.onGlobalContextUpdated(contextRef.get()); - final RestconfInvokeOperationsServiceImpl invokeOperationsService = new RestconfInvokeOperationsServiceImpl(null, schemaContextHandler); - - final QName qname = QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "toasterStatus"); - final QName qname1 = QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "toaster"); - final QName rpcQnameInput = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "input"); - final QName inputQname = QName.create(rpcQnameInput, "path"); - final YangInstanceIdentifier iid = YangInstanceIdentifier.builder() - .node(rpcQnameInput) - .build(); - final YangInstanceIdentifier iidAsLeafValue = YangInstanceIdentifier.builder() - .node(qname1) - .node(qname) - .build(); - - final LeafNode contentLeaf = Builders.leafBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(inputQname)) - .withValue(iidAsLeafValue) - .build(); - final ContainerNode input = Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(rpcQnameInput)) - .withChild(contentLeaf) - .build(); - final Iterator iterator = contextRef.get().getOperations().iterator(); - RpcDefinition rpcDef = null; - while (iterator.hasNext()) { - rpcDef = iterator.next(); - if ("create-data-change-event-subscription".equals(rpcDef.getQName().getLocalName())) { - break; - } - } + this.invokeOperationsService = + new RestconfInvokeOperationsServiceImpl(this.rpcServiceHandler, schemaContextHandler); + Mockito.when(this.rpcServiceHandler.get()).thenReturn(this.rpcService); + } - final InstanceIdentifierContext iidContext = new InstanceIdentifierContext<>(iid, rpcDef, null, contextRef.get()); - final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, input); - final NormalizedNodeContext context = invokeOperationsService.invokeRpc(null, payload, null); + @Test + public void testInvokeRpc() throws Exception { + final String identifier = "invoke-rpc-module:rpcTest"; + final NormalizedNode result = Mockito.mock(NormalizedNode.class); + final NormalizedNodeContext payload = prepNNC(result); + final UriInfo uriInfo = Mockito.mock(UriInfo.class); - final QName rpcQnameOutput = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "output"); - final QName outputQname = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "stream-name"); - final LeafNode contentLeaf2 = Builders.leafBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(outputQname)) - .withValue("toaster:toaster/toasterStatus/datastore=CONFIGURATION/scope=BASE") - .build(); - final ContainerNode output = Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(rpcQnameOutput)) - .withChild(contentLeaf2) - .build(); - final InstanceIdentifierContext iidContextResult = new InstanceIdentifierContext<>(null, rpcDef, null, contextRef.get()); - final NormalizedNodeContext payloadResult = new NormalizedNodeContext(iidContextResult, output); + final NormalizedNodeContext rpc = this.invokeOperationsService.invokeRpc(identifier, payload, uriInfo); + Assert.assertEquals(result, rpc.getData()); + } - assertNotNull(context); - assertEquals(payloadResult.getData(), context.getData()); - assertEquals(payloadResult.getInstanceIdentifierContext().getSchemaNode(), - context.getInstanceIdentifierContext().getSchemaNode()); - assertEquals(payloadResult.getInstanceIdentifierContext().getSchemaContext(), - context.getInstanceIdentifierContext().getSchemaContext()); - assertNull(context.getInstanceIdentifierContext().getMountPoint()); - assertNull(context.getInstanceIdentifierContext().getInstanceIdentifier()); + private NormalizedNodeContext prepNNC(final NormalizedNode result) { + final InstanceIdentifierContext context = Mockito.mock(InstanceIdentifierContext.class); + final RpcDefinition schemaNode = Mockito.mock(RpcDefinition.class); + final QName qname = QName.create("invoke:rpc:module", "2013-12-3", "rpcTest"); + final SchemaPath schemaPath = SchemaPath.create(true, qname); + Mockito.when(schemaNode.getPath()).thenReturn(schemaPath); + Mockito.when(schemaNode.getQName()).thenReturn(qname); + Mockito.when(context.getSchemaNode()).thenReturn(schemaNode); + final NormalizedNode data = Mockito.mock(NormalizedNode.class); + final DOMRpcResult domRpcResult = Mockito.mock(DOMRpcResult.class); + final CheckedFuture checkdFuture = Futures.immediateCheckedFuture(domRpcResult); + Mockito.when(this.rpcService.invokeRpc(schemaPath, data)).thenReturn(checkdFuture); + Mockito.when(domRpcResult.getResult()).thenReturn(result); + return new NormalizedNodeContext(context, data); } } diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfStreamsSubscriptionServiceImplTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfStreamsSubscriptionServiceImplTest.java index 2a5ba718d4..157fafc999 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfStreamsSubscriptionServiceImplTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfStreamsSubscriptionServiceImplTest.java @@ -73,7 +73,7 @@ public class RestconfStreamsSubscriptionServiceImplTest { } @Test - public void testSubscribueToStream() { + public void testSubscribeToStream() { final UriBuilder uriBuilder = UriBuilder.fromUri(uri); doReturn(uriBuilder).when(this.uriInfo).getAbsolutePathBuilder(); final RestconfStreamsSubscriptionServiceImpl streamsSubscriptionService =