2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.restconf.nb.rfc8040.jersey.providers.patch;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
13 import java.io.ByteArrayInputStream;
14 import java.io.InputStream;
15 import java.nio.charset.StandardCharsets;
16 import javax.ws.rs.core.MediaType;
17 import org.junit.BeforeClass;
18 import org.junit.Ignore;
19 import org.junit.Test;
20 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
21 import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.AbstractBodyReaderTest;
22 import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.XmlBodyReaderTest;
23 import org.opendaylight.yangtools.yang.common.ErrorTag;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
27 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
28 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
29 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
31 public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
32 private static EffectiveModelContext schemaContext;
34 private final XmlPatchBodyReader xmlToPatchBodyReader;
36 public XmlPatchBodyReaderTest() throws Exception {
38 xmlToPatchBodyReader = new XmlPatchBodyReader(databindProvider, mountPointService);
42 protected MediaType getMediaType() {
43 return new MediaType(MediaType.APPLICATION_XML, null);
47 public static void initialization() {
48 schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
52 public void moduleDataTest() throws Exception {
53 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
54 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
55 XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdata.xml")));
59 * Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
62 public void moduleDataValueMissingNegativeTest() throws Exception {
63 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
64 final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
65 "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
66 final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
67 () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
68 assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
72 * Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
76 public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
77 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
78 final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
79 "/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
80 final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
81 () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
82 assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
86 * Test of Yang Patch with absolute target path.
89 public void moduleDataAbsoluteTargetPathTest() throws Exception {
90 mockBodyReader("", xmlToPatchBodyReader, false);
91 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
92 XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml")));
96 * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
99 public void modulePatchCompleteTargetInURITest() throws Exception {
100 mockBodyReader("instance-identifier-patch-module:patch-cont", xmlToPatchBodyReader, false);
101 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
102 XmlBodyReaderTest.class.getResourceAsStream(
103 "/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml")));
107 * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
110 public void moduleDataMergeOperationOnListTest() throws Exception {
111 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
112 final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
113 "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
114 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
118 * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
121 public void moduleDataMergeOperationOnContainerTest() throws Exception {
122 mockBodyReader("instance-identifier-patch-module:patch-cont", xmlToPatchBodyReader, false);
123 final InputStream inputStream = XmlBodyReaderTest.class
124 .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
125 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
129 * Test of Yang Patch on the top-level container with empty URI for data root.
132 public void modulePatchTargetTopLevelContainerWithEmptyURITest() throws Exception {
133 mockBodyReader("", xmlToPatchBodyReader, false);
134 final InputStream inputStream = XmlBodyReaderTest.class
135 .getResourceAsStream("/instanceidentifier/xml/xmlPATCHTargetTopLevelContainerWithEmptyURI.xml");
136 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
140 * Test of Yang Patch on the top system map node element.
143 public void moduleTargetMapNodeTest() throws Exception {
144 mockBodyReader("", xmlToPatchBodyReader, false);
145 final var inputStream = new ByteArrayInputStream("""
146 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
147 <patch-id>map-patch</patch-id>
148 <comment>YANG patch comment</comment>
150 <edit-id>edit1</edit-id>
151 <operation>replace</operation>
152 <target>/map-model:cont-root/map-model:cont1/map-model:my-map=key</target>
154 <my-map xmlns="map:ns">
155 <key-leaf>key</key-leaf>
156 <data-leaf>data</data-leaf>
161 """.getBytes(StandardCharsets.UTF_8));
162 final var expectedData = Builders.mapBuilder()
163 .withNodeIdentifier(new NodeIdentifier(MAP_CONT_QNAME))
164 .withChild(Builders.mapEntryBuilder()
165 .withNodeIdentifier(NodeIdentifierWithPredicates.of(MAP_CONT_QNAME, KEY_LEAF_QNAME, "key"))
166 .withChild(ImmutableNodes.leafNode(KEY_LEAF_QNAME, "key"))
167 .withChild(ImmutableNodes.leafNode(DATA_LEAF_QNAME, "data"))
170 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
171 checkPatchContext(returnValue);
172 final var data = returnValue.getData().get(0).getNode();
173 assertEquals(MAP_CONT_QNAME, data.getIdentifier().getNodeType());
174 assertEquals(expectedData, data);
178 * Test of Yang Patch on the leaf set node element.
179 * TODO: Remove ignore when NETCONF-937 will be resolved
183 public void modulePatchTargetLeafSetNodeTest() throws Exception {
184 mockBodyReader("", xmlToPatchBodyReader, false);
185 final var inputStream = new ByteArrayInputStream("""
186 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
187 <patch-id>set-patch</patch-id>
188 <comment>YANG patch comment</comment>
190 <edit-id>edit1</edit-id>
191 <operation>replace</operation>
192 <target>/set-model:cont-root/set-model:cont1/set-model:my-set="data1"</target>
194 <my-set xmlns="set:ns">data1</my-set>
198 """.getBytes(StandardCharsets.UTF_8));
199 final var expectedData = Builders.leafSetBuilder()
200 .withNodeIdentifier(new NodeIdentifier(LEAF_SET_QNAME))
201 .withChild(Builders.leafSetEntryBuilder()
202 .withNodeIdentifier(new NodeWithValue(LEAF_SET_QNAME, "data1"))
206 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
207 checkPatchContext(returnValue);
208 final var data = returnValue.getData().get(0).getNode();
209 assertEquals(LEAF_SET_QNAME, data.getIdentifier().getNodeType());
210 assertEquals(expectedData, data);
214 * Test of Yang Patch on the top unkeyed list element.
217 public void moduleTargetUnkeyedListNodeTest() throws Exception {
218 mockBodyReader("", xmlToPatchBodyReader, false);
219 final var inputStream = new ByteArrayInputStream("""
220 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
221 <patch-id>list-patch</patch-id>
222 <comment>YANG patch comment</comment>
224 <edit-id>edit1</edit-id>
225 <operation>replace</operation>
226 <target>/list-model:cont-root/list-model:cont1/list-model:unkeyed-list</target>
228 <unkeyed-list xmlns="list:ns">
235 """.getBytes(StandardCharsets.UTF_8));
236 final var expectedData = Builders.unkeyedListBuilder()
237 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
238 .withChild(Builders.unkeyedListEntryBuilder()
239 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
240 .withChild(ImmutableNodes.leafNode(LIST_LEAF1_QNAME, "data1"))
241 .withChild(ImmutableNodes.leafNode(LIST_LEAF2_QNAME, "data2"))
244 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
245 checkPatchContext(returnValue);
246 final var data = returnValue.getData().get(0).getNode();
247 assertEquals(LIST_QNAME, data.getIdentifier().getNodeType());
248 assertEquals(expectedData, data);
252 * Test of Yang Patch on the top case node element.
255 public void moduleTargetCaseNodeTest() throws Exception {
256 mockBodyReader("", xmlToPatchBodyReader, false);
257 final var inputStream = new ByteArrayInputStream("""
258 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
259 <patch-id>choice-patch</patch-id>
260 <comment>YANG patch comment</comment>
262 <edit-id>edit1</edit-id>
263 <operation>replace</operation>
264 <target>/choice-model:cont-root/choice-model:cont1/choice-model:case-cont1</target>
266 <case-cont1 xmlns="choice:ns">
267 <case-leaf1>data</case-leaf1>
272 """.getBytes(StandardCharsets.UTF_8));
273 final var expectedData = Builders.containerBuilder()
274 .withNodeIdentifier(new NodeIdentifier(CHOICE_CONT_QNAME))
275 .withChild(ImmutableNodes.leafNode(CASE_LEAF1_QNAME, "data"))
277 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
278 checkPatchContext(returnValue);
279 final var data = returnValue.getData().get(0).getNode();
280 assertEquals(CHOICE_CONT_QNAME, data.getIdentifier().getNodeType());
281 assertEquals(expectedData, data);