From 1f8527b71ed3ff9cf9f9a8c612723bb297e1cd07 Mon Sep 17 00:00:00 2001 From: OleksandrZharov Date: Fri, 26 Aug 2022 17:43:24 +0200 Subject: [PATCH] Fix YANG patch request for augmented element When writing JSON data using yangtool's NormalizedNodeStreamWriter we have to check if the result is instance of Augmentation. In that case we have to use its child as data. Similar process is applied in JsonNormalizedNodeBodyReader. JIRA: NETCONF-747 Change-Id: I2c1d1abcd3cbb483b414408c2c768bdc5731b8ce Signed-off-by: OleksandrZharov Signed-off-by: Ivan Hrasko --- .../providers/patch/JsonPatchBodyReader.java | 15 ++++++-- .../patch/JsonPatchBodyReaderTest.java | 37 +++++++++++++++++++ .../patch/XmlPatchBodyReaderTest.java | 33 +++++++++++++++++ .../test/AbstractBodyReaderTest.java | 2 + .../yang/test-model-aug.yang | 29 +++++++++++++++ .../instanceidentifier/yang/test-model.yang | 27 ++++++++++++++ 6 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model-aug.yang create mode 100644 restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model.yang diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java index aac27e18e8..2522cc1504 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java @@ -42,8 +42,8 @@ import org.opendaylight.yangtools.yang.common.ErrorTag; import org.opendaylight.yangtools.yang.common.ErrorType; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier; import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; @@ -374,12 +374,19 @@ public class JsonPatchBodyReader extends AbstractPatchBodyReader { */ private static NormalizedNode readEditData(final @NonNull JsonReader in, final @NonNull Inference targetSchemaNode, final @NonNull InstanceIdentifierContext path) { - final NormalizedNodeResult resultHolder = new NormalizedNodeResult(); - final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder); + final var resultHolder = new NormalizedNodeResult(); + final var writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder); JsonParserStream.create(writer, JSONCodecFactorySupplier.RFC7951.getShared(path.getSchemaContext()), targetSchemaNode).parse(in); - return resultHolder.getResult(); + // In case AugmentationNode additional step to get actual data node is required + var data = resultHolder.getResult(); + while (data instanceof AugmentationNode augNode) { + final var it = augNode.body().iterator(); + verify(it.hasNext(), "Augmentation %s is missing child", data); + data = it.next(); + } + return data; } /** diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java index 87485e60a4..956582d4d7 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java @@ -188,6 +188,43 @@ public class JsonPatchBodyReaderTest extends AbstractBodyReaderTest { checkPatchContext(returnValue); } + /** + * Test of Yang Patch on the top augmented element. + */ + @Test + public void modulePatchTargetTopLevelAugmentedContainerTest() throws Exception { + mockBodyReader("", jsonToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + { + "ietf-yang-patch:yang-patch": { + "patch-id": "test-patch", + "comment": "comment", + "edit": [ + { + "edit-id": "edit1", + "operation": "replace", + "target": "/test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug", + "value": { + "container-aug": { + "leaf-aug": "data" + } + } + } + ] + } + } + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(CONT_AUG_QNAME)) + .withChild(ImmutableNodes.leafNode(LEAF_AUG_QNAME, "data")) + .build(); + final var returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(CONT_AUG_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + /** * Test of Yang Patch on the system map node element. */ diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java index b791ed626d..d0826a3a38 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java @@ -135,6 +135,39 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest { checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream)); } + /** + * Test of Yang Patch on the top augmented element. + */ + @Test + public void moduleTargetTopLevelAugmentedContainerTest() throws Exception { + mockBodyReader("", xmlToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + + test-patch + This test patch for augmented element + + edit1 + replace + /test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug + + + data + + + + + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(CONT_AUG_QNAME)) + .withChild(ImmutableNodes.leafNode(LEAF_AUG_QNAME, "data")) + .build(); + final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(CONT_AUG_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + /** * Test of Yang Patch on the top system map node element. */ diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java index ba0e597b95..a3ee31338d 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java @@ -43,6 +43,8 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; public abstract class AbstractBodyReaderTest { + protected static final QName CONT_AUG_QNAME = QName.create("test-ns-aug", "container-aug").intern(); + protected static final QName LEAF_AUG_QNAME = QName.create("test-ns-aug", "leaf-aug").intern(); protected static final QName MAP_CONT_QNAME = QName.create("map:ns", "my-map").intern(); protected static final QName KEY_LEAF_QNAME = QName.create("map:ns", "key-leaf").intern(); protected static final QName DATA_LEAF_QNAME = QName.create("map:ns", "data-leaf").intern(); diff --git a/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model-aug.yang b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model-aug.yang new file mode 100644 index 0000000000..21445ca4c0 --- /dev/null +++ b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model-aug.yang @@ -0,0 +1,29 @@ +module test-m-aug { + namespace "test-ns-aug"; + prefix test-m; + + import test-m { + prefix tm; + } + + augment /tm:container-root/tm:container-lvl1 { + container container-aug { + leaf leaf-aug { + type string; + } + + list list-aug { + key list-aug-key; + leaf list-aug-key { + type string; + } + + container list-aug-container { + leaf foo { + type string; + } + } + } + } + } +} diff --git a/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model.yang b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model.yang new file mode 100644 index 0000000000..39af1d1a2e --- /dev/null +++ b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model.yang @@ -0,0 +1,27 @@ +module test-m { + namespace "test-ns"; + prefix test-m; + + container container-root { + leaf leaf-lvl1 { + type string; + } + + container container-lvl1 { + leaf leaf-lvl2 { + type string; + } + + list list-lvl2 { + key list-lvl2-key; + leaf list-lvl2-key { + type string; + } + + leaf leaf-lvl2 { + type string; + } + } + } + } +} -- 2.36.6