Bug 6935 - RPC in latest draft doesn't work - problem of parsing 36/46936/16
authorJakub Toth <jatoth@cisco.com>
Fri, 14 Oct 2016 08:43:36 +0000 (10:43 +0200)
committerJakub Toth <jatoth@cisco.com>
Wed, 9 Nov 2016 11:50:40 +0000 (12:50 +0100)
to instance identifier

 *added parsing of rpc identifier
 *test for rpc

Change-Id: Icfb2108a9087e208f32a62702249662fe9865583
Signed-off-by: Jakub Toth <jatoth@cisco.com>
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/parser/builder/YangInstanceIdentifierDeserializer.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/utils/parser/ParserIdentifier.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfInvokeOperationsServiceImplTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/services/impl/RestconfStreamsSubscriptionServiceImplTest.java

index 89315be51594feae743a08ce1719fde50dac154d..13281451272e3410c467ccedf03d92189a80b119 100644 (file)
@@ -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<PathArgument> 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;
         }
 
index fc2703f98be3a9eb3a2a4496e2554f0a9e05919d..0ed61c60b602b8b130264f8bfc8bffca63e778d6 100644 (file)
@@ -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<DOMMountPointService> 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<SchemaNode>(
-                    pathYangInstanceIdentifier, child.getDataSchemaNode(), mountPoint.get(),
+            if (child != null) {
+                return new InstanceIdentifierContext<SchemaNode>(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<RpcDefinition>(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<SchemaNode>(
-                    deserialize, child.getDataSchemaNode(), null, schemaContext);
+            if(child != null){
+                return new InstanceIdentifierContext<SchemaNode>(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<RpcDefinition>(deserialize, def, null, schemaContext);
         }
     }
 
index 5a57b15d63796b38293bed2659c778ca704cd0c9..4eb01e9397c5fbd6fd4da3911727566d64582b8c 100644 (file)
@@ -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<RpcDefinition> 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<RpcDefinition> 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<RpcDefinition> 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<DOMRpcResult, DOMRpcException> checkdFuture = Futures.immediateCheckedFuture(domRpcResult);
+        Mockito.when(this.rpcService.invokeRpc(schemaPath, data)).thenReturn(checkdFuture);
+        Mockito.when(domRpcResult.getResult()).thenReturn(result);
+        return new NormalizedNodeContext(context, data);
     }
 
 }
index 2a5ba718d4d997c261e55aacf221436c0ff0f06e..157fafc9995fd3dd9e03ba8bcbef79407a105547 100644 (file)
@@ -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 =