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