From b49fc5fd7940c9072cac55c770b3ebe9219ff73e 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 | 16 ++++++-- .../patch/JsonPatchBodyReaderTest.java | 40 +++++++++++++++++++ .../patch/XmlPatchBodyReaderTest.java | 37 +++++++++++++++++ .../test/AbstractBodyReaderTest.java | 6 ++- .../yang/test-model-aug.yang | 29 ++++++++++++++ .../instanceidentifier/yang/test-model.yang | 27 +++++++++++++ 6 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/yang/test-model-aug.yang create mode 100644 restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/yang/test-model.yang diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java index c581243ab3..f04d763a23 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java +++ b/restconf/restconf-nb-rfc8040/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,20 @@ 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) { + final var augNode = (AugmentationNode) data; + 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-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java index d9f42d9978..6f4b1cbc7d 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java +++ b/restconf/restconf-nb-rfc8040/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,39 @@ 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(("{\n" + + " \"ietf-yang-patch:yang-patch\": {\n" + + " \"patch-id\": \"test-patch\",\n" + + " \"comment\": \"comment\",\n" + + " \"edit\": [\n" + + " {\n" + + " \"edit-id\": \"edit1\",\n" + + " \"operation\": \"replace\",\n" + + " \"target\": \"/test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug\",\n" + + " \"value\": {\n" + + " \"container-aug\": {\n" + + " \"leaf-aug\": \"data\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + "}").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-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java index 96e16d71eb..439683b18e 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java +++ b/restconf/restconf-nb-rfc8040/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,36 @@ 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(( + "\n" + + " test-patch\n" + + " This test patch for augmented element\n" + + " \n" + + " edit1\n" + + " replace\n" + + " /test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug\n" + + " \n" + + " \n" + + " data\n" + + " \n" + + " \n" + + " \n" + + "").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-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java index fe32b1c69c..f0c3889d71 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java +++ b/restconf/restconf-nb-rfc8040/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-rfc8040/src/test/resources/instanceidentifier/yang/test-model-aug.yang b/restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/yang/test-model-aug.yang new file mode 100644 index 0000000000..21445ca4c0 --- /dev/null +++ b/restconf/restconf-nb-rfc8040/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-rfc8040/src/test/resources/instanceidentifier/yang/test-model.yang b/restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/yang/test-model.yang new file mode 100644 index 0000000000..39af1d1a2e --- /dev/null +++ b/restconf/restconf-nb-rfc8040/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