From 51533ce6f2e886cb507efbaac38b3bfb67a2e64d 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 Signed-off-by: Yaroslav Lastivka --- .../providers/patch/JsonPatchBodyReader.java | 15 +++++-- .../patch/JsonPatchBodyReaderTest.java | 42 +++++++++++++++++++ .../patch/XmlPatchBodyReaderTest.java | 38 +++++++++++++++++ .../test/AbstractBodyReaderTest.java | 6 ++- .../yang/test-model-aug.yang | 29 +++++++++++++ .../instanceidentifier/yang/test-model.yang | 27 ++++++++++++ 6 files changed, 152 insertions(+), 5 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 95190882a7..19092de923 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 d9f42d9978..7cd773eb5e 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 @@ -11,7 +11,9 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import javax.ws.rs.core.MediaType; import org.junit.BeforeClass; import org.junit.Test; @@ -20,6 +22,9 @@ import org.opendaylight.restconf.common.patch.PatchContext; import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.AbstractBodyReaderTest; import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.JsonBodyReaderTest; import org.opendaylight.yangtools.yang.common.ErrorTag; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; public class JsonPatchBodyReaderTest extends AbstractBodyReaderTest { @@ -177,4 +182,41 @@ public class JsonPatchBodyReaderTest extends AbstractBodyReaderTest { final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); 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); + } } 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 96e16d71eb..435d9ef643 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 @@ -10,7 +10,9 @@ package org.opendaylight.restconf.nb.rfc8040.jersey.providers.patch; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import javax.ws.rs.core.MediaType; import org.junit.BeforeClass; import org.junit.Test; @@ -18,6 +20,9 @@ import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.AbstractBodyReaderTest; import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.XmlBodyReaderTest; import org.opendaylight.yangtools.yang.common.ErrorTag; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest { @@ -127,4 +132,37 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest { .getResourceAsStream("/instanceidentifier/xml/xmlPATCHTargetTopLevelContainerWithEmptyURI.xml"); 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); + } } 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 fe32b1c69c..f0c3889d71 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 @@ -38,10 +38,14 @@ import org.opendaylight.restconf.nb.rfc8040.jersey.providers.spi.AbstractIdentif import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; import org.opendaylight.yangtools.yang.common.ErrorTag; import org.opendaylight.yangtools.yang.common.ErrorType; +import org.opendaylight.yangtools.yang.common.QName; 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 final MediaType mediaType; protected final SchemaContextHandler schemaContextHandler; protected final DOMMountPointService mountPointService; @@ -53,7 +57,7 @@ public abstract class AbstractBodyReaderTest { schemaContextHandler = TestUtils.newSchemaContextHandler(schemaContext); mountPointService = mock(DOMMountPointService.class); - final DOMMountPoint mountPoint = mock(DOMMountPoint.class); + final var mountPoint = mock(DOMMountPoint.class); doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(any(YangInstanceIdentifier.class)); doReturn(Optional.of(FixedDOMSchemaService.of(schemaContext))).when(mountPoint) .getService(DOMSchemaService.class); 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