Fix YANG patch request for augmented element 27/102227/47
authorOleksandrZharov <Oleksandr.Zharov@pantheon.tech>
Fri, 26 Aug 2022 15:43:24 +0000 (17:43 +0200)
committerRobert Varga <nite@hq.sk>
Wed, 1 Mar 2023 14:59:48 +0000 (14:59 +0000)
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 <Oleksandr.Zharov@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderTest.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/test/AbstractBodyReaderTest.java
restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model-aug.yang [new file with mode: 0644]
restconf/restconf-nb/src/test/resources/instanceidentifier/yang/test-model.yang [new file with mode: 0644]

index aac27e18e8eea43f85602f2776d2c5410de0d936..2522cc1504958835a28e968c5f27a841a2d82a9c 100644 (file)
@@ -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;
     }
 
     /**
index 87485e60a481a29abdd1f60e4aaf099bf2ecef59..956582d4d714dfca1681cdad536058c79c80b56b 100644 (file)
@@ -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.
      */
index b791ed626d6d4e5b48e686c04bca4e814e465ea7..d0826a3a38263545b3f6a5443f216bbd75cb6043 100644 (file)
@@ -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("""
+            <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+                <patch-id>test-patch</patch-id>
+                <comment>This test patch for augmented element</comment>
+                <edit>
+                    <edit-id>edit1</edit-id>
+                    <operation>replace</operation>
+                    <target>/test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug</target>
+                    <value>
+                        <container-aug xmlns="test-ns-aug">
+                            <leaf-aug>data</leaf-aug>
+                        </container-aug>
+                    </value>
+                </edit>
+            </yang-patch>
+            """.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.
      */
index ba0e597b95dfb34d02148013f123d7532eeb9bd7..a3ee31338d8e8c8a99f6f0bda143cd5757a9d019 100644 (file)
@@ -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 (file)
index 0000000..21445ca
--- /dev/null
@@ -0,0 +1,29 @@
+module test-m-aug {\r
+  namespace "test-ns-aug";\r
+  prefix test-m;\r
+\r
+  import test-m {\r
+    prefix tm;\r
+  }\r
+\r
+  augment /tm:container-root/tm:container-lvl1 {\r
+    container container-aug {\r
+      leaf leaf-aug {\r
+        type string;\r
+      }\r
+\r
+      list list-aug {\r
+        key list-aug-key;\r
+        leaf list-aug-key {\r
+          type string;\r
+        }\r
+\r
+        container list-aug-container {\r
+          leaf foo {\r
+            type string;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r
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 (file)
index 0000000..39af1d1
--- /dev/null
@@ -0,0 +1,27 @@
+module test-m {\r
+  namespace "test-ns";\r
+  prefix test-m;\r
+\r
+  container container-root {\r
+    leaf leaf-lvl1 {\r
+      type string;\r
+    }\r
+\r
+    container container-lvl1 {\r
+      leaf leaf-lvl2 {\r
+        type string;\r
+      }\r
+\r
+      list list-lvl2 {\r
+        key list-lvl2-key;\r
+        leaf list-lvl2-key {\r
+          type string;\r
+        }\r
+\r
+        leaf leaf-lvl2 {\r
+          type string;\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r