Bug 7933: NPE when posting using XML 83/57683/2
authorIvan Hrasko <ivan.hrasko@pantheon.tech>
Tue, 23 May 2017 12:21:01 +0000 (14:21 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Tue, 23 May 2017 12:47:30 +0000 (14:47 +0200)
PUT operation:
- fix issue when putting malformed XML body did not
fail with appropriate status.

Change-Id: I6bff6467f4b99bed9adf1ac39def54822899761e
Signed-off-by: matus.kubica <matus.kubica@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
14 files changed:
restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/jersey/providers/XmlNormalizedNodeBodyReader.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/AbstractBodyReaderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonBodyReaderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderMountPointTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderMountPointTest.java [new file with mode: 0644]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderMountPointTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderTest.java
restconf/sal-rest-connector/src/test/resources/instanceidentifier/xml/bug7933.xml [new file with mode: 0644]

index bc1eeeae508756bceea4c0637ea9f96fbe637f2f..e074f94837a9aacca9c8846db4f335ac71b963fb 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.netconf.sal.rest.impl;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,6 +34,7 @@ import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
 import org.opendaylight.restconf.utils.RestconfConstants;
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
@@ -144,6 +146,14 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro
                     iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(schemaNode.getQName()));
                 }
             }
+        // PUT
+        } else if (!isRpc) {
+            final QName scQName = schemaNode.getQName();
+            Preconditions.checkState(
+                    docRootElm.equals(scQName.getLocalName())
+                            && docRootNamespace.equals(scQName.getNamespace().toASCIIString()),
+                    String.format("Not correct message root element \"%s\", should be \"%s\"",
+                            docRootElm, scQName));
         }
 
         NormalizedNode<?, ?> parsed = null;
index 507f4f362ace875a89e7dfd72814e6481661d72a..55f2b005a413b2e8c546cf8d1a5a9d736fc893fe 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.restconf.jersey.providers;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import java.io.IOException;
 import java.io.InputStream;
@@ -34,6 +35,7 @@ import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
 import org.opendaylight.restconf.Rfc8040;
 import org.opendaylight.restconf.utils.RestconfConstants;
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
@@ -132,6 +134,14 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro
                     iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(schemaNode.getQName()));
                 }
             }
+        // PUT
+        } else if (!isRpc) {
+            final QName scQName = schemaNode.getQName();
+            Preconditions.checkState(
+                    docRootElm.equals(scQName.getLocalName())
+                            && docRootNamespace.equals(scQName.getNamespace().toASCIIString()),
+                    String.format("Not correct message root element \"%s\", should be \"%s\"",
+                            docRootElm, scQName));
         }
 
         NormalizedNode<?, ?> parsed = null;
