Output-less RPCs should return 204 (new restconf) 21/81221/2
authorJaroslav Tóth <jtoth@frinx.io>
Wed, 27 Mar 2019 11:52:22 +0000 (12:52 +0100)
committerJaroslav Tóth <jtoth@frinx.io>
Wed, 27 Mar 2019 12:57:23 +0000 (12:57 +0000)
- RFC-8040 (4.4.2 - Invoke Operation Mode):
  "If the POST request succeeds, a "200 OK" status-line is returned
  if there is a response message-body, and a "204 No Content"
  status-line is returned if there is no response message-body."
  The example in RFC confirms on specific RPC without output (also
  in section 4.4.2).
- Restconf RFC 8040 RPC handler is modified so it is checked
  against empty data in output container. If there is no data child
  under otuput container, WebApplicationException with status code
  204 is thrown.

Change-Id: I3e9396db8096571719ad7947cb46f6196cc54532
JIRA: NETCONF-366
Signed-off-by: Jaroslav Tóth <jtoth@frinx.io>
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImpl.java
restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java

index deb3fd160fb7c421ecc95b91d92d50d50e2afa99..55c6be3d8dc0c735e6529f35228a87193caf7d79 100644 (file)
@@ -9,6 +9,8 @@ package org.opendaylight.restconf.nb.rfc8040.rests.services.impl;
 
 import java.net.URI;
 import javax.ws.rs.Path;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
@@ -24,6 +26,7 @@ import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfInvokeOpe
 import org.opendaylight.restconf.nb.rfc8040.rests.utils.CreateStreamUtil;
 import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfInvokeOperationsUtil;
 import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 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;
@@ -92,7 +95,12 @@ public class RestconfInvokeOperationsServiceImpl implements RestconfInvokeOperat
             resultData = result.getResult();
             resultNodeSchema = (RpcDefinition) payload.getInstanceIdentifierContext().getSchemaNode();
         }
-        return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, resultNodeSchema,
-                mountPoint, schemaContextRef.get()), resultData);
+
+        if (resultData != null && ((ContainerNode) resultData).getValue().isEmpty()) {
+            throw new WebApplicationException(Response.Status.NO_CONTENT);
+        } else {
+            return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, resultNodeSchema,
+                    mountPoint, schemaContextRef.get()), resultData);
+        }
     }
 }
index 1508efaab0a794a4f3c182d77990b343457dd6a1..31f6229957b3585cf4d123b3778ccd9a242e1183 100644 (file)
@@ -13,7 +13,11 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
 
+import java.util.Collections;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -32,6 +36,8 @@ import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
 import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
 import org.opendaylight.yangtools.yang.common.QName;
+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.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -69,9 +75,12 @@ public class RestconfInvokeOperationsServiceImplTest {
     }
 
     @Test
-    public void testInvokeRpc() throws Exception {
+    public void testInvokeRpcWithNonEmptyOutput() {
         final String identifier = "invoke-rpc-module:rpcTest";
-        final NormalizedNode<?, ?> result = mock(NormalizedNode.class);
+        final ContainerNode result = mock(ContainerNode.class);
+        final LeafNode outputChild = mock(LeafNode.class);
+        when(result.getValue()).thenReturn(Collections.singleton(outputChild));
+
         final NormalizedNodeContext payload = prepNNC(result);
         final UriInfo uriInfo = mock(UriInfo.class);
 
@@ -79,6 +88,25 @@ public class RestconfInvokeOperationsServiceImplTest {
         assertEquals(result, rpc.getData());
     }
 
+    @Test
+    public void testInvokeRpcWithEmptyOutput() {
+        final String identifier = "invoke-rpc-module:rpcTest";
+        final ContainerNode result = mock(ContainerNode.class);
+
+        final NormalizedNodeContext payload = prepNNC(result);
+        final UriInfo uriInfo = mock(UriInfo.class);
+
+        WebApplicationException exceptionToBeThrown = null;
+        try {
+            this.invokeOperationsService.invokeRpc(identifier, payload, uriInfo);
+        } catch (final WebApplicationException exception) {
+            exceptionToBeThrown = exception;
+
+        }
+        Assert.assertNotNull("WebApplicationException with status code 204 is expected.", exceptionToBeThrown);
+        Assert.assertEquals(Response.Status.NO_CONTENT.getStatusCode(), exceptionToBeThrown.getResponse().getStatus());
+    }
+
     private NormalizedNodeContext prepNNC(final NormalizedNode<?, ?> result) {
         final InstanceIdentifierContext<?> context = mock(InstanceIdentifierContext.class);
         final RpcDefinition schemaNode = mock(RpcDefinition.class);