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