index a366ce29b0329cdc26cb809e860bd155befd4d03..2a5fb7b0ef4a49a04fd49c1dc1434ccfcf938e12 100644 (file)
@@ -35,8 +35,7 @@ public abstract class AbstractBodyReaderTest {
     private static Field uriField;
     private static Field requestField;
 
-    public AbstractBodyReaderTest() throws NoSuchFieldException,
-            SecurityException {
+    public AbstractBodyReaderTest() throws NoSuchFieldException {
         uriField = AbstractIdentifierAwareJaxRsProvider.class
                 .getDeclaredField("uriInfo");
         uriField.setAccessible(true);
index 0a3f14a384d61ef8c309d6b89300c4757a35568a..1ac78c8e25932d05e623520959da84e084b7965a 100644 (file)
@@ -20,11 +20,14 @@ import java.net.URI;
 import java.text.ParseException;
 import java.util.Collection;
 import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
 import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
@@ -64,7 +67,7 @@ public class TestXmlBodyReader extends AbstractBodyReaderTest {
         }
     }
 
-    public TestXmlBodyReader () throws NoSuchFieldException, SecurityException {
+    public TestXmlBodyReader() throws Exception {
         super();
         this.xmlBodyReader = new XmlNormalizedNodeBodyReader();
     }
@@ -252,4 +255,24 @@ public class TestXmlBodyReader extends AbstractBodyReaderTest {
         assertEquals("Not correct container found, namespace was ignored",
                 "bar:module", returnValue.getData().getNodeType().getNamespace().toString());
     }
+
+    /**
+     * Test PUT operation when message root element is not the same as the last element in request URI.
+     * PUT operation message should always start with schema node from URI otherwise exception should be
+     * thrown.
+     */
+    @Test
+    public void wrongRootElementTest() throws Exception {
+        mockBodyReader("instance-identifier-module:cont", this.xmlBodyReader, false);
+        final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+                "/instanceidentifier/xml/bug7933.xml");
+        try {
+            this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+            Assert.fail("Test should fail due to malformed PUT operation message");
+        } catch (final RestconfDocumentedException exception) {
+            final RestconfError restconfError = exception.getErrors().get(0);
+            Assert.assertEquals(RestconfError.ErrorType.PROTOCOL, restconfError.getErrorType());
+            Assert.assertEquals(RestconfError.ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+        }
+    }
 }
index f95090b7389fa3cfeec6a984d7891d53b43ba3a4..9e1237b7ba19719f419381a30b53bae65f82d072 100644 (file)
@@ -22,6 +22,7 @@ import java.net.URI;
 import java.text.ParseException;
 import java.util.Collection;
 import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
@@ -30,6 +31,8 @@ import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
 import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
@@ -67,9 +70,7 @@ public class TestXmlBodyReaderMountPoint extends AbstractBodyReaderTest {
         }
     }
 
-
-    public TestXmlBodyReaderMountPoint() throws NoSuchFieldException,
-            SecurityException {
+    public TestXmlBodyReaderMountPoint() throws Exception {
         super();
         this.xmlBodyReader = new XmlNormalizedNodeBodyReader();
     }
@@ -234,4 +235,24 @@ public class TestXmlBodyReaderMountPoint extends AbstractBodyReaderTest {
         assertEquals("Not correct container found, namespace was ignored",
                 "bar:module", returnValue.getData().getNodeType().getNamespace().toString());
     }
+
+    /**
+     * Test PUT operation when message root element is not the same as the last element in request URI.
+     * PUT operation message should always start with schema node from URI otherwise exception should be
+     * thrown.
+     */
+    @Test
+    public void wrongRootElementTest() throws Exception {
+        mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, false);
+        final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+                "/instanceidentifier/xml/bug7933.xml");
+        try {
+            this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+            Assert.fail("Test should fail due to malformed PUT operation message");
+        } catch (final RestconfDocumentedException exception) {
+            final RestconfError restconfError = exception.getErrors().get(0);
+            Assert.assertEquals(RestconfError.ErrorType.PROTOCOL, restconfError.getErrorType());
+            Assert.assertEquals(RestconfError.ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+        }
+    }
 }
index 16ef10055f461f5f4731643f204d59c9038b0c27..1284d0fec54dd5fd8f996d248e2a46eb24dd6f7d 100644 (file)
@@ -30,9 +30,9 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 abstract class AbstractBodyReaderTest {
 
-    protected final static ControllerContext controllerContext = ControllerContext.getInstance();
+    protected final static ControllerContext CONTROLLER_CONTEXT = ControllerContext.getInstance();
     protected final MediaType mediaType;
-    protected final static DOMMountPointServiceHandler mountPointServiceHandler = mock(
+    protected final static DOMMountPointServiceHandler MOUNT_POINT_SERVICE_HANDLER = mock(
             DOMMountPointServiceHandler.class);
 
     AbstractBodyReaderTest() throws NoSuchFieldException, IllegalAccessException {
@@ -41,7 +41,7 @@ abstract class AbstractBodyReaderTest {
         final Field mountPointServiceHandlerField = RestConnectorProvider.class.
                 getDeclaredField("mountPointServiceHandler");
         mountPointServiceHandlerField.setAccessible(true);
-        mountPointServiceHandlerField.set(RestConnectorProvider.class, mountPointServiceHandler);
+        mountPointServiceHandlerField.set(RestConnectorProvider.class, MOUNT_POINT_SERVICE_HANDLER);
     }
 
     protected abstract MediaType getMediaType();
@@ -77,6 +77,12 @@ abstract class AbstractBodyReaderTest {
         normalizedNodeProvider.setRequest(request);
     }
 
+    protected static void checkMountPointNormalizedNodeContext(
+            final NormalizedNodeContext nnContext) {
+        checkNormalizedNodeContext(nnContext);
+        assertNotNull(nnContext.getInstanceIdentifierContext().getMountPoint());
+    }
+
     protected static void checkNormalizedNodeContext(
             final NormalizedNodeContext nnContext) {
         assertNotNull(nnContext.getData());
index 4b3bb46e9777f72946c02fb210c6e2a6dae7c8f8..42696130581025653ce7f5a26a60d7ffe8e9b004 100644 (file)
@@ -72,8 +72,8 @@ public class JsonBodyReaderTest extends AbstractBodyReaderTest {
         final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
         testFiles.addAll(TestRestconfUtils.loadFiles("/modules"));
         schemaContext = YangParserTestUtils.parseYangSources(testFiles);
-        controllerContext.setSchemas(schemaContext);
-        when(mountPointServiceHandler.get()).thenReturn(mock(DOMMountPointService.class));
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mock(DOMMountPointService.class));
     }
 
     @Test
index f50106e96f67f3a7e8c9621c6f479f25cd0d86a5..727f7ce935cc61a57e5d3de5b137f999170c0ee7 100644 (file)
@@ -51,11 +51,11 @@ public class JsonPATCHBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final DOMMountPointService mountPointService = mock(DOMMountPointService.class);
         final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
 
-        when(mountPointServiceHandler.get()).thenReturn(mountPointService);
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mountPointService);
         when(mountPointService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountPoint));
         when(mountPoint.getSchemaContext()).thenReturn(schemaContext);
 
-        controllerContext.setSchemas(schemaContext);
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
     }
 
     @Test
