Rename Any{Data,Xml}SchemaNode to Any{data,xml}SchemaNode
[yangtools.git] / yang / yang-parser-rfc7950 / src / test / java / org / opendaylight / yangtools / yang / stmt / DeviationResolutionTest.java
1 /*
2  * Copyright (c) 2017 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.stmt;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.assertTrue;
16 import static org.junit.Assert.fail;
17 import static org.opendaylight.yangtools.yang.stmt.StmtTestUtils.sourceForResource;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.PrintStream;
21 import java.util.Optional;
22 import org.junit.Test;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.Revision;
25 import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
30 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.Module;
34 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
35 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.InvalidSubstatementException;
40 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
41
42 public class DeviationResolutionTest {
43
44     @Test
45     public void testDeviateNotSupported() throws Exception {
46         final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
47                 "/deviation-resolution-test/deviation-not-supported");
48         assertNotNull(schemaContext);
49
50         final Module importedModule = schemaContext.findModule("imported", Revision.of("2017-01-20")).get();
51         final ContainerSchemaNode myContA = (ContainerSchemaNode) importedModule.getDataChildByName(
52                 QName.create(importedModule.getQNameModule(), "my-cont-a"));
53         assertNotNull(myContA);
54
55         assertEquals(1, myContA.getChildNodes().size());
56         assertNotNull(myContA.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-a3")));
57
58         final ContainerSchemaNode myContB = (ContainerSchemaNode) importedModule.getDataChildByName(
59                 QName.create(importedModule.getQNameModule(), "my-cont-b"));
60         assertNull(myContB);
61
62         final ContainerSchemaNode myContC = (ContainerSchemaNode) importedModule.getDataChildByName(
63                 QName.create(importedModule.getQNameModule(), "my-cont-c"));
64         assertNotNull(myContC);
65
66         assertEquals(2, myContC.getChildNodes().size());
67         assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c1")));
68         assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c2")));
69     }
70
71     @Test
72     public void testDeviateAdd() throws Exception {
73         final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
74                 sourceForResource("/deviation-resolution-test/deviation-add/foo.yang"),
75                 sourceForResource("/deviation-resolution-test/deviation-add/bar.yang"));
76         assertNotNull(schemaContext);
77
78         final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
79         final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
80                 QName.create(barModule.getQNameModule(), "my-leaf-list"));
81         assertNotNull(myLeafList);
82
83         assertFalse(myLeafList.isConfiguration());
84         assertEquals(3, myLeafList.getDefaults().size());
85
86         final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
87         assertEquals(10, constraint.getMaxElements().intValue());
88         assertEquals(5, constraint.getMinElements().intValue());
89         assertNotNull(myLeafList.getType().getUnits());
90
91         final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
92                 QName.create(barModule.getQNameModule(), "my-list"));
93         assertNotNull(myList);
94         assertEquals(2, myList.getUniqueConstraints().size());
95
96         final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
97                 QName.create(barModule.getQNameModule(), "my-choice"));
98         assertNotNull(myChoice);
99         assertEquals("c2", myChoice.getDefaultCase().get().getQName().getLocalName());
100
101         final RpcDefinition myRpc = barModule.getRpcs().iterator().next();
102         final ContainerSchemaNode input = myRpc.getInput();
103         assertEquals(2, input.getMustConstraints().size());
104         final ContainerSchemaNode output = myRpc.getOutput();
105         assertEquals(2, output.getMustConstraints().size());
106
107         final NotificationDefinition myNotification = barModule.getNotifications().iterator().next();
108         assertEquals(2, myNotification.getMustConstraints().size());
109
110         final AnyxmlSchemaNode myAnyxml = (AnyxmlSchemaNode) barModule.getDataChildByName(
111                 QName.create(barModule.getQNameModule(), "my-anyxml"));
112         assertNotNull(myAnyxml);
113         assertTrue(myAnyxml.isMandatory());
114         assertEquals(2, myAnyxml.getUnknownSchemaNodes().size());
115
116         final AnydataSchemaNode myAnyData = (AnydataSchemaNode) barModule.findDataChildByName(
117                 QName.create(barModule.getQNameModule(), "my-anydata")).orElse(null);
118         assertNotNull(myAnyData);
119         assertTrue(myAnyData.isMandatory());
120         assertEquals(2, myAnyData.getUnknownSchemaNodes().size());
121     }
122
123     @Test
124     public void testDeviateReplace() throws Exception {
125         final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
126                 sourceForResource("/deviation-resolution-test/deviation-replace/foo.yang"),
127                 sourceForResource("/deviation-resolution-test/deviation-replace/bar.yang"));
128         assertNotNull(schemaContext);
129
130         final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
131         assertNotNull(barModule);
132
133         final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
134                 QName.create(barModule.getQNameModule(), "my-leaf"));
135         assertNotNull(myLeaf);
136
137         assertTrue(myLeaf.getType() instanceof Uint32TypeDefinition);
138         assertEquals(Optional.of("bytes"), myLeaf.getType().getUnits());
139         assertEquals(Optional.of("10"), myLeaf.getType().getDefaultValue());
140
141         final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
142                 QName.create(barModule.getQNameModule(), "my-leaf-list-test"));
143         assertNotNull(myLeafList);
144
145         final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
146         assertEquals(6, constraint.getMaxElements().intValue());
147         assertEquals(3, constraint.getMinElements().intValue());
148         assertTrue(myLeafList.isConfiguration());
149
150         final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
151                 QName.create(barModule.getQNameModule(), "my-choice"));
152         assertNotNull(myChoice);
153
154         assertFalse(myChoice.isMandatory());
155         assertEquals(1, myChoice.getUnknownSchemaNodes().size());
156         assertEquals("new arg", myChoice.getUnknownSchemaNodes().iterator().next().getNodeParameter());
157
158         final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
159                 QName.create(barModule.getQNameModule(), "my-cont"));
160         assertNotNull(myCont);
161
162         final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
163                 QName.create(barModule.getQNameModule(), "my-aug-leaf"));
164         assertNotNull(myAugLeaf);
165         assertTrue(myAugLeaf.getType() instanceof Uint32TypeDefinition);
166         assertEquals(Optional.of("seconds"), myAugLeaf.getType().getUnits());
167         assertEquals(Optional.of("new-def-val"), myAugLeaf.getType().getDefaultValue());
168         assertEquals(1, myAugLeaf.getUnknownSchemaNodes().size());
169         assertEquals("new arg", myAugLeaf.getUnknownSchemaNodes().iterator().next().getNodeParameter());
170
171         final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
172                 QName.create(barModule.getQNameModule(), "my-used-leaf"));
173         assertNotNull(myUsedLeaf);
174         assertTrue(myUsedLeaf.getType() instanceof Uint32TypeDefinition);
175         assertEquals(Optional.of("weeks"), myUsedLeaf.getType().getUnits());
176         assertEquals(Optional.of("new-def-val"), myUsedLeaf.getType().getDefaultValue());
177         assertEquals(1, myUsedLeaf.getUnknownSchemaNodes().size());
178         assertEquals("new arg", myUsedLeaf.getUnknownSchemaNodes().iterator().next().getNodeParameter());
179     }
180
181     @Test
182     public void testDeviateDelete() throws Exception {
183         final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
184                 sourceForResource("/deviation-resolution-test/deviation-delete/foo.yang"),
185                 sourceForResource("/deviation-resolution-test/deviation-delete/bar.yang"));
186         assertNotNull(schemaContext);
187
188         final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
189         final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
190                 QName.create(barModule.getQNameModule(), "my-leaf"));
191         assertNotNull(myLeaf);
192
193         assertEquals(Optional.empty(), myLeaf.getType().getDefaultValue());
194         assertEquals(Optional.empty(), myLeaf.getType().getUnits());
195         assertEquals(0, myLeaf.getUnknownSchemaNodes().size());
196
197         final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
198                 QName.create(barModule.getQNameModule(), "my-leaf-list"));
199         assertNotNull(myLeafList);
200
201         assertEquals(0, myLeafList.getDefaults().size());
202         assertEquals(0, myLeafList.getMustConstraints().size());
203
204         final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
205                 QName.create(barModule.getQNameModule(), "my-list"));
206         assertNotNull(myList);
207
208         assertEquals(0, myList.getUniqueConstraints().size());
209         assertEquals(0, myList.getUnknownSchemaNodes().size());
210
211         final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
212                 QName.create(barModule.getQNameModule(), "my-cont"));
213         assertNotNull(myCont);
214
215         final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
216                 QName.create(barModule.getQNameModule(), "my-aug-leaf"));
217         assertNotNull(myAugLeaf);
218         assertEquals(Optional.empty(), myAugLeaf.getType().getDefaultValue());
219         assertEquals(Optional.empty(), myAugLeaf.getType().getUnits());
220         assertEquals(0, myAugLeaf.getMustConstraints().size());
221         assertEquals(0, myAugLeaf.getUnknownSchemaNodes().size());
222
223         final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
224                 QName.create(barModule.getQNameModule(), "my-used-leaf"));
225         assertNotNull(myUsedLeaf);
226         assertEquals(Optional.empty(), myUsedLeaf.getType().getDefaultValue());
227         assertEquals(Optional.empty(), myUsedLeaf.getType().getUnits());
228         assertEquals(0, myUsedLeaf.getMustConstraints().size());
229         assertEquals(0, myUsedLeaf.getUnknownSchemaNodes().size());
230     }
231
232     @Test
233     public void shouldFailOnInvalidYang10Model() throws Exception {
234         try {
235             StmtTestUtils.parseYangSources(
236                     sourceForResource("/deviation-resolution-test/deviation-add/foo10-invalid.yang"),
237                     sourceForResource("/deviation-resolution-test/deviation-add/bar10-invalid.yang"));
238             fail("An exception should have been thrown.");
239         } catch (final ReactorException ex) {
240             final Throwable cause = ex.getCause();
241             assertTrue(cause instanceof InvalidSubstatementException);
242             assertTrue(cause.getMessage().startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."));
243         }
244     }
245
246     @Test
247     public void shouldFailOnInvalidYang10Model2() throws Exception {
248         try {
249             StmtTestUtils.parseYangSources(
250                     sourceForResource("/deviation-resolution-test/deviation-delete/foo10-invalid.yang"),
251                     sourceForResource("/deviation-resolution-test/deviation-delete/bar10-invalid.yang"));
252             fail("An exception should have been thrown.");
253         } catch (final ReactorException ex) {
254             final Throwable cause = ex.getCause();
255             assertTrue(cause instanceof InvalidSubstatementException);
256             assertTrue(cause.getMessage().startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."));
257         }
258     }
259
260     @Test
261     public void shouldFailOnInvalidDeviationTarget() throws Exception {
262         try {
263             StmtTestUtils.parseYangSources(sourceForResource(
264                     "/deviation-resolution-test/foo-invalid-deviation-target.yang"),
265                     sourceForResource("/deviation-resolution-test/bar.yang"));
266             fail("An exception should have been thrown.");
267         } catch (final ReactorException ex) {
268             final Throwable cause = ex.getCause();
269             assertTrue(cause instanceof InferenceException);
270             assertTrue(cause.getMessage().startsWith("(bar?revision=2017-01-20)my-cont is not a valid deviation "
271                     + "target for substatement (urn:ietf:params:xml:ns:yang:yin:1)max-elements."));
272         }
273     }
274
275     @Test
276     public void shouldFailOnInvalidDeviationPath() throws Exception {
277         try {
278             StmtTestUtils.parseYangSources(
279                     sourceForResource("/deviation-resolution-test/foo-invalid-deviation-path.yang"),
280                     sourceForResource("/deviation-resolution-test/bar.yang"));
281             fail("An exception should have been thrown.");
282         } catch (final ReactorException ex) {
283             final Throwable cause = ex.getCause().getCause();
284             assertTrue(cause instanceof InferenceException);
285             assertTrue(cause.getMessage().startsWith("Deviation target 'Absolute{path=[(bar?revision=2017-01-20)"
286                     + "invalid, (bar?revision=2017-01-20)path]}' not found"));
287         }
288     }
289
290     @Test
291     public void shouldFailOnInvalidDeviateAdd() throws Exception {
292         try {
293             StmtTestUtils.parseYangSources(
294                     sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid.yang"),
295                     sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid.yang"));
296             fail("An exception should have been thrown.");
297         } catch (final ReactorException ex) {
298             final Throwable cause = ex.getCause();
299             assertTrue(cause instanceof InferenceException);
300             assertTrue(cause.getMessage().startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
301                     + ":yin:1)config to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
302                     + " target and can appear only once."));
303         }
304     }
305
306     @Test
307     public void shouldFailOnInvalidDeviateAdd2() throws Exception {
308         try {
309             StmtTestUtils.parseYangSources(
310                     sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid-2.yang"),
311                     sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid-2.yang"));
312             fail("An exception should have been thrown.");
313         } catch (final ReactorException ex) {
314             final Throwable cause = ex.getCause();
315             assertTrue(cause instanceof InferenceException);
316             assertTrue(cause.getMessage().startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
317                     + ":yin:1)default to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
318                     + " target and can appear only once."));
319         }
320     }
321
322     @Test
323     public void shouldFailOnInvalidDeviateAdd3() throws Exception {
324         try {
325             StmtTestUtils.parseYangSources(
326                     sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid-4.yang"),
327                     sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid-4.yang"));
328             fail("An exception should have been thrown.");
329         } catch (final ReactorException ex) {
330             final Throwable cause = ex.getCause();
331             assertTrue(cause instanceof InferenceException);
332             assertTrue(cause.getMessage().startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
333                     + ":yin:1)default to target node (bar?revision=2017-02-01)my-used-leaf because it is already "
334                     + "defined in target and can appear only once."));
335         }
336     }
337
338     @Test
339     public void shouldFailOnInvalidDeviateReplace() throws Exception {
340         try {
341             StmtTestUtils.parseYangSources(
342                     sourceForResource("/deviation-resolution-test/deviation-replace/foo-invalid.yang"),
343                     sourceForResource("/deviation-resolution-test/deviation-replace/bar-invalid.yang"));
344             fail("An exception should have been thrown.");
345         } catch (final ReactorException ex) {
346             final Throwable cause = ex.getCause();
347             assertTrue(cause instanceof InferenceException);
348             assertTrue(cause.getMessage().startsWith("Deviation cannot replace substatement "
349                     + "(urn:ietf:params:xml:ns:yang:yin:1)units in target node (bar?revision=2017-01-20)my-leaf "
350                     + "because it does not exist in target node."));
351         }
352     }
353
354     @Test
355     @SuppressWarnings("checkstyle:regexpSinglelineJava")
356     public void shouldLogInvalidDeviateReplaceAttempt() throws Exception {
357         final PrintStream stdout = System.out;
358         final ByteArrayOutputStream output = new ByteArrayOutputStream();
359         final String testLog;
360
361         System.setOut(new PrintStream(output, true, "UTF-8"));
362
363         StmtTestUtils.parseYangSources(
364                 sourceForResource("/deviation-resolution-test/deviation-replace/foo-invalid-2.yang"),
365                 sourceForResource("/deviation-resolution-test/deviation-replace/bar-invalid-2.yang"));
366
367         testLog = output.toString();
368         System.setOut(stdout);
369         assertTrue(testLog.contains("Deviation cannot replace substatement (urn:ietf:params:xml:ns:yang:yin:1)default"
370                 + " in target leaf-list (bar?revision=2017-01-20)my-leaf-list because a leaf-list can have multiple "
371                 + "default statements."));
372     }
373
374     @Test
375     @SuppressWarnings("checkstyle:regexpSinglelineJava")
376     public void shouldLogInvalidDeviateDeleteAttempt() throws Exception {
377         final PrintStream stdout = System.out;
378         final ByteArrayOutputStream output = new ByteArrayOutputStream();
379         final String testLog;
380
381         System.setOut(new PrintStream(output, true, "UTF-8"));
382
383         StmtTestUtils.parseYangSources(
384                 sourceForResource("/deviation-resolution-test/deviation-delete/foo-invalid.yang"),
385                 sourceForResource("/deviation-resolution-test/deviation-delete/bar-invalid.yang"));
386
387         testLog = output.toString();
388         System.setOut(stdout);
389         assertTrue(testLog.contains("Deviation cannot delete substatement (urn:ietf:params:xml:ns:yang:yin:1)units "
390                 + "with argument 'seconds' in target node (bar?revision=2017-01-20)my-leaf because it does not exist "
391                 + "in the target node."));
392     }
393
394     @Test
395     public void shouldFailOnInvalidDeviateAddSubstatement() throws Exception {
396         try {
397             StmtTestUtils.parseYangSources(
398                     sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid-3.yang"),
399                     sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid-3.yang"));
400             fail("An exception should have been thrown.");
401         } catch (final ReactorException ex) {
402             final Throwable cause = ex.getCause();
403             assertTrue(cause instanceof InvalidSubstatementException);
404             assertTrue(cause.getMessage().startsWith("TYPE is not valid for DEVIATE."));
405         }
406     }
407
408     @Test
409     public void shouldFailOnInvalidDeviateReplaceSubstatement() throws Exception {
410         try {
411             StmtTestUtils.parseYangSources(
412                     sourceForResource("/deviation-resolution-test/deviation-replace/foo-invalid-3.yang"),
413                     sourceForResource("/deviation-resolution-test/deviation-replace/bar-invalid-3.yang"));
414             fail("An exception should have been thrown.");
415         } catch (final ReactorException ex) {
416             final Throwable cause = ex.getCause();
417             assertTrue(cause instanceof InvalidSubstatementException);
418             assertTrue(cause.getMessage().startsWith("MUST is not valid for DEVIATE."));
419         }
420     }
421
422     @Test
423     public void shouldFailOnInvalidDeviateDeleteSubstatement() throws Exception {
424         try {
425             StmtTestUtils.parseYangSources(
426                     sourceForResource("/deviation-resolution-test/deviation-delete/foo-invalid-2.yang"),
427                     sourceForResource("/deviation-resolution-test/deviation-delete/bar-invalid-2.yang"));
428             fail("An exception should have been thrown.");
429         } catch (final ReactorException ex) {
430             final Throwable cause = ex.getCause();
431             assertTrue(cause instanceof InvalidSubstatementException);
432             assertTrue(cause.getMessage().startsWith("CONFIG is not valid for DEVIATE."));
433         }
434     }
435 }