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.Test;
19 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
20 import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.AbstractBodyReaderTest;
21 import org.opendaylight.restconf.nb.rfc8040.jersey.providers.test.XmlBodyReaderTest;
22 import org.opendaylight.yangtools.yang.common.ErrorTag;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
26 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
30 public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
31 private static EffectiveModelContext schemaContext;
33 private final XmlPatchBodyReader xmlToPatchBodyReader;
35 public XmlPatchBodyReaderTest() throws Exception {
37 xmlToPatchBodyReader = new XmlPatchBodyReader(databindProvider, mountPointService);
41 protected MediaType getMediaType() {
42 return new MediaType(MediaType.APPLICATION_XML, null);
46 public static void initialization() {
47 schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
51 public void moduleDataTest() throws Exception {
52 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
53 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
54 XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdata.xml")));
58 * Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
61 public void moduleDataValueMissingNegativeTest() throws Exception {
62 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
63 final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
64 "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
65 final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
66 () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
67 assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
71 * Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
75 public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
76 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
77 final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
78 "/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
79 final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
80 () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
81 assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
85 * Test of Yang Patch with absolute target path.
88 public void moduleDataAbsoluteTargetPathTest() throws Exception {
89 mockBodyReader("", xmlToPatchBodyReader, false);
90 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
91 XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml")));
95 * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
98 public void modulePatchCompleteTargetInURITest() throws Exception {
99 mockBodyReader("instance-identifier-patch-module:patch-cont", xmlToPatchBodyReader, false);
100 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
101 XmlBodyReaderTest.class.getResourceAsStream(
102 "/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml")));
106 * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
109 public void moduleDataMergeOperationOnListTest() throws Exception {
110 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
111 final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
112 "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
113 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
117 * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
120 public void moduleDataMergeOperationOnContainerTest() throws Exception {
121 mockBodyReader("instance-identifier-patch-module:patch-cont", xmlToPatchBodyReader, false);
122 final InputStream inputStream = XmlBodyReaderTest.class
123 .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
124 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
128 * Test of Yang Patch on the top-level container with empty URI for data root.
131 public void modulePatchTargetTopLevelContainerWithEmptyURITest() throws Exception {
132 mockBodyReader("", xmlToPatchBodyReader, false);
133 final InputStream inputStream = XmlBodyReaderTest.class
134 .getResourceAsStream("/instanceidentifier/xml/xmlPATCHTargetTopLevelContainerWithEmptyURI.xml");
135 checkPatchContext(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
139 * Test of Yang Patch on the top augmented element.
142 public void moduleTargetTopLevelAugmentedContainerTest() throws Exception {
143 mockBodyReader("", xmlToPatchBodyReader, false);
144 final var inputStream = new ByteArrayInputStream("""
145 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
146 <patch-id>test-patch</patch-id>
147 <comment>This test patch for augmented element</comment>
149 <edit-id>edit1</edit-id>
150 <operation>replace</operation>
151 <target>/test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug</target>
153 <container-aug xmlns="test-ns-aug">
154 <leaf-aug>data</leaf-aug>
159 """.getBytes(StandardCharsets.UTF_8));
160 final var expectedData = Builders.containerBuilder()
161 .withNodeIdentifier(new NodeIdentifier(CONT_AUG_QNAME))
162 .withChild(ImmutableNodes.leafNode(LEAF_AUG_QNAME, "data"))
164 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
165 checkPatchContext(returnValue);
166 final var data = returnValue.getData().get(0).getNode();
167 assertEquals(CONT_AUG_QNAME, data.getIdentifier().getNodeType());
168 assertEquals(expectedData, data);
172 * Test of Yang Patch on the top system map node element.
175 public void moduleTargetMapNodeTest() throws Exception {
176 mockBodyReader("", xmlToPatchBodyReader, false);
177 final var inputStream = new ByteArrayInputStream("""
178 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
179 <patch-id>map-patch</patch-id>
180 <comment>YANG patch comment</comment>
182 <edit-id>edit1</edit-id>
183 <operation>replace</operation>
184 <target>/map-model:cont-root/map-model:cont1/map-model:my-map=key</target>
186 <my-map xmlns="map:ns">
187 <key-leaf>key</key-leaf>
188 <data-leaf>data</data-leaf>
193 """.getBytes(StandardCharsets.UTF_8));
194 final var expectedData = Builders.mapBuilder()
195 .withNodeIdentifier(new NodeIdentifier(MAP_CONT_QNAME))
196 .withChild(Builders.mapEntryBuilder()
197 .withNodeIdentifier(NodeIdentifierWithPredicates.of(MAP_CONT_QNAME, KEY_LEAF_QNAME, "key"))
198 .withChild(ImmutableNodes.leafNode(KEY_LEAF_QNAME, "key"))
199 .withChild(ImmutableNodes.leafNode(DATA_LEAF_QNAME, "data"))
202 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
203 checkPatchContext(returnValue);
204 final var data = returnValue.getData().get(0).getNode();
205 assertEquals(MAP_CONT_QNAME, data.getIdentifier().getNodeType());
206 assertEquals(expectedData, data);
210 * Test of Yang Patch on the leaf set node element.
213 public void modulePatchTargetLeafSetNodeTest() throws Exception {
214 mockBodyReader("", xmlToPatchBodyReader, false);
215 final var inputStream = new ByteArrayInputStream("""
216 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
217 <patch-id>set-patch</patch-id>
218 <comment>YANG patch comment</comment>
220 <edit-id>edit1</edit-id>
221 <operation>replace</operation>
222 <target>/set-model:cont-root/set-model:cont1/set-model:my-set="data1"</target>
224 <my-set xmlns="set:ns">data1</my-set>
228 """.getBytes(StandardCharsets.UTF_8));
229 final var expectedData = Builders.leafSetBuilder()
230 .withNodeIdentifier(new NodeIdentifier(LEAF_SET_QNAME))
231 .withChild(Builders.leafSetEntryBuilder()
232 .withNodeIdentifier(new NodeWithValue<>(LEAF_SET_QNAME, "data1"))
236 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
237 checkPatchContext(returnValue);
238 final var data = returnValue.getData().get(0).getNode();
239 assertEquals(LEAF_SET_QNAME, data.getIdentifier().getNodeType());
240 assertEquals(expectedData, data);
244 * Test of Yang Patch on the top unkeyed list element.
247 public void moduleTargetUnkeyedListNodeTest() throws Exception {
248 mockBodyReader("", xmlToPatchBodyReader, false);
249 final var inputStream = new ByteArrayInputStream("""
250 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
251 <patch-id>list-patch</patch-id>
252 <comment>YANG patch comment</comment>
254 <edit-id>edit1</edit-id>
255 <operation>replace</operation>
256 <target>/list-model:cont-root/list-model:cont1/list-model:unkeyed-list</target>
258 <unkeyed-list xmlns="list:ns">
265 """.getBytes(StandardCharsets.UTF_8));
266 final var expectedData = Builders.unkeyedListBuilder()
267 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
268 .withChild(Builders.unkeyedListEntryBuilder()
269 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
270 .withChild(ImmutableNodes.leafNode(LIST_LEAF1_QNAME, "data1"))
271 .withChild(ImmutableNodes.leafNode(LIST_LEAF2_QNAME, "data2"))
274 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
275 checkPatchContext(returnValue);
276 final var data = returnValue.getData().get(0).getNode();
277 assertEquals(LIST_QNAME, data.getIdentifier().getNodeType());
278 assertEquals(expectedData, data);
282 * Test of Yang Patch on the top case node element.
285 public void moduleTargetCaseNodeTest() throws Exception {
286 mockBodyReader("", xmlToPatchBodyReader, false);
287 final var inputStream = new ByteArrayInputStream("""
288 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
289 <patch-id>choice-patch</patch-id>
290 <comment>YANG patch comment</comment>
292 <edit-id>edit1</edit-id>
293 <operation>replace</operation>
294 <target>/choice-model:cont-root/choice-model:cont1/choice-model:case-cont1</target>
296 <case-cont1 xmlns="choice:ns">
297 <case-leaf1>data</case-leaf1>
302 """.getBytes(StandardCharsets.UTF_8));
303 final var expectedData = Builders.containerBuilder()
304 .withNodeIdentifier(new NodeIdentifier(CHOICE_CONT_QNAME))
305 .withChild(ImmutableNodes.leafNode(CASE_LEAF1_QNAME, "data"))
307 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
308 checkPatchContext(returnValue);
309 final var data = returnValue.getData().get(0).getNode();
310 assertEquals(CHOICE_CONT_QNAME, data.getIdentifier().getNodeType());
311 assertEquals(expectedData, data);
315 * Test reading simple leaf value.
318 public void modulePatchSimpleLeafValueTest() throws Exception {
319 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
320 final var inputStream = new ByteArrayInputStream("""
321 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
322 <patch-id>test-patch</patch-id>
323 <comment>this is test patch</comment>
325 <edit-id>edit1</edit-id>
326 <operation>replace</operation>
327 <target>/my-list2=my-leaf20/name</target>
329 <name xmlns="instance:identifier:patch:module">my-leaf20</name>
333 """.getBytes(StandardCharsets.UTF_8));
334 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
335 checkPatchContext(returnValue);
336 final var data = returnValue.getData().get(0).getNode();
337 assertEquals(LEAF_NAME_QNAME, data.getIdentifier().getNodeType());
338 assertEquals(ImmutableNodes.leafNode(LEAF_NAME_QNAME, "my-leaf20"), data);