index 6d8808ec0c2a9b32eeb94d83329089adc9b7741a..2adc789694990faa08e73d548f9aa552d548791e 100644 (file)
@@ -42,8 +42,8 @@ public class JsonPATCHBodyReaderTest extends AbstractBodyReaderTest {
     @BeforeClass
     public static void initialization() {
         schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
-        when(mountPointServiceHandler.get()).thenReturn(mock(DOMMountPointService.class));
-        controllerContext.setSchemas(schemaContext);
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mock(DOMMountPointService.class));
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
     }
 
     @Test
diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderMountPointTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderMountPointTest.java
new file mode 100644 (file)
index 0000000..cb3d10c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.restconf.jersey.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Optional;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.Collection;
+import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.TestXmlBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class XmlBodyReaderMountPointTest extends AbstractBodyReaderTest {
+    private final XmlNormalizedNodeBodyReader xmlBodyReader;
+    private static SchemaContext schemaContext;
+
+    private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = initializeInstanceIdentifierModule();
+
+    private static QNameModule initializeInstanceIdentifierModule() {
+        try {
+            return QNameModule.create(URI.create("instance:identifier:module"),
+                SimpleDateFormatUtil.getRevisionFormat().parse("2014-01-17"));
+        } catch (final ParseException e) {
+            throw new Error(e);
+        }
+    }
+
+    public XmlBodyReaderMountPointTest() throws Exception {
+        super();
+        this.xmlBodyReader = new XmlNormalizedNodeBodyReader();
+    }
+
+    @Override
+    protected MediaType getMediaType() {
+        return new MediaType(MediaType.APPLICATION_XML, null);
+    }
+
+    @BeforeClass
+    public static void initialization() throws Exception {
+        final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+        testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+        schemaContext = YangParserTestUtils.parseYangSources(testFiles);
+
+        final DOMMountPointService mountPointService = mock(DOMMountPointService.class);
+        final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mountPointService);
+        when(mountPointService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountPoint));
+        when(mountPoint.getSchemaContext()).thenReturn(schemaContext);
+
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
+    }
+
+    @Test
+    public void moduleDataTest() throws Exception {
+        final DataSchemaNode dataSchemaNode = schemaContext
+                .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+        final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+        mockBodyReader(uri, this.xmlBodyReader, false);
+        final InputStream inputStream = XmlBodyReaderMountPointTest.class
+                .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
+        final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null,
+                null, null, this.mediaType, null, inputStream);
+        checkMountPointNormalizedNodeContext(returnValue);
+        checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+    }
+
+    @Test
+    public void moduleSubContainerDataPutTest() throws Exception {
+        final DataSchemaNode dataSchemaNode = schemaContext
+                .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+        final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont/cont1";
+        mockBodyReader(uri, this.xmlBodyReader, false);
+        final InputStream inputStream = XmlBodyReaderMountPointTest.class
+                .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+        final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null,
+                null, null, this.mediaType, null, inputStream);
+        checkMountPointNormalizedNodeContext(returnValue);
+        checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue,
+                QName.create(dataSchemaNode.getQName(), "cont1"));
+    }
+
+    @Test
+    public void moduleSubContainerDataPostTest() throws Exception {
+        final DataSchemaNode dataSchemaNode = schemaContext
+                .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+        final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+        mockBodyReader(uri, this.xmlBodyReader, true);
+        final InputStream inputStream = XmlBodyReaderMountPointTest.class
+                .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+        final NormalizedNodeContext returnValue = this.xmlBodyReader.readFrom(null,
+                null, null, this.mediaType, null, inputStream);
+        checkMountPointNormalizedNodeContext(returnValue);
+        checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+    }
+
+    private void checkExpectValueNormalizeNodeContext(
+            final DataSchemaNode dataSchemaNode,
+            final NormalizedNodeContext nnContext) {
+        checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null);
+    }
+
+    private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+            final NormalizedNodeContext nnContext, final QName qualifiedName) {
+        YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier
+                .of(dataSchemaNode.getQName());
+        final DOMMountPoint mountPoint = nnContext
+                .getInstanceIdentifierContext().getMountPoint();
+        final DataSchemaNode mountDataSchemaNode = mountPoint
+                .getSchemaContext().getDataChildByName(
+                        dataSchemaNode.getQName());
+        assertNotNull(mountDataSchemaNode);
+        if ((qualifiedName != null) && (dataSchemaNode instanceof DataNodeContainer)) {
+            final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode)
+                    .getDataChildByName(qualifiedName);
+            dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent)
+                    .node(child.getQName()).build();
+            assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode()
+                    .equals(child));
+        } else {
+            assertTrue(mountDataSchemaNode.equals(dataSchemaNode));
+        }
+        assertNotNull(NormalizedNodes.findNode(nnContext.getData(),
+                dataNodeIdent));
+    }
+
+    /**
+     * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+     * used to distinguish between them to find correct one. Check if container was found not only according to its name
+     * but also by correct namespace used in payload.
+     */
+    @Test
+    public void findFooContainerUsingNamespaceTest() throws Exception {
+        mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, true);
+        final InputStream inputStream = TestXmlBodyReader.class
+                .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
+        final NormalizedNodeContext returnValue = this.xmlBodyReader
+                .readFrom(null, null, null, this.mediaType, null, inputStream);
+
+        // check return value
+        checkMountPointNormalizedNodeContext(returnValue);
+        // check if container was found both according to its name and namespace
+        assertEquals("Not correct container found, name was ignored",
+                "foo-bar-container", returnValue.getData().getNodeType().getLocalName());
+        assertEquals("Not correct container found, namespace was ignored",
+                "foo:module", returnValue.getData().getNodeType().getNamespace().toString());
+    }
+
+    /**
+     * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+     * used to distinguish between them to find correct one. Check if container was found not only according to its name
+     * but also by correct namespace used in payload.
+     */
+    @Test
+    public void findBarContainerUsingNamespaceTest() throws Exception {
+        mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, true);
+        final InputStream inputStream = TestXmlBodyReader.class
+                .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
+        final NormalizedNodeContext returnValue = this.xmlBodyReader
+                .readFrom(null, null, null, this.mediaType, null, inputStream);
+
+        // check return value
+        checkMountPointNormalizedNodeContext(returnValue);
+        // check if container was found both according to its name and namespace
+        assertEquals("Not correct container found, name was ignored",
+                "foo-bar-container", returnValue.getData().getNodeType().getLocalName());
+        assertEquals("Not correct container found, namespace was ignored",
+                "bar:module", returnValue.getData().getNodeType().getNamespace().toString());
+    }
+
+    /**
+     * Test PUT operation when message root element is not the same as the last element in request URI.
+     * PUT operation message should always start with schema node from URI otherwise exception should be
+     * thrown.
+     */
+    @Test
+    public void wrongRootElementTest() throws Exception {
+        mockBodyReader("instance-identifier-module:cont/yang-ext:mount", this.xmlBodyReader, false);
+        final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+                "/instanceidentifier/xml/bug7933.xml");
+        try {
+            this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+            Assert.fail("Test should fail due to malformed PUT operation message");
+        } catch (final RestconfDocumentedException exception) {
+            final RestconfError restconfError = exception.getErrors().get(0);
+            Assert.assertEquals(RestconfError.ErrorType.PROTOCOL, restconfError.getErrorType());
+            Assert.assertEquals(RestconfError.ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+        }
+    }
+}
index 1aef4b1714338a2705366163593695fad2cf63e5..29281c7a0d24b4a8e3d86cd5d32705f14a67c136 100644 (file)
@@ -20,11 +20,15 @@ import java.net.URI;
 import java.text.ParseException;
 import java.util.Collection;
 import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.TestXmlBodyReader;
 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
