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 system map node element.
142 public void moduleTargetMapNodeTest() 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>map-patch</patch-id>
147 <comment>YANG patch comment</comment>
149 <edit-id>edit1</edit-id>
150 <operation>replace</operation>
151 <target>/map-model:cont-root/map-model:cont1/map-model:my-map=key</target>
153 <my-map xmlns="map:ns">
154 <key-leaf>key</key-leaf>
155 <data-leaf>data</data-leaf>
160 """.getBytes(StandardCharsets.UTF_8));
161 final var expectedData = Builders.mapBuilder()
162 .withNodeIdentifier(new NodeIdentifier(MAP_CONT_QNAME))
163 .withChild(Builders.mapEntryBuilder()
164 .withNodeIdentifier(NodeIdentifierWithPredicates.of(MAP_CONT_QNAME, KEY_LEAF_QNAME, "key"))
165 .withChild(ImmutableNodes.leafNode(KEY_LEAF_QNAME, "key"))
166 .withChild(ImmutableNodes.leafNode(DATA_LEAF_QNAME, "data"))
169 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
170 checkPatchContext(returnValue);
171 final var data = returnValue.getData().get(0).getNode();
172 assertEquals(MAP_CONT_QNAME, data.getIdentifier().getNodeType());
173 assertEquals(expectedData, data);
177 * Test of Yang Patch on the leaf set node element.
180 public void modulePatchTargetLeafSetNodeTest() throws Exception {
181 mockBodyReader("", xmlToPatchBodyReader, false);
182 final var inputStream = new ByteArrayInputStream("""
183 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
184 <patch-id>set-patch</patch-id>
185 <comment>YANG patch comment</comment>
187 <edit-id>edit1</edit-id>
188 <operation>replace</operation>
189 <target>/set-model:cont-root/set-model:cont1/set-model:my-set="data1"</target>
191 <my-set xmlns="set:ns">data1</my-set>
195 """.getBytes(StandardCharsets.UTF_8));
196 final var expectedData = Builders.leafSetBuilder()
197 .withNodeIdentifier(new NodeIdentifier(LEAF_SET_QNAME))
198 .withChild(Builders.leafSetEntryBuilder()
199 .withNodeIdentifier(new NodeWithValue<>(LEAF_SET_QNAME, "data1"))
203 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
204 checkPatchContext(returnValue);
205 final var data = returnValue.getData().get(0).getNode();
206 assertEquals(LEAF_SET_QNAME, data.getIdentifier().getNodeType());
207 assertEquals(expectedData, data);
211 * Test of Yang Patch on the top unkeyed list element.
214 public void moduleTargetUnkeyedListNodeTest() throws Exception {
215 mockBodyReader("", xmlToPatchBodyReader, false);
216 final var inputStream = new ByteArrayInputStream("""
217 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
218 <patch-id>list-patch</patch-id>
219 <comment>YANG patch comment</comment>
221 <edit-id>edit1</edit-id>
222 <operation>replace</operation>
223 <target>/list-model:cont-root/list-model:cont1/list-model:unkeyed-list</target>
225 <unkeyed-list xmlns="list:ns">
232 """.getBytes(StandardCharsets.UTF_8));
233 final var expectedData = Builders.unkeyedListBuilder()
234 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
235 .withChild(Builders.unkeyedListEntryBuilder()
236 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
237 .withChild(ImmutableNodes.leafNode(LIST_LEAF1_QNAME, "data1"))
238 .withChild(ImmutableNodes.leafNode(LIST_LEAF2_QNAME, "data2"))
241 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
242 checkPatchContext(returnValue);
243 final var data = returnValue.getData().get(0).getNode();
244 assertEquals(LIST_QNAME, data.getIdentifier().getNodeType());
245 assertEquals(expectedData, data);
249 * Test of Yang Patch on the top case node element.
252 public void moduleTargetCaseNodeTest() throws Exception {
253 mockBodyReader("", xmlToPatchBodyReader, false);
254 final var inputStream = new ByteArrayInputStream("""
255 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
256 <patch-id>choice-patch</patch-id>
257 <comment>YANG patch comment</comment>
259 <edit-id>edit1</edit-id>
260 <operation>replace</operation>
261 <target>/choice-model:cont-root/choice-model:cont1/choice-model:case-cont1</target>
263 <case-cont1 xmlns="choice:ns">
264 <case-leaf1>data</case-leaf1>
269 """.getBytes(StandardCharsets.UTF_8));
270 final var expectedData = Builders.containerBuilder()
271 .withNodeIdentifier(new NodeIdentifier(CHOICE_CONT_QNAME))
272 .withChild(ImmutableNodes.leafNode(CASE_LEAF1_QNAME, "data"))
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(CHOICE_CONT_QNAME, data.getIdentifier().getNodeType());
278 assertEquals(expectedData, data);
282 * Test reading simple leaf value.
285 public void modulePatchSimpleLeafValueTest() throws Exception {
286 mockBodyReader("instance-identifier-patch-module:patch-cont/my-list1=leaf1", xmlToPatchBodyReader, false);
287 final var inputStream = new ByteArrayInputStream("""
288 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
289 <patch-id>test-patch</patch-id>
290 <comment>this is test patch</comment>
292 <edit-id>edit1</edit-id>
293 <operation>replace</operation>
294 <target>/my-list2=my-leaf20/name</target>
296 <name xmlns="instance:identifier:patch:module">my-leaf20</name>
300 """.getBytes(StandardCharsets.UTF_8));
301 final var returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
302 checkPatchContext(returnValue);
303 final var data = returnValue.getData().get(0).getNode();
304 assertEquals(LEAF_NAME_QNAME, data.getIdentifier().getNodeType());
305 assertEquals(ImmutableNodes.leafNode(LEAF_NAME_QNAME, "my-leaf20"), data);