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