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