Split Restconf implementations (draft02 and RFC) - move restconf
[netconf.git] / restconf / restconf-nb-bierman02 / src / test / java / org / opendaylight / restconf / jersey / providers / XmlBodyReaderTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.restconf.jersey.providers;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.when;
17
18 import com.google.common.collect.Sets;
19 import java.io.File;
20 import java.io.InputStream;
21 import java.net.URI;
22 import java.text.ParseException;
23 import java.util.Collection;
24 import javax.ws.rs.core.MediaType;
25 import org.junit.Assert;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
29 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
30 import org.opendaylight.controller.sal.rest.impl.test.providers.TestXmlBodyReader;
31 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
32 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
33 import org.opendaylight.restconf.common.errors.RestconfError;
34 import org.opendaylight.yangtools.yang.common.QName;
35 import org.opendaylight.yangtools.yang.common.QNameModule;
36 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
39 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
40 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
42 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
43 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.Module;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
47
48 public class XmlBodyReaderTest extends AbstractBodyReaderTest {
49
50     private final XmlNormalizedNodeBodyReader xmlBodyReader;
51     private static SchemaContext schemaContext;
52     private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = initializeInstanceIdentifierModule();
53
54     private static QNameModule initializeInstanceIdentifierModule() {
55         try {
56             return QNameModule.create(URI.create("instance:identifier:module"),
57                 SimpleDateFormatUtil.getRevisionFormat().parse("2014-01-17"));
58         } catch (final ParseException e) {
59             throw new Error(e);
60         }
61     }
62
63     public XmlBodyReaderTest() throws Exception {
64         super();
65         this.xmlBodyReader = new XmlNormalizedNodeBodyReader();
66     }
67
68     @Override
69     protected MediaType getMediaType() {
70         return new MediaType(MediaType.APPLICATION_XML, null);
71     }
72
73     @BeforeClass
74     public static void initialization() throws Exception {
75         final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
76         testFiles.addAll(TestRestconfUtils.loadFiles("/modules"));
77         testFiles.addAll(TestRestconfUtils.loadFiles("/foo-xml-test/yang"));
78         schemaContext = YangParserTestUtils.parseYangSources(testFiles);
79         CONTROLLER_CONTEXT.setSchemas(schemaContext);
80         when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mock(DOMMountPointService.class));
81     }
82
83     @Test
84     public void putXmlTest() throws Exception {
85         runXmlTest(false, "foo:top-level-list=key-value");
86     }
87
88     @Test
89     public void postXmlTest() throws Exception {
90         runXmlTest(true, "");
91     }
92
93     private void runXmlTest(final boolean isPost, final String path) throws Exception {
94         mockBodyReader(path, xmlBodyReader, isPost);
95         final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream("/foo-xml-test/foo.xml");
96         final NormalizedNodeContext nnc = xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
97         assertNotNull(nnc);
98
99         assertTrue(nnc.getData() instanceof MapEntryNode);
100         final MapEntryNode data = (MapEntryNode) nnc.getData();
101         assertTrue(data.getValue().size() == 2);
102         for (final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
103             switch (child.getNodeType().getLocalName()) {
104                 case "key-leaf":
105                     assertEquals("key-value", child.getValue());
106                     break;
107
108                 case "ordinary-leaf":
109                     assertEquals("leaf-value", child.getValue());
110                     break;
111                 default:
112                     fail();
113             }
114         }
115     }
116
117     @Test
118     public void moduleDataTest() throws Exception {
119         final DataSchemaNode dataSchemaNode = schemaContext
120                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
121         final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName());
122         final String uri = "instance-identifier-module:cont";
123         mockBodyReader(uri, this.xmlBodyReader, false);
124         final InputStream inputStream = XmlBodyReaderTest.class
125                 .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
126         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
127                 inputStream);
128         checkNormalizedNodeContext(returnValue);
129         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
130     }
131
132     @Test
133     public void moduleSubContainerDataPutTest() throws Exception {
134         final DataSchemaNode dataSchemaNode = schemaContext
135                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
136         final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
137         final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
138         final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName);
139         final String uri = "instance-identifier-module:cont/cont1";
140         mockBodyReader(uri, this.xmlBodyReader, false);
141         final InputStream inputStream = XmlBodyReaderTest.class
142                 .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
143         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
144                 inputStream);
145         checkNormalizedNodeContext(returnValue);
146         checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII);
147     }
148
149     @Test
150     public void moduleSubContainerDataPostTest() throws Exception {
151         final DataSchemaNode dataSchemaNode = schemaContext
152                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
153         final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
154         final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
155         final String uri = "instance-identifier-module:cont";
156         mockBodyReader(uri, this.xmlBodyReader, true);
157         final InputStream inputStream = XmlBodyReaderTest.class
158                 .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
159         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
160                 inputStream);
161         checkNormalizedNodeContext(returnValue);
162         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
163     }
164
165     @Test
166     public void moduleSubContainerAugmentDataPostTest() throws Exception {
167         final DataSchemaNode dataSchemaNode = schemaContext
168                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
169         final Module augmentModule = schemaContext.findModuleByNamespace(new URI("augment:module")).iterator().next();
170         final QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment");
171         final YangInstanceIdentifier.AugmentationIdentifier augII = new YangInstanceIdentifier.AugmentationIdentifier(
172                 Sets.newHashSet(contAugmentQName));
173         final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(augII)
174                 .node(contAugmentQName);
175         final String uri = "instance-identifier-module:cont";
176         mockBodyReader(uri, this.xmlBodyReader, true);
177         final InputStream inputStream = XmlBodyReaderTest.class
178                 .getResourceAsStream("/instanceidentifier/xml/xml_augment_container.xml");
179         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
180                 inputStream);
181         checkNormalizedNodeContext(returnValue);
182         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
183     }
184
185     @Test
186     public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception {
187         final DataSchemaNode dataSchemaNode = schemaContext
188                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
189         final Module augmentModule = schemaContext.findModuleByNamespace(new URI("augment:module")).iterator().next();
190         final QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1");
191         final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
192         final QName containerQName = QName.create(augmentChoice1QName, "case-choice-case-container1");
193         final YangInstanceIdentifier.AugmentationIdentifier augChoice1II =
194                 new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(augmentChoice1QName));
195         final YangInstanceIdentifier.AugmentationIdentifier augChoice2II =
196                 new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(augmentChoice2QName));
197         final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(augChoice1II)
198                 .node(augmentChoice1QName).node(augChoice2II).node(augmentChoice2QName).node(containerQName);
199         final String uri = "instance-identifier-module:cont";
200         mockBodyReader(uri, this.xmlBodyReader, true);
201         final InputStream inputStream = XmlBodyReaderTest.class
202                 .getResourceAsStream("/instanceidentifier/xml/xml_augment_choice_container.xml");
203         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
204                 inputStream);
205         checkNormalizedNodeContext(returnValue);
206         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
207     }
208
209     private static void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
210             final NormalizedNodeContext nnContext, final YangInstanceIdentifier dataNodeIdent) {
211         assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode());
212         assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
213         assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
214     }
215
216     /**
217      * Test when container with the same name is placed in two modules
218      * (foo-module and bar-module). Namespace must be used to distinguish
219      * between them to find correct one. Check if container was found not only
220      * according to its name but also by correct namespace used in payload.
221      */
222     @Test
223     public void findFooContainerUsingNamespaceTest() throws Exception {
224         mockBodyReader("", this.xmlBodyReader, true);
225         final InputStream inputStream = XmlBodyReaderTest.class
226                 .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
227         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
228                 inputStream);
229
230         // check return value
231         checkNormalizedNodeContext(returnValue);
232         // check if container was found both according to its name and namespace
233         assertEquals("Not correct container found, name was ignored", "foo-bar-container",
234                 returnValue.getData().getNodeType().getLocalName());
235         assertEquals("Not correct container found, namespace was ignored", "foo:module",
236                 returnValue.getData().getNodeType().getNamespace().toString());
237     }
238
239     /**
240      * Test when container with the same name is placed in two modules
241      * (foo-module and bar-module). Namespace must be used to distinguish
242      * between them to find correct one. Check if container was found not only
243      * according to its name but also by correct namespace used in payload.
244      */
245     @Test
246     public void findBarContainerUsingNamespaceTest() throws Exception {
247         mockBodyReader("", this.xmlBodyReader, true);
248         final InputStream inputStream = XmlBodyReaderTest.class
249                 .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
250         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null,
251                 inputStream);
252
253         // check return value
254         checkNormalizedNodeContext(returnValue);
255         // check if container was found both according to its name and namespace
256         assertEquals("Not correct container found, name was ignored", "foo-bar-container",
257                 returnValue.getData().getNodeType().getLocalName());
258         assertEquals("Not correct container found, namespace was ignored", "bar:module",
259                 returnValue.getData().getNodeType().getNamespace().toString());
260     }
261
262     /**
263      * Test PUT operation when message root element is not the same as the last element in request URI.
264      * PUT operation message should always start with schema node from URI otherwise exception should be
265      * thrown.
266      */
267     @Test
268     public void wrongRootElementTest() throws Exception {
269         mockBodyReader("instance-identifier-module:cont", this.xmlBodyReader, false);
270         final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
271                 "/instanceidentifier/xml/bug7933.xml");
272         try {
273             this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
274             Assert.fail("Test should fail due to malformed PUT operation message");
275         } catch (final RestconfDocumentedException exception) {
276             final RestconfError restconfError = exception.getErrors().get(0);
277             Assert.assertEquals(RestconfError.ErrorType.PROTOCOL, restconfError.getErrorType());
278             Assert.assertEquals(RestconfError.ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
279         }
280     }
281
282 }