From eb8a4d946d946f39c5d73fc392c5c59f14c4ea97 Mon Sep 17 00:00:00 2001 From: Ivan Hrasko Date: Tue, 23 May 2017 14:21:01 +0200 Subject: [PATCH] Bug 7933: NPE when posting using XML PUT operation: - fix issue when putting malformed XML body did not fail with appropriate status. Change-Id: I6bff6467f4b99bed9adf1ac39def54822899761e Signed-off-by: matus.kubica Signed-off-by: Ivan Hrasko --- .../impl/XmlNormalizedNodeBodyReader.java | 10 + .../XmlNormalizedNodeBodyReader.java | 10 + .../providers/AbstractBodyReaderTest.java | 3 +- .../test/providers/TestXmlBodyReader.java | 25 +- .../TestXmlBodyReaderMountPoint.java | 27 ++- .../providers/AbstractBodyReaderTest.java | 12 +- .../jersey/providers/JsonBodyReaderTest.java | 4 +- .../JsonPATCHBodyReaderMountPointTest.java | 4 +- .../providers/JsonPATCHBodyReaderTest.java | 4 +- .../XmlBodyReaderMountPointTest.java | 222 ++++++++++++++++++ .../jersey/providers/XmlBodyReaderTest.java | 29 ++- .../XmlPATCHBodyReaderMountPointTest.java | 4 +- .../providers/XmlPATCHBodyReaderTest.java | 4 +- .../instanceidentifier/xml/bug7933.xml | 9 + 14 files changed, 346 insertions(+), 21 deletions(-) create mode 100644 restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderMountPointTest.java create mode 100644 restconf/sal-rest-connector/src/test/resources/instanceidentifier/xml/bug7933.xml diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java index bc1eeeae50..e074f94837 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java @@ -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; diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/jersey/providers/XmlNormalizedNodeBodyReader.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/jersey/providers/XmlNormalizedNodeBodyReader.java index 507f4f362a..55f2b005a4 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/jersey/providers/XmlNormalizedNodeBodyReader.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/jersey/providers/XmlNormalizedNodeBodyReader.java @@ -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; diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java index a366ce29b0..2a5fb7b0ef 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java @@ -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); diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java index 0a3f14a384..1ac78c8e25 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java @@ -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()); + } + } } diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java index f95090b738..9e1237b7ba 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java @@ -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()); + } + } } diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/AbstractBodyReaderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/AbstractBodyReaderTest.java index 16ef10055f..1284d0fec5 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/AbstractBodyReaderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/AbstractBodyReaderTest.java @@ -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()); diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonBodyReaderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonBodyReaderTest.java index 4b3bb46e97..4269613058 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonBodyReaderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonBodyReaderTest.java @@ -72,8 +72,8 @@ public class JsonBodyReaderTest extends AbstractBodyReaderTest { final Collection 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 diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderMountPointTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderMountPointTest.java index f50106e96f..727f7ce935 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderMountPointTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderMountPointTest.java @@ -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 diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderTest.java index 6d8808ec0c..2adc789694 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/JsonPATCHBodyReaderTest.java @@ -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 index 0000000000..cb3d10c3a4 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderMountPointTest.java @@ -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 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()); + } + } +} diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderTest.java index 1aef4b1714..29281c7a0d 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlBodyReaderTest.java @@ -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 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()); + } + } + } diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderMountPointTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderMountPointTest.java index 9c6205a2ce..d7174ab2ba 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderMountPointTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderMountPointTest.java @@ -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 diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderTest.java index 1d7a13485b..8a29e69f87 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/XmlPATCHBodyReaderTest.java @@ -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 index 0000000000..aa0d79e324 --- /dev/null +++ b/restconf/sal-rest-connector/src/test/resources/instanceidentifier/xml/bug7933.xml @@ -0,0 +1,9 @@ + + + -- 2.36.6