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;
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 {
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);
+ }
}
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 {
.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("""
+ <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>map-patch</patch-id>
+ <comment>YANG patch comment</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>replace</operation>
+ <target>/map-model:cont-root/map-model:cont1/map-model:my-map=key</target>
+ <value>
+ <my-map xmlns="map:ns">
+ <key-leaf>key</key-leaf>
+ <data-leaf>data</data-leaf>
+ </my-map>
+ </value>
+ </edit>
+ </yang-patch>
+ """.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("""
+ <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>set-patch</patch-id>
+ <comment>YANG patch comment</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>replace</operation>
+ <target>/set-model:cont-root/set-model:cont1/set-model:my-set="data1"</target>
+ <value>
+ <my-set xmlns="set:ns">data1</my-set>
+ </value>
+ </edit>
+ </yang-patch>
+ """.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("""
+ <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>list-patch</patch-id>
+ <comment>YANG patch comment</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>replace</operation>
+ <target>/list-model:cont-root/list-model:cont1/list-model:unkeyed-list</target>
+ <value>
+ <unkeyed-list xmlns="list:ns">
+ <leaf1>data1</leaf1>
+ <leaf2>data2</leaf2>
+ </unkeyed-list>
+ </value>
+ </edit>
+ </yang-patch>
+ """.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("""
+ <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>choice-patch</patch-id>
+ <comment>YANG patch comment</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>replace</operation>
+ <target>/choice-model:cont-root/choice-model:cont1/choice-model:case-cont1</target>
+ <value>
+ <case-cont1 xmlns="choice:ns">
+ <case-leaf1>data</case-leaf1>
+ </case-cont1>
+ </value>
+ </edit>
+ </yang-patch>
+ """.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);
+ }
}
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;
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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