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