From df25a540e0985695d3d0f93c68a977a4de729329 Mon Sep 17 00:00:00 2001 From: Sanjana B Date: Mon, 10 Feb 2020 16:56:59 +0530 Subject: [PATCH] Do not attempt to parse empty RPC/action reply MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit An RPC or action can legally result in an empty reply, even if it has some optional content in its schema. Detect reply and do not attempt to parse it as YANG data. JIRA: NETCONF-568 JIRA: NETCONF-644 Change-Id: I1f0b5c349f418824b9b0b3e1f01f16824b1b8df4 Signed-off-by: Anna Bencurova Signed-off-by: Sanjana B Signed-off-by: Tibor Král --- .../mapping/NetconfMessageTransformer.java | 13 +++- .../NetconfMessageTransformerTest.java | 64 ++++++++++++++++++- .../schemas/rpcs-actions-outputs.yang | 30 +++++++++ 3 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 netconf/sal-netconf-connector/src/test/resources/schemas/rpcs-actions-outputs.yang diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index 0406b95db7..5974875ef7 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import javax.xml.stream.XMLStreamException; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; @@ -311,13 +312,19 @@ public class NetconfMessageTransformer implements MessageTransformer parseResult(final NetconfMessage message, final OperationDefinition operationDefinition) { + final Optional okResponseElement = XmlElement.fromDomDocument(message.getDocument()) + .getOnlyChildElementWithSameNamespaceOptionally("ok"); if (operationDefinition.getOutput().getChildNodes().isEmpty()) { - Preconditions.checkArgument(XmlElement.fromDomDocument( - message.getDocument()).getOnlyChildElementWithSameNamespaceOptionally("ok").isPresent(), + Preconditions.checkArgument(okResponseElement.isPresent(), "Unexpected content in response of rpc: %s, %s", operationDefinition.getQName(), message); return null; } else { - final Element element = message.getDocument().getDocumentElement(); + if (okResponseElement.isPresent()) { + LOG.debug("Received response for RPC with defined Output"); + return null; + } + + Element element = message.getDocument().getDocumentElement(); try { final NormalizedNodeResult resultHolder = new NormalizedNodeResult(); final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder); diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java index 74e106374b..0aae222188 100644 --- a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java @@ -102,6 +102,8 @@ public class NetconfMessageTransformerTest { private static final String URN_EXAMPLE_AUGMENTED_ACTION = "urn:example:augmented-action"; + private static final String URN_EXAMPLE_RPCS_ACTIONS_OUTPUTS = "urn:example:rpcs-actions-outputs"; + private static final QName SERVER_QNAME = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "server"); private static final QName RESET_QNAME = QName.create(SERVER_QNAME, "reset"); @@ -126,6 +128,19 @@ public class NetconfMessageTransformerTest { private static final SchemaPath DISABLE_INTERFACE_PATH = SchemaPath.create(true, DEVICE_QNAME, INTERFACE_QNAME, DISABLE_QNAME); + private static final QName CHECK_WITH_OUTPUT_QNAME = + QName.create(URN_EXAMPLE_RPCS_ACTIONS_OUTPUTS, "check-with-output"); + private static final SchemaPath CHECK_WITH_OUTPUT_INTERFACE_PATH = + SchemaPath.create(true, DEVICE_QNAME, INTERFACE_QNAME, CHECK_WITH_OUTPUT_QNAME); + private static final QName CHECK_WITHOUT_OUTPUT_QNAME = + QName.create(URN_EXAMPLE_RPCS_ACTIONS_OUTPUTS, "check-without-output"); + private static final SchemaPath CHECK_WITHOUT_OUTPUT_INTERFACE_PATH = + SchemaPath.create(true, DEVICE_QNAME, INTERFACE_QNAME, CHECK_WITHOUT_OUTPUT_QNAME); + private static final QName RPC_WITH_OUTPUT_QNAME = + QName.create(URN_EXAMPLE_RPCS_ACTIONS_OUTPUTS, "rpc-with-output"); + private static final QName RPC_WITHOUT_OUTPUT_QNAME = + QName.create(URN_EXAMPLE_RPCS_ACTIONS_OUTPUTS, "rpc-without-output"); + private static final QName BOX_OUT_QNAME = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "box-out"); private static final QName BOX_IN_QNAME = QName.create(BOX_OUT_QNAME, "box-in"); @@ -164,7 +179,8 @@ public class NetconfMessageTransformerTest { ACTION_SCHEMA = YangParserTestUtils.parseYangResources(NetconfMessageTransformerTest.class, "/schemas/example-server-farm.yang","/schemas/example-server-farm-2.yang", - "/schemas/conflicting-actions.yang", "/schemas/augmented-action.yang"); + "/schemas/conflicting-actions.yang", "/schemas/augmented-action.yang", + "/schemas/rpcs-actions-outputs.yang"); } @AfterClass @@ -216,6 +232,26 @@ public class NetconfMessageTransformerTest { transformer.toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), toPath(NETCONF_LOCK_QNAME)); } + @Test + public void testRpcEmptyBodyWithOutputDefinedSchemaResult() throws Exception { + final String result = ""; + + DOMRpcResult domRpcResult = actionNetconfMessageTransformer + .toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), + toPath(RPC_WITH_OUTPUT_QNAME)); + assertNotNull(domRpcResult); + } + + @Test + public void testRpcEmptyBodyWithoutOutputDefinedSchemaResult() throws Exception { + final String result = ""; + + DOMRpcResult domRpcResult = actionNetconfMessageTransformer + .toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), + toPath(RPC_WITHOUT_OUTPUT_QNAME)); + assertNotNull(domRpcResult); + } + @Test public void testDiscardChangesRequest() throws Exception { final NetconfMessage netconfMessage = @@ -474,6 +510,8 @@ public class NetconfMessageTransformerTest { schemaPaths.add(XYZZY_BAR_PATH); schemaPaths.add(CHOICE_ACTION_PATH); schemaPaths.add(DISABLE_INTERFACE_PATH); + schemaPaths.add(CHECK_WITH_OUTPUT_INTERFACE_PATH); + schemaPaths.add(CHECK_WITHOUT_OUTPUT_INTERFACE_PATH); List actions = NetconfMessageTransformer.getActions(ACTION_SCHEMA); assertEquals(schemaPaths.size(), actions.size()); @@ -765,6 +803,30 @@ public class NetconfMessageTransformerTest { assertEquals("now", leaf.getValue()); } + @Test + public void toActionEmptyBodyWithOutputDefinedResultTest() throws Exception { + NetconfMessage message = new NetconfMessage(XmlUtil.readXmlToDocument( + "" + + "" + + "")); + DOMActionResult actionResult = + actionNetconfMessageTransformer.toActionResult(CHECK_WITH_OUTPUT_INTERFACE_PATH, message); + assertNotNull(actionResult); + assertTrue(actionResult.getOutput().isEmpty()); + } + + @Test + public void toActionEmptyBodyWithoutOutputDefinedResultTest() throws Exception { + NetconfMessage message = new NetconfMessage(XmlUtil.readXmlToDocument( + "" + + "" + + "")); + DOMActionResult actionResult = + actionNetconfMessageTransformer.toActionResult(CHECK_WITHOUT_OUTPUT_INTERFACE_PATH, message); + assertNotNull(actionResult); + assertTrue(actionResult.getOutput().isEmpty()); + } + private static void checkAction(final QName actionQname, final Node action , final String inputLocalName, final String inputNodeName, final String inputValue) { checkNode(action, actionQname.getLocalName(), actionQname.getLocalName(), diff --git a/netconf/sal-netconf-connector/src/test/resources/schemas/rpcs-actions-outputs.yang b/netconf/sal-netconf-connector/src/test/resources/schemas/rpcs-actions-outputs.yang new file mode 100644 index 0000000000..3b61d865db --- /dev/null +++ b/netconf/sal-netconf-connector/src/test/resources/schemas/rpcs-actions-outputs.yang @@ -0,0 +1,30 @@ +module rpcs-actions-outputs { + yang-version 1.1; + namespace "urn:example:rpcs-actions-outputs"; + prefix "rao"; + + import example-server-farm { prefix sfarm; revision-date 2018-08-07; } + + augment "/sfarm:device/sfarm:interface" { + action check-with-output { + output { + leaf not-mandatory-message { + type string; + } + } + } + action check-without-output { + } + } + + rpc rpc-with-output { + output { + leaf not-mandatory-message { + type string; + } + } + } + + rpc rpc-without-output { + } +} \ No newline at end of file -- 2.36.6