From 38731f54f58263d94dc56e85c6ee08409d153472 Mon Sep 17 00:00:00 2001 From: OleksandrZharov Date: Fri, 26 Aug 2022 17:43:24 +0200 Subject: [PATCH] Test Json/Xml PatchBodyReaders on mixin nodes Created tests for both JSON and XML PatchBodyReaders with different types of mixin nodes. JIRA: NETCONF-943 Change-Id: Idd9bc2da6d561463bdd01b9714ea9f61a7a86e88 Signed-off-by: OleksandrZharov --- .../patch/JsonPatchBodyReaderTest.java | 166 ++++++++++++++++++ .../patch/XmlPatchBodyReaderTest.java | 153 ++++++++++++++++ .../test/AbstractBodyReaderTest.java | 11 ++ .../instanceidentifier/yang/choice-model.yang | 18 ++ .../yang/leaf-set-model.yang | 12 ++ .../instanceidentifier/yang/map-model.yang | 21 +++ .../yang/unkeyed-list-model.yang | 17 ++ 7 files changed, 398 insertions(+) create mode 100644 restconf/restconf-nb/src/test/resources/instanceidentifier/yang/choice-model.yang create mode 100644 restconf/restconf-nb/src/test/resources/instanceidentifier/yang/leaf-set-model.yang create mode 100644 restconf/restconf-nb/src/test/resources/instanceidentifier/yang/map-model.yang create mode 100644 restconf/restconf-nb/src/test/resources/instanceidentifier/yang/unkeyed-list-model.yang 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 7c557b1dd7..664ae5e79a 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,11 @@ 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.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; +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 +184,163 @@ public class JsonPatchBodyReaderTest extends AbstractBodyReaderTest { final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); checkPatchContext(returnValue); } + + /** + * Test of Yang Patch on the system map node element. + */ + @Test + public void modulePatchTargetMapNodeTest() throws Exception { + mockBodyReader("", jsonToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + { + "ietf-yang-patch:yang-patch": { + "patch-id": "map-patch", + "comment": "comment", + "edit": [ + { + "edit-id": "edit1", + "operation": "replace", + "target": "/map-model:cont-root/map-model:cont1/map-model:my-map=key", + "value": { + "my-map": { + "key-leaf": "key", + "data-leaf": "data" + } + } + } + ] + } + } + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(MAP_CONT_QNAME)) + .withChild(Builders.mapEntryBuilder() + .withNodeIdentifier(NodeIdentifierWithPredicates.of(MAP_CONT_QNAME, KEY_LEAF_QNAME, "key")) + .withChild(ImmutableNodes.leafNode(KEY_LEAF_QNAME, "key")) + .withChild(ImmutableNodes.leafNode(DATA_LEAF_QNAME, "data")) + .build()) + .build(); + final var returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(MAP_CONT_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + + /** + * Test of Yang Patch on the leaf set node element. + */ + @Test + public void modulePatchTargetLeafSetNodeTest() throws Exception { + mockBodyReader("", jsonToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + { + "ietf-yang-patch:yang-patch": { + "patch-id": "set-patch", + "comment": "comment", + "edit": [ + { + "edit-id": "edit1", + "operation": "replace", + "target": "/set-model:cont-root/set-model:cont1/set-model:my-set=data1", + "value": { + "my-set": [ "data1" ] + } + } + ] + } + } + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.leafSetBuilder() + .withNodeIdentifier(new NodeIdentifier(LEAF_SET_QNAME)) + .withChild(Builders.leafSetEntryBuilder() + .withNodeIdentifier(new NodeWithValue(LEAF_SET_QNAME, "data1")) + .withValue("data1") + .build()) + .build(); + final var returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(LEAF_SET_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + + /** + * Test of Yang Patch on the unkeyed list node element. + */ + @Test + public void modulePatchTargetUnkeyedListNodeTest() throws Exception { + mockBodyReader("", jsonToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + { + "ietf-yang-patch:yang-patch": { + "patch-id": "list-patch", + "comment": "comment", + "edit": [ + { + "edit-id": "edit1", + "operation": "replace", + "target": "/list-model:cont-root/list-model:cont1/list-model:unkeyed-list", + "value": { + "unkeyed-list": { + "leaf1": "data1", + "leaf2": "data2" + } + } + } + ] + } + } + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.unkeyedListBuilder() + .withNodeIdentifier(new NodeIdentifier(LIST_QNAME)) + .withChild(Builders.unkeyedListEntryBuilder() + .withNodeIdentifier(new NodeIdentifier(LIST_QNAME)) + .withChild(ImmutableNodes.leafNode(LIST_LEAF1_QNAME, "data1")) + .withChild(ImmutableNodes.leafNode(LIST_LEAF2_QNAME, "data2")) + .build()) + .build(); + final var returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(LIST_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + + /** + * Test of Yang Patch on the case node element. + */ + @Test + public void modulePatchTargetCaseNodeTest() throws Exception { + mockBodyReader("", jsonToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + { + "ietf-yang-patch:yang-patch": { + "patch-id": "choice-patch", + "comment": "comment", + "edit": [ + { + "edit-id": "edit1", + "operation": "replace", + "target": "/choice-model:cont-root/choice-model:cont1/choice-model:case-cont1", + "value": { + "case-cont1": { + "case-leaf1": "data" + } + } + } + ] + } + } + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(CHOICE_CONT_QNAME)) + .withChild(ImmutableNodes.leafNode(CASE_LEAF1_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(CHOICE_CONT_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 71a7bee0bf..c9b33b2062 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,14 +10,22 @@ 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.Ignore; import org.junit.Test; 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.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; +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 +135,149 @@ 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 system map node element. + */ + @Test + public void moduleTargetMapNodeTest() throws Exception { + mockBodyReader("", xmlToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + + map-patch + YANG patch comment + + edit1 + replace + /map-model:cont-root/map-model:cont1/map-model:my-map=key + + + key + data + + + + + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(MAP_CONT_QNAME)) + .withChild(Builders.mapEntryBuilder() + .withNodeIdentifier(NodeIdentifierWithPredicates.of(MAP_CONT_QNAME, KEY_LEAF_QNAME, "key")) + .withChild(ImmutableNodes.leafNode(KEY_LEAF_QNAME, "key")) + .withChild(ImmutableNodes.leafNode(DATA_LEAF_QNAME, "data")) + .build()) + .build(); + final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(MAP_CONT_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + + /** + * Test of Yang Patch on the leaf set node element. + * TODO: Remove ignore when NETCONF-937 will be resolved + */ + @Ignore + @Test + public void modulePatchTargetLeafSetNodeTest() throws Exception { + mockBodyReader("", xmlToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + + set-patch + YANG patch comment + + edit1 + replace + /set-model:cont-root/set-model:cont1/set-model:my-set="data1" + + data1 + + + + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.leafSetBuilder() + .withNodeIdentifier(new NodeIdentifier(LEAF_SET_QNAME)) + .withChild(Builders.leafSetEntryBuilder() + .withNodeIdentifier(new NodeWithValue(LEAF_SET_QNAME, "data1")) + .withValue("data1") + .build()) + .build(); + final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(LEAF_SET_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + + /** + * Test of Yang Patch on the top unkeyed list element. + */ + @Test + public void moduleTargetUnkeyedListNodeTest() throws Exception { + mockBodyReader("", xmlToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + + list-patch + YANG patch comment + + edit1 + replace + /list-model:cont-root/list-model:cont1/list-model:unkeyed-list + + + data1 + data2 + + + + + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.unkeyedListBuilder() + .withNodeIdentifier(new NodeIdentifier(LIST_QNAME)) + .withChild(Builders.unkeyedListEntryBuilder() + .withNodeIdentifier(new NodeIdentifier(LIST_QNAME)) + .withChild(ImmutableNodes.leafNode(LIST_LEAF1_QNAME, "data1")) + .withChild(ImmutableNodes.leafNode(LIST_LEAF2_QNAME, "data2")) + .build()) + .build(); + final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream); + checkPatchContext(returnValue); + final var data = returnValue.getData().get(0).getNode(); + assertEquals(LIST_QNAME, data.getIdentifier().getNodeType()); + assertEquals(expectedData, data); + } + + /** + * Test of Yang Patch on the top case node element. + */ + @Test + public void moduleTargetCaseNodeTest() throws Exception { + mockBodyReader("", xmlToPatchBodyReader, false); + final var inputStream = new ByteArrayInputStream(""" + + choice-patch + YANG patch comment + + edit1 + replace + /choice-model:cont-root/choice-model:cont1/choice-model:case-cont1 + + + data + + + + + """.getBytes(StandardCharsets.UTF_8)); + final var expectedData = Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(CHOICE_CONT_QNAME)) + .withChild(ImmutableNodes.leafNode(CASE_LEAF1_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(CHOICE_CONT_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 f9aa84238d..876dbfa002 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,21 @@ 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 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(); + protected static final QName LEAF_SET_QNAME = QName.create("set:ns", "my-set").intern(); + protected static final QName LIST_QNAME = QName.create("list:ns", "unkeyed-list").intern(); + protected static final QName LIST_LEAF1_QNAME = QName.create("list:ns", "leaf1").intern(); + protected static final QName LIST_LEAF2_QNAME = QName.create("list:ns", "leaf2").intern(); + protected static final QName CHOICE_CONT_QNAME = QName.create("choice:ns", "case-cont1").intern(); + protected static final QName CASE_LEAF1_QNAME = QName.create("choice:ns", "case-leaf1").intern(); + protected final MediaType mediaType; protected final DatabindProvider databindProvider; protected final DOMMountPointService mountPointService; diff --git a/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/choice-model.yang b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/choice-model.yang new file mode 100644 index 0000000000..aeee9f5610 --- /dev/null +++ b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/choice-model.yang @@ -0,0 +1,18 @@ +module choice-model { + namespace "choice:ns"; + prefix choice-model; + + container cont-root { + container cont1 { + choice choice1 { + case case1 { + container case-cont1 { + leaf case-leaf1 { + type string; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/leaf-set-model.yang b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/leaf-set-model.yang new file mode 100644 index 0000000000..cc35fc64e1 --- /dev/null +++ b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/leaf-set-model.yang @@ -0,0 +1,12 @@ +module set-model { + namespace "set:ns"; + prefix set-model; + + container cont-root { + container cont1 { + leaf-list my-set { + type string; + } + } + } +} \ No newline at end of file diff --git a/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/map-model.yang b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/map-model.yang new file mode 100644 index 0000000000..611efaebb6 --- /dev/null +++ b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/map-model.yang @@ -0,0 +1,21 @@ +module map-model { + namespace "map:ns"; + prefix map-model; + + container cont-root { + container cont1 { + list my-map { + + key "key-leaf"; + + leaf key-leaf { + type string; + } + + leaf data-leaf { + type string; + } + } + } + } +} \ No newline at end of file diff --git a/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/unkeyed-list-model.yang b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/unkeyed-list-model.yang new file mode 100644 index 0000000000..ea47570041 --- /dev/null +++ b/restconf/restconf-nb/src/test/resources/instanceidentifier/yang/unkeyed-list-model.yang @@ -0,0 +1,17 @@ +module list-model { + namespace "list:ns"; + prefix list-model; + + container cont-root { + container cont1 { + list unkeyed-list { + leaf leaf1 { + type string; + } + leaf leaf2 { + type string; + } + } + } + } +} \ No newline at end of file -- 2.36.6