YANGTOOLS-890 - Fix XML parser bug 33/73933/4
authorMichal Cmarada <michal.cmarada@pantheon.tech>
Wed, 11 Jul 2018 15:18:59 +0000 (17:18 +0200)
committerRobert Varga <nite@hq.sk>
Fri, 13 Jul 2018 16:40:34 +0000 (16:40 +0000)
When model contains list which has the same name as its
encapsulating parent container it leads to
IllegalStateException: Attributes can be extracted only
from START_ELEMENT. This is caused by list not beeing
processed correctly and one additional empty list item
is created. To fix this it is necessary to end the loop
when end list element is reached.

Change-Id: I0d6f6ec356e503fcfc941f18d9133ea0c9cebc6c
Signed-off-by: Michal Cmarada <michal.cmarada@pantheon.tech>
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java
yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/bug890/xml/foo.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/bug890/yang/foo.yang [new file with mode: 0644]

index 79901ffd9aa9edfcf151aacd2f6464f18e12447d..eba402eb8e862e4c4217b9b62d318e3f665318d5 100644 (file)
@@ -289,7 +289,8 @@ public final class XmlParserStream implements Closeable, Flushable {
             String xmlElementName = in.getLocalName();
             while (xmlElementName.equals(parent.getSchema().getQName().getLocalName())) {
                 read(in, newEntryNode(parent), rootElement);
-                if (in.getEventType() == XMLStreamConstants.END_DOCUMENT) {
+                if (in.getEventType() == XMLStreamConstants.END_DOCUMENT
+                        || in.getEventType() == XMLStreamConstants.END_ELEMENT) {
                     break;
                 }
                 xmlElementName = in.getLocalName();
diff --git a/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java
new file mode 100644 (file)
index 0000000..fdc76d7
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 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
+ */
+
+package org.opendaylight.yangtools.yang.data.codec.xml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Optional;
+import javax.xml.stream.XMLStreamReader;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class Bug890Test {
+    private static final QNameModule FOO_MODULE = QNameModule.create(URI.create("foo"), Revision.of("2018-07-10"));
+    private static final QName OUTGOING_LABELS_QNAME = QName.create(FOO_MODULE, "outgoing-labels");
+    private static final QName INDEX_QNAME = QName.create(FOO_MODULE, "index");
+
+    private SchemaContext schemaContext;
+
+    @Before
+    public void setUp() throws Exception {
+        schemaContext = YangParserTestUtils.parseYangResource("/bug890/yang/foo.yang");
+    }
+
+    @Test
+    public void testinputXml() throws Exception {
+        final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/bug890/xml/foo.xml");
+        final Module fooModule = schemaContext.getModules().iterator().next();
+        final Optional<DataSchemaNode> rootCont = fooModule.findDataChildByName(
+                QName.create(fooModule.getQNameModule(), "root"));
+        assertTrue(rootCont.isPresent());
+        ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) rootCont.get();
+        assertNotNull(containerSchemaNode);
+
+        final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
+
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+        final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, containerSchemaNode);
+        xmlParser.parse(reader);
+
+        assertNotNull(result.getResult());
+        assertTrue(result.getResult() instanceof ContainerNode);
+        final ContainerNode rootContainer = (ContainerNode) result.getResult();
+
+        Optional<DataContainerChild<? extends PathArgument, ?>> myLeaf =
+                rootContainer.getChild(new NodeIdentifier(OUTGOING_LABELS_QNAME));
+        assertTrue(myLeaf.orElse(null) instanceof ContainerNode);
+
+        ContainerNode outgoingLabelsContainer = (ContainerNode)myLeaf.get();
+        Optional<DataContainerChild<? extends PathArgument, ?>> outgoingLabelsList =
+                outgoingLabelsContainer.getChild(new NodeIdentifier(OUTGOING_LABELS_QNAME));
+        assertTrue(outgoingLabelsList.orElse(null) instanceof MapNode);
+        MapNode outgoingLabelsMap = (MapNode) outgoingLabelsList.get();
+
+        assertEquals(2, outgoingLabelsMap.getValue().size());
+        Collection<MapEntryNode> labels = outgoingLabelsMap.getValue();
+        YangInstanceIdentifier.NodeIdentifierWithPredicates firstNodeId =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(OUTGOING_LABELS_QNAME, INDEX_QNAME, 0);
+        YangInstanceIdentifier.NodeIdentifierWithPredicates secondNodeId =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(OUTGOING_LABELS_QNAME, INDEX_QNAME, 1);
+        assertTrue(labels.stream().anyMatch(mapEntryNode -> mapEntryNode.getIdentifier().compareTo(firstNodeId) == 0));
+        assertTrue(labels.stream().anyMatch(mapEntryNode -> mapEntryNode.getIdentifier().compareTo(secondNodeId) == 0));
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/test/resources/bug890/xml/foo.xml b/yang/yang-data-codec-xml/src/test/resources/bug890/xml/foo.xml
new file mode 100644 (file)
index 0000000..4bd91b1
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<root xmlns="foo">
+    <outgoing-labels>
+        <outgoing-labels>
+            <index>0</index>
+            <config>
+                <index>0</index>
+                <label>103</label>
+            </config>
+        </outgoing-labels>
+        <outgoing-labels>
+            <index>1</index>
+            <config>
+                <index>1</index>
+                <label>104</label>
+            </config>
+        </outgoing-labels>
+    </outgoing-labels>
+</root>
\ No newline at end of file
diff --git a/yang/yang-data-codec-xml/src/test/resources/bug890/yang/foo.yang b/yang/yang-data-codec-xml/src/test/resources/bug890/yang/foo.yang
new file mode 100644 (file)
index 0000000..4caaf48
--- /dev/null
@@ -0,0 +1,54 @@
+module foo {
+    yang-version 1;
+    namespace "foo";
+    prefix "foo";
+
+    revision "2018-07-10" {
+    }
+
+    grouping path-outgoing-labels_config {
+        description "Path outgoing labels grouping";
+        leaf index {
+              type uint8 {
+                range "0..255";
+              }
+              description "Index of the label. Index 0 indicates top of the label stack";
+        }
+        leaf label {
+          type uint32;
+          description "The outgoing MPLS labels to impose";
+        }
+    }
+
+    grouping path-outgoing-labels {
+        description "Path outgoing labels grouping";
+        container outgoing-labels {
+            description "List of outgoing labels";
+            list outgoing-labels {
+                key "index";
+                description "Outgoing label list";
+                leaf index {
+                    type leafref {
+                        path "../config/index";
+                    }
+                    description
+                    "Index of the label. Index 0 indicates
+                     top of the label stack";
+                }
+                container config {
+                    description "Configuration intended parameters";
+                    uses path-outgoing-labels_config;
+                }
+                container state {
+                    config false;
+                    description "Configuration applied parameters and state";
+                    uses path-outgoing-labels_config;
+                }
+            }
+        }
+    }
+
+    container root {
+        uses path-outgoing-labels;
+    }
+}