@@ -66,8 +70,8 @@ public class XmlBodyReaderTest extends AbstractBodyReaderTest {
         final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
         testFiles.addAll(TestRestconfUtils.loadFiles("/modules"));
         schemaContext = YangParserTestUtils.parseYangSources(testFiles);
-        controllerContext.setSchemas(schemaContext);
-        when(mountPointServiceHandler.get()).thenReturn(mock(DOMMountPointService.class));
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mock(DOMMountPointService.class));
     }
 
     @Test
@@ -214,4 +218,25 @@ public class XmlBodyReaderTest extends AbstractBodyReaderTest {
         assertEquals("Not correct container found, namespace was ignored", "bar:module",
                 returnValue.getData().getNodeType().getNamespace().toString());
     }
+
+    /**
+     * Test PUT operation when message root element is not the same as the last element in request URI.
+     * PUT operation message should always start with schema node from URI otherwise exception should be
+     * thrown.
+     */
+    @Test
+    public void wrongRootElementTest() throws Exception {
+        mockBodyReader("instance-identifier-module:cont", this.xmlBodyReader, false);
+        final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+                "/instanceidentifier/xml/bug7933.xml");
+        try {
+            this.xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+            Assert.fail("Test should fail due to malformed PUT operation message");
+        } catch (final RestconfDocumentedException exception) {
+            final RestconfError restconfError = exception.getErrors().get(0);
+            Assert.assertEquals(RestconfError.ErrorType.PROTOCOL, restconfError.getErrorType());
+            Assert.assertEquals(RestconfError.ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+        }
+    }
+
 }
index 9c6205a2ce1a91012a10d9fb91404b5ac2495e54..d7174ab2baff8fc16a35eb456d3ee60ddbb9c0d2 100644 (file)
@@ -50,11 +50,11 @@ public class XmlPATCHBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final DOMMountPointService mountPointService = mock(DOMMountPointService.class);
         final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
 
-        when(mountPointServiceHandler.get()).thenReturn(mountPointService);
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mountPointService);
         when(mountPointService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountPoint));
         when(mountPoint.getSchemaContext()).thenReturn(schemaContext);
 
-        controllerContext.setSchemas(schemaContext);
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
     }
 
     @Test
index 1d7a13485ba26d17c82bd1aa9f42b1e2f467fc58..8a29e69f87599adaa92a237c58f3ed31be38d2e9 100644 (file)
@@ -41,8 +41,8 @@ public class XmlPATCHBodyReaderTest extends AbstractBodyReaderTest {
     @BeforeClass
     public static void initialization() {
         schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
-        when(mountPointServiceHandler.get()).thenReturn(mock(DOMMountPointService.class));
-        controllerContext.setSchemas(schemaContext);
+        when(MOUNT_POINT_SERVICE_HANDLER.get()).thenReturn(mock(DOMMountPointService.class));
+        CONTROLLER_CONTEXT.setSchemas(schemaContext);
     }
 
     @Test
diff --git a/restconf/sal-rest-connector/src/test/resources/instanceidentifier/xml/bug7933.xml b/restconf/sal-rest-connector/src/test/resources/instanceidentifier/xml/bug7933.xml
new file mode 100644 (file)
index 0000000..aa0d79e
--- /dev/null
@@ -0,0 +1,9 @@
+<!--
+  ~ Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<cont1 xmlns="instance:identifier:module"/>