9947379fa9875af74f1bb4b3d8c3115a323c8ad4
[yangtools.git] / yang / yang-data-codec-xml / src / test / java / org / opendaylight / yangtools / yang / data / codec / xml / XmlToNormalizedNodesTest.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.yangtools.yang.data.codec.xml;
10
11 import static org.hamcrest.CoreMatchers.containsString;
12 import static org.hamcrest.CoreMatchers.startsWith;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertThat;
16 import static org.junit.Assert.fail;
17
18 import com.google.common.collect.ImmutableList;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.Map;
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.stream.XMLStreamException;
28 import javax.xml.stream.XMLStreamReader;
29 import org.junit.AfterClass;
30 import org.junit.BeforeClass;
31 import org.junit.Test;
32 import org.opendaylight.yangtools.util.xml.UntrustedXML;
33 import org.opendaylight.yangtools.yang.common.QName;
34 import org.opendaylight.yangtools.yang.common.QNameModule;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
39 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
47 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
48 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
49 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
50 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
52 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
53 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
54 import org.xml.sax.SAXException;
55
56 public class XmlToNormalizedNodesTest {
57
58     private static final QNameModule FOO_MODULE = QNameModule.create(URI.create("foo-namespace"));
59     private static final QName PARENT_CONTAINER = QName.create(FOO_MODULE, "parent-container");
60
61     private static final QNameModule BAZ_MODULE = QNameModule.create(URI.create("baz-namespace"));
62     private static final QName OUTER_CONTAINER = QName.create(BAZ_MODULE, "outer-container");
63
64     private static final QName MY_CONTAINER_1 = QName.create(BAZ_MODULE, "my-container-1");
65     private static final QName MY_KEYED_LIST = QName.create(BAZ_MODULE, "my-keyed-list");
66     private static final QName MY_KEY_LEAF = QName.create(BAZ_MODULE, "my-key-leaf");
67     private static final QName MY_LEAF_IN_LIST_1 = QName.create(BAZ_MODULE, "my-leaf-in-list-1");
68     private static final QName MY_LEAF_IN_LIST_2 = QName.create(BAZ_MODULE, "my-leaf-in-list-2");
69     private static final QName MY_LEAF_1 = QName.create(BAZ_MODULE, "my-leaf-1");
70     private static final QName MY_LEAFLIST = QName.create(BAZ_MODULE, "my-leaf-list");
71
72     private static final QName MY_CONTAINER_2 = QName.create(BAZ_MODULE, "my-container-2");
73     private static final QName INNER_CONTAINER = QName.create(BAZ_MODULE, "inner-container");
74     private static final QName MY_LEAF_2 = QName.create(BAZ_MODULE, "my-leaf-2");
75     private static final QName MY_LEAF_3 = QName.create(BAZ_MODULE, "my-leaf-3");
76     private static final QName MY_CHOICE = QName.create(BAZ_MODULE, "my-choice");
77     private static final QName MY_LEAF_IN_CASE_2 = QName.create(BAZ_MODULE, "my-leaf-in-case-2");
78
79     private static final QName MY_CONTAINER_3 = QName.create(BAZ_MODULE, "my-container-3");
80     private static final QName MY_DOUBLY_KEYED_LIST = QName.create(BAZ_MODULE, "my-doubly-keyed-list");
81     private static final QName MY_FIRST_KEY_LEAF = QName.create(BAZ_MODULE, "my-first-key-leaf");
82     private static final QName MY_SECOND_KEY_LEAF = QName.create(BAZ_MODULE, "my-second-key-leaf");
83     private static final QName MY_LEAF_IN_LIST_3 = QName.create(BAZ_MODULE, "my-leaf-in-list-3");
84
85     private static SchemaContext schemaContext;
86     private static ContainerSchemaNode outerContainerSchema;
87     private static ContainerSchemaNode parentContainerSchema;
88
89     @BeforeClass
90     public static void setup() {
91         schemaContext = YangParserTestUtils.parseYangResourceDirectory("/");
92         parentContainerSchema = (ContainerSchemaNode) SchemaContextUtil.findNodeInSchemaContext(schemaContext,
93                 ImmutableList.of(PARENT_CONTAINER));
94         outerContainerSchema = (ContainerSchemaNode) SchemaContextUtil.findNodeInSchemaContext(schemaContext,
95                 ImmutableList.of(OUTER_CONTAINER));
96     }
97
98     @AfterClass
99     public static void cleanup() {
100         schemaContext = null;
101         parentContainerSchema = null;
102         outerContainerSchema = null;
103     }
104
105     @Test
106     public void testComplexXmlParsing() throws IOException, SAXException, URISyntaxException, XMLStreamException,
107             ParserConfigurationException {
108         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/baz.xml");
109
110         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
111
112         final NormalizedNodeResult result = new NormalizedNodeResult();
113         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
114
115         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, outerContainerSchema);
116         xmlParser.parse(reader);
117
118         xmlParser.flush();
119         xmlParser.close();
120
121         final NormalizedNode<?, ?> transformedInput = result.getResult();
122         assertNotNull(transformedInput);
123
124         final NormalizedNode<?, ?> expectedNormalizedNode = buildOuterContainerNode();
125         assertNotNull(expectedNormalizedNode);
126
127         assertEquals(expectedNormalizedNode, transformedInput);
128     }
129
130     @Test
131     public void testSimpleXmlParsing() throws IOException, URISyntaxException, XMLStreamException,
132             ParserConfigurationException, SAXException {
133         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/foo.xml");
134
135         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
136
137         final NormalizedNodeResult result = new NormalizedNodeResult();
138         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
139
140         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, parentContainerSchema);
141         xmlParser.parse(reader);
142
143         final NormalizedNode<?, ?> transformedInput = result.getResult();
144         assertNotNull(transformedInput);
145     }
146
147     @Test
148     public void shouldFailOnDuplicateLeaf() throws XMLStreamException, IOException,
149             ParserConfigurationException, SAXException, URISyntaxException {
150         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo.xml");
151
152         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
153
154         final NormalizedNodeResult result = new NormalizedNodeResult();
155         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
156
157         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, parentContainerSchema);
158         try {
159             xmlParser.parse(reader);
160             fail("IllegalStateException should have been thrown because of duplicate leaf.");
161         } catch (IllegalStateException ex) {
162             assertThat(ex.getMessage(), startsWith("Duplicate namespace \"foo-namespace\" element \"decimal64-leaf\" "
163                     + "in XML input at: line 7 column "));
164         }
165     }
166
167     @Test
168     public void shouldFailOnDuplicateAnyXml() throws XMLStreamException, IOException,
169             ParserConfigurationException, SAXException, URISyntaxException {
170         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-2.xml");
171
172         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
173
174         final NormalizedNodeResult result = new NormalizedNodeResult();
175         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
176
177         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, parentContainerSchema);
178         try {
179             xmlParser.parse(reader);
180             fail("IllegalStateException should have been thrown because of duplicate anyxml");
181         } catch (IllegalStateException ex) {
182             assertThat(ex.getMessage(), startsWith("Duplicate namespace \"foo-namespace\" element \"my-anyxml\" in XML "
183                     + "input at: line 19 column "));
184         }
185     }
186
187     @Test
188     public void shouldFailOnDuplicateContainer() throws XMLStreamException, IOException,
189             ParserConfigurationException, SAXException, URISyntaxException {
190         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-3.xml");
191
192         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
193
194         final NormalizedNodeResult result = new NormalizedNodeResult();
195         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
196
197         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, parentContainerSchema);
198         try {
199             xmlParser.parse(reader);
200             fail("IllegalStateException should have been thrown because of duplicate container");
201         } catch (IllegalStateException ex) {
202             assertThat(ex.getMessage(), startsWith("Duplicate namespace \"foo-namespace\" element \"leaf-container\" "
203                 + "in XML input at: line 13 column "));
204         }
205     }
206
207     @Test
208     public void shouldFailOnUnterminatedLeafElement() throws XMLStreamException, IOException,
209             ParserConfigurationException, SAXException, URISyntaxException {
210         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz.xml");
211
212         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
213
214         final NormalizedNodeResult result = new NormalizedNodeResult();
215         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
216
217         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, outerContainerSchema);
218         try {
219             xmlParser.parse(reader);
220             fail("XMLStreamException should have been thrown because of unterminated leaf element.");
221         } catch (XMLStreamException ex) {
222             assertThat(ex.getMessage(), containsString(" START_ELEMENT "));
223         }
224     }
225
226     @Test
227     public void shouldFailOnUnterminatedLeafElement2() throws XMLStreamException, IOException,
228             ParserConfigurationException, SAXException, URISyntaxException {
229         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-2.xml");
230
231         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
232
233         final NormalizedNodeResult result = new NormalizedNodeResult();
234         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
235
236         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, outerContainerSchema);
237         try {
238             xmlParser.parse(reader);
239             fail("XMLStreamException should have been thrown because of unterminated leaf element.");
240         } catch (XMLStreamException ex) {
241             assertThat(ex.getMessage(), containsString("</my-leaf-1>"));
242         }
243     }
244
245     @Test
246     public void shouldFailOnUnterminatedContainerElement() throws XMLStreamException, IOException,
247             ParserConfigurationException, SAXException, URISyntaxException {
248         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-4.xml");
249
250         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
251
252         final NormalizedNodeResult result = new NormalizedNodeResult();
253         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
254
255         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, outerContainerSchema);
256         try {
257             xmlParser.parse(reader);
258             fail("XMLStreamException should have been thrown because of unterminated container element.");
259         } catch (XMLStreamException ex) {
260             assertThat(ex.getMessage(), containsString("</my-container-1>"));
261         }
262     }
263
264     @Test
265     public void shouldFailOnUnknownChildNode() throws XMLStreamException, IOException,
266             ParserConfigurationException, SAXException, URISyntaxException {
267         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-3.xml");
268
269         final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
270
271         final NormalizedNodeResult result = new NormalizedNodeResult();
272         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
273
274         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, outerContainerSchema);
275         try {
276             xmlParser.parse(reader);
277             fail("IllegalStateException should have been thrown because of an unknown child node.");
278         } catch (IllegalStateException ex) {
279             assertEquals("Schema for node with name my-container-1 and namespace baz-namespace does not exist at "
280                     + "AbsoluteSchemaPath{path=[(baz-namespace)outer-container, (baz-namespace)my-container-1]}",
281                     ex.getMessage());
282         }
283     }
284
285     private static NormalizedNode<?, ?> buildOuterContainerNode() {
286         // my-container-1
287         MapNode myKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(MY_KEYED_LIST))
288                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
289                         new NodeIdentifierWithPredicates(MY_KEYED_LIST, MY_KEY_LEAF, "listkeyvalue1"))
290                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_IN_LIST_1))
291                                 .withValue("listleafvalue1").build())
292                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_IN_LIST_2))
293                                 .withValue("listleafvalue2").build()).build())
294                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
295                         new NodeIdentifierWithPredicates(MY_KEYED_LIST, MY_KEY_LEAF, "listkeyvalue2"))
296                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_IN_LIST_1))
297                                 .withValue("listleafvalue12").build())
298                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_IN_LIST_2))
299                                 .withValue("listleafvalue22").build()).build()).build();
300
301         LeafNode<?> myLeaf1Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_1))
302                 .withValue("value1").build();
303
304         LeafSetNode<?> myLeafListNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAFLIST))
305                 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
306                         new NodeWithValue<>(MY_LEAFLIST, "lflvalue1")).withValue("lflvalue1").build())
307                 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
308                         new NodeWithValue<>(MY_LEAFLIST, "lflvalue2")).withValue("lflvalue2").build()).build();
309
310         ContainerNode myContainer1Node = Builders.containerBuilder().withNodeIdentifier(
311                 new NodeIdentifier(MY_CONTAINER_1))
312                 .withChild(myKeyedListNode)
313                 .withChild(myLeaf1Node)
314                 .withChild(myLeafListNode).build();
315
316         // my-container-2
317         ContainerNode innerContainerNode = Builders.containerBuilder().withNodeIdentifier(
318                 new NodeIdentifier(INNER_CONTAINER))
319                 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_2))
320                         .withValue("value2").build()).build();
321
322         LeafNode<?> myLeaf3Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_3))
323                 .withValue("value3").build();
324
325         ChoiceNode myChoiceNode = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(MY_CHOICE))
326                 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(MY_LEAF_IN_CASE_2))
327                         .withValue("case2value").build()).build();
328
329         ContainerNode myContainer2Node = Builders.containerBuilder().withNodeIdentifier(
330                 new NodeIdentifier(MY_CONTAINER_2))
331                 .withChild(innerContainerNode)
332                 .withChild(myLeaf3Node)
333                 .withChild(myChoiceNode).build();
334
335         // my-container-3
336         Map<QName, Object> keys = new HashMap<>();
337         keys.put(MY_FIRST_KEY_LEAF, "listkeyvalue1");
338         keys.put(MY_SECOND_KEY_LEAF, "listkeyvalue2");
339
340         MapNode myDoublyKeyedListNode = Builders.mapBuilder()
341                 .withNodeIdentifier(new NodeIdentifier(MY_DOUBLY_KEYED_LIST))
342                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
343                         new NodeIdentifierWithPredicates(MY_DOUBLY_KEYED_LIST, keys))
344                         .withChild(Builders.leafBuilder().withNodeIdentifier(
345                                 new NodeIdentifier(MY_LEAF_IN_LIST_3)).withValue("listleafvalue1").build()).build())
346                 .build();
347
348         AugmentationNode myDoublyKeyedListAugNode = Builders.augmentationBuilder().withNodeIdentifier(
349                 new AugmentationIdentifier(Collections.singleton(MY_DOUBLY_KEYED_LIST)))
350                 .withChild(myDoublyKeyedListNode).build();
351
352         ContainerNode myContainer3Node = Builders.containerBuilder().withNodeIdentifier(
353                 new NodeIdentifier(MY_CONTAINER_3))
354                 .withChild(myDoublyKeyedListAugNode).build();
355
356         AugmentationNode myContainer3AugNode = Builders.augmentationBuilder().withNodeIdentifier(
357                 new AugmentationIdentifier(Collections.singleton(MY_CONTAINER_3)))
358                 .withChild(myContainer3Node).build();
359
360         ContainerNode outerContainerNode = Builders.containerBuilder().withNodeIdentifier(
361                 new NodeIdentifier(OUTER_CONTAINER))
362                 .withChild(myContainer1Node)
363                 .withChild(myContainer2Node)
364                 .withChild(myContainer3AugNode).build();
365
366         return outerContainerNode;
367     }
368 }