Bug 7933: NPE when posting using XML
[netconf.git] / restconf / sal-rest-connector / src / test / java / org / opendaylight / restconf / jersey / providers / XmlBodyReaderMountPointTest.java
1 /*
2  * Copyright (c) 2015 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.mockito.Matchers.any;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.when;
17
18 import com.google.common.base.Optional;
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.DOMMountPoint;
29 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
30 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
31 import org.opendaylight.controller.sal.rest.impl.test.providers.TestXmlBodyReader;
32 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
33 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
34 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.common.QNameModule;
37 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
39 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
40 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
41 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
44
45 public class XmlBodyReaderMountPointTest extends AbstractBodyReaderTest {
46     private final XmlNormalizedNodeBodyReader xmlBodyReader;
47     private static SchemaContext schemaContext;
48
49     private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = initializeInstanceIdentifierModule();
50
51     private static QNameModule initializeInstanceIdentifierModule() {
52         try {
53             return QNameModule.create(URI.create("instance:identifier:module"),
54                 SimpleDateFormatUtil.getRevisionFormat().parse("2014-01-17"));
55         } catch (final ParseException e) {
56             throw new Error(e);
57         }
58     }
59
60     public XmlBodyReaderMountPointTest() throws Exception {
61         super();
62         this.xmlBodyReader = new XmlNormalizedNodeBodyReader();
63     }
64
65     @Override
66     protected MediaType getMediaType() {
67         return new MediaType(MediaType.APPLICATION_XML, null);
68     }
69
70     @BeforeClass
71     public static void initialization() throws Exception {
72         final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
73         testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
74         schemaContext = YangParserTestUtils.parseYangSources(testFiles);
75
76         final DOMMountPointService mountPointService = mock(DOMMountPointService.class);
77         final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
78
79         when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mountPointService);
80         when(mountPointService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountPoint));
81         when(mountPoint.getSchemaContext()).thenReturn(schemaContext);
82
83         CONTROLLER_CONTEXT.setSchemas(schemaContext);
84     }
85
86     @Test
87     public void moduleDataTest() throws Exception {
88         final DataSchemaNode dataSchemaNode = schemaContext
89                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
90         final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
91         mockBodyReader(uri, this.xmlBodyReader, false);
92         final InputStream inputStream = XmlBodyReaderMountPointTest.class
93                 .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
94         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null,
95                 null, null, this.mediaType, null, inputStream);
96         checkMountPointNormalizedNodeContext(returnValue);
97         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
98     }
99
100     @Test
101     public void moduleSubContainerDataPutTest() throws Exception {
102         final DataSchemaNode dataSchemaNode = schemaContext
103                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
104         final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont/cont1";
105         mockBodyReader(uri, this.xmlBodyReader, false);
106         final InputStream inputStream = XmlBodyReaderMountPointTest.class
107                 .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
108         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null,
109                 null, null, this.mediaType, null, inputStream);
110         checkMountPointNormalizedNodeContext(returnValue);
111         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue,
112                 QName.create(dataSchemaNode.getQName(), "cont1"));
113     }
114
115     @Test
116     public void moduleSubContainerDataPostTest() throws Exception {
117         final DataSchemaNode dataSchemaNode = schemaContext
118                 .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
119         final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
120         mockBodyReader(uri, this.xmlBodyReader, true);
121         final InputStream inputStream = XmlBodyReaderMountPointTest.class
122                 .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
123         final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null,
124                 null, null, this.mediaType, null, inputStream);
125         checkMountPointNormalizedNodeContext(returnValue);
126         checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
127     }
128
129     private void checkExpectValueNormalizeNodeContext(
130             final DataSchemaNode dataSchemaNode,
131             final NormalizedNodeContext nnContext) {
132         checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null);
133     }
134
135     private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
136             final NormalizedNodeContext nnContext, final QName qualifiedName) {
137         YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier
138                 .of(dataSchemaNode.getQName());
139         final DOMMountPoint mountPoint = nnContext
140                 .getInstanceIdentifierContext().getMountPoint();
141         final DataSchemaNode mountDataSchemaNode = mountPoint
142                 .getSchemaContext().getDataChildByName(
143                         dataSchemaNode.getQName());
144         assertNotNull(mountDataSchemaNode);
145         if ((qualifiedName != null) && (dataSchemaNode instanceof DataNodeContainer)) {
146             final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode)
147                     .getDataChildByName(qualifiedName);
148             dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent)
149                     .node(child.getQName()).build();
150             assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode()
151                     .equals(child));
152         } else {
153             assertTrue(mountDataSchemaNode.equals(dataSchemaNode));
154         }
155         assertNotNull(NormalizedNodes.findNode(nnContext.getData(),
156                 dataNodeIdent));
157     }
158
159     /**
160      * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
161      * used to distinguish between them to find correct one. Check if container was found not only according to its name
162      * but also by correct namespace used in payload.
163      */
164     @Test
165     public void findFooContainerUsingNamespaceTest() throws Exception {
166         mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, true);
167         final InputStream inputStream = TestXmlBodyReader.class
168                 .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
169         final NormalizedNodeContext returnValue = this.xmlBodyReader
170                 .readFrom(null, null, null, this.mediaType, null, inputStream);
171
172         // check return value
173         checkMountPointNormalizedNodeContext(returnValue);
174         // check if container was found both according to its name and namespace
175         assertEquals("Not correct container found, name was ignored",
176                 "foo-bar-container", returnValue.getData().getNodeType().getLocalName());
177         assertEquals("Not correct container found, namespace was ignored",
178                 "foo:module", returnValue.getData().getNodeType().getNamespace().toString());
179     }
180
181     /**
182      * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
183      * used to distinguish between them to find correct one. Check if container was found not only according to its name
184      * but also by correct namespace used in payload.
185      */
186     @Test
187     public void findBarContainerUsingNamespaceTest() throws Exception {
188         mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, true);
189         final InputStream inputStream = TestXmlBodyReader.class
190                 .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
191         final NormalizedNodeContext returnValue = this.xmlBodyReader
192                 .readFrom(null, null, null, this.mediaType, null, inputStream);
193
194         // check return value
195         checkMountPointNormalizedNodeContext(returnValue);
196         // check if container was found both according to its name and namespace
197         assertEquals("Not correct container found, name was ignored",
198                 "foo-bar-container", returnValue.getData().getNodeType().getLocalName());
199         assertEquals("Not correct container found, namespace was ignored",
200                 "bar:module", returnValue.getData().getNodeType().getNamespace().toString());
201     }
202
203     /**
204      * Test PUT operation when message root element is not the same as the last element in request URI.
205      * PUT operation message should always start with schema node from URI otherwise exception should be
206      * thrown.
207      */
208     @Test
209     public void wrongRootElementTest() throws Exception {
210         mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, false);
211         final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
212                 "/instanceidentifier/xml/bug7933.xml");
213         try {
214             this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
215             Assert.fail("Test should fail due to malformed PUT operation message");
216         } catch (final RestconfDocumentedException exception) {
217             final RestconfError restconfError = exception.getErrors().get(0);
218             Assert.assertEquals(RestconfError.ErrorType.PROTOCOL, restconfError.getErrorType());
219             Assert.assertEquals(RestconfError.ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
220         }
221     }
222 }