2 * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.stmt;
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.startsWith;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.jupiter.api.Assertions.assertEquals;
14 import static org.junit.jupiter.api.Assertions.assertFalse;
15 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
16 import static org.junit.jupiter.api.Assertions.assertNotNull;
17 import static org.junit.jupiter.api.Assertions.assertNull;
18 import static org.junit.jupiter.api.Assertions.assertTrue;
20 import java.io.ByteArrayOutputStream;
21 import java.io.PrintStream;
22 import java.nio.charset.StandardCharsets;
23 import java.util.Optional;
24 import org.junit.jupiter.api.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.InputSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.Module;
37 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
38 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
42 class DeviationResolutionTest extends AbstractYangTest {
44 void testDeviateNotSupported() {
45 final var schemaContext = assertEffectiveModelDir("/deviation-resolution-test/deviation-not-supported");
46 assertNotNull(schemaContext);
48 final Module importedModule = schemaContext.findModule("imported", Revision.of("2017-01-20")).get();
49 final ContainerSchemaNode myContA = (ContainerSchemaNode) importedModule.getDataChildByName(
50 QName.create(importedModule.getQNameModule(), "my-cont-a"));
51 assertNotNull(myContA);
53 assertEquals(1, myContA.getChildNodes().size());
54 assertNotNull(myContA.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-a3")));
56 final ContainerSchemaNode myContB = (ContainerSchemaNode) importedModule.dataChildByName(
57 QName.create(importedModule.getQNameModule(), "my-cont-b"));
60 final ContainerSchemaNode myContC = (ContainerSchemaNode) importedModule.getDataChildByName(
61 QName.create(importedModule.getQNameModule(), "my-cont-c"));
62 assertNotNull(myContC);
64 assertEquals(2, myContC.getChildNodes().size());
65 assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c1")));
66 assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c2")));
70 void testDeviateAdd() {
71 final var schemaContext = assertEffectiveModel(
72 "/deviation-resolution-test/deviation-add/foo.yang",
73 "/deviation-resolution-test/deviation-add/bar.yang");
75 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
76 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
77 QName.create(barModule.getQNameModule(), "my-leaf-list"));
78 assertNotNull(myLeafList);
80 assertEquals(Optional.of(Boolean.FALSE), myLeafList.effectiveConfig());
81 assertEquals(3, myLeafList.getDefaults().size());
83 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
84 assertEquals((Object) 10, constraint.getMaxElements());
85 assertEquals((Object) 5, constraint.getMinElements());
86 assertNotNull(myLeafList.getType().getUnits());
88 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
89 QName.create(barModule.getQNameModule(), "my-list"));
90 assertNotNull(myList);
91 assertEquals(2, myList.getUniqueConstraints().size());
93 final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
94 QName.create(barModule.getQNameModule(), "my-choice"));
95 assertNotNull(myChoice);
96 assertEquals("c2", myChoice.getDefaultCase().get().getQName().getLocalName());
98 final RpcDefinition myRpc = barModule.getRpcs().iterator().next();
99 final InputSchemaNode input = myRpc.getInput();
100 assertEquals(2, input.getMustConstraints().size());
101 final OutputSchemaNode output = myRpc.getOutput();
102 assertEquals(2, output.getMustConstraints().size());
104 final NotificationDefinition myNotification = barModule.getNotifications().iterator().next();
105 assertEquals(2, myNotification.getMustConstraints().size());
107 final AnyxmlSchemaNode myAnyxml = (AnyxmlSchemaNode) barModule.getDataChildByName(
108 QName.create(barModule.getQNameModule(), "my-anyxml"));
109 assertNotNull(myAnyxml);
110 assertTrue(myAnyxml.isMandatory());
112 final AnydataSchemaNode myAnyData = (AnydataSchemaNode) barModule.findDataChildByName(
113 QName.create(barModule.getQNameModule(), "my-anydata")).orElse(null);
114 assertNotNull(myAnyData);
115 assertTrue(myAnyData.isMandatory());
119 void testDeviateReplace() throws Exception {
120 final var schemaContext = assertEffectiveModel(
121 "/deviation-resolution-test/deviation-replace/foo.yang",
122 "/deviation-resolution-test/deviation-replace/bar.yang");
124 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
125 assertNotNull(barModule);
127 final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
128 QName.create(barModule.getQNameModule(), "my-leaf"));
129 assertNotNull(myLeaf);
131 assertInstanceOf(Uint32TypeDefinition.class, myLeaf.getType());
132 assertEquals(Optional.of("bytes"), myLeaf.getType().getUnits());
133 assertEquals(Optional.of("10"), myLeaf.getType().getDefaultValue());
135 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
136 QName.create(barModule.getQNameModule(), "my-leaf-list-test"));
137 assertNotNull(myLeafList);
139 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
140 assertEquals((Object) 6, constraint.getMaxElements());
141 assertEquals((Object) 3, constraint.getMinElements());
142 assertEquals(Optional.of(Boolean.TRUE), myLeafList.effectiveConfig());
144 final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
145 QName.create(barModule.getQNameModule(), "my-choice"));
146 assertNotNull(myChoice);
148 assertFalse(myChoice.isMandatory());
149 // FIXME: we need a supported extension to properly test this
150 assertEquals(0, myChoice.getUnknownSchemaNodes().size());
152 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
153 QName.create(barModule.getQNameModule(), "my-cont"));
154 assertNotNull(myCont);
156 final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
157 QName.create(barModule.getQNameModule(), "my-aug-leaf"));
158 assertNotNull(myAugLeaf);
159 assertInstanceOf(Uint32TypeDefinition.class, myAugLeaf.getType());
160 assertEquals(Optional.of("seconds"), myAugLeaf.getType().getUnits());
161 assertEquals(Optional.of("new-def-val"), myAugLeaf.getType().getDefaultValue());
162 // FIXME: we need a supported extension to properly test this
163 assertEquals(0, myAugLeaf.getUnknownSchemaNodes().size());
165 final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
166 QName.create(barModule.getQNameModule(), "my-used-leaf"));
167 assertNotNull(myUsedLeaf);
168 assertInstanceOf(Uint32TypeDefinition.class, myUsedLeaf.getType());
169 assertEquals(Optional.of("weeks"), myUsedLeaf.getType().getUnits());
170 assertEquals(Optional.of("new-def-val"), myUsedLeaf.getType().getDefaultValue());
171 // FIXME: we need a supported extension to properly test this
172 assertEquals(0, myUsedLeaf.getUnknownSchemaNodes().size());
176 void testDeviateDelete() throws Exception {
177 final var schemaContext = assertEffectiveModel(
178 "/deviation-resolution-test/deviation-delete/foo.yang",
179 "/deviation-resolution-test/deviation-delete/bar.yang");
181 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
182 final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
183 QName.create(barModule.getQNameModule(), "my-leaf"));
184 assertNotNull(myLeaf);
186 assertEquals(Optional.empty(), myLeaf.getType().getDefaultValue());
187 assertEquals(Optional.empty(), myLeaf.getType().getUnits());
188 assertEquals(0, myLeaf.getUnknownSchemaNodes().size());
190 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
191 QName.create(barModule.getQNameModule(), "my-leaf-list"));
192 assertNotNull(myLeafList);
194 assertEquals(0, myLeafList.getDefaults().size());
195 assertEquals(0, myLeafList.getMustConstraints().size());
197 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
198 QName.create(barModule.getQNameModule(), "my-list"));
199 assertNotNull(myList);
201 assertEquals(0, myList.getUniqueConstraints().size());
202 assertEquals(0, myList.getUnknownSchemaNodes().size());
204 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
205 QName.create(barModule.getQNameModule(), "my-cont"));
206 assertNotNull(myCont);
208 final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
209 QName.create(barModule.getQNameModule(), "my-aug-leaf"));
210 assertNotNull(myAugLeaf);
211 assertEquals(Optional.empty(), myAugLeaf.getType().getDefaultValue());
212 assertEquals(Optional.empty(), myAugLeaf.getType().getUnits());
213 assertEquals(0, myAugLeaf.getMustConstraints().size());
214 assertEquals(0, myAugLeaf.getUnknownSchemaNodes().size());
216 final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
217 QName.create(barModule.getQNameModule(), "my-used-leaf"));
218 assertNotNull(myUsedLeaf);
219 assertEquals(Optional.empty(), myUsedLeaf.getType().getDefaultValue());
220 assertEquals(Optional.empty(), myUsedLeaf.getType().getUnits());
221 assertEquals(0, myUsedLeaf.getMustConstraints().size());
222 assertEquals(0, myUsedLeaf.getUnknownSchemaNodes().size());
226 void shouldFailOnInvalidYang10Model() {
227 assertInvalidSubstatementException(startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."),
228 "/deviation-resolution-test/deviation-add/foo10-invalid.yang",
229 "/deviation-resolution-test/deviation-add/bar10-invalid.yang");
233 void shouldFailOnInvalidYang10Model2() {
234 assertInvalidSubstatementException(startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."),
235 "/deviation-resolution-test/deviation-delete/foo10-invalid.yang",
236 "/deviation-resolution-test/deviation-delete/bar10-invalid.yang");
240 void shouldFailOnInvalidDeviationTarget() {
241 assertInferenceException(startsWith("(bar?revision=2017-01-20)my-cont is not a valid deviation "
242 + "target for substatement (urn:ietf:params:xml:ns:yang:yin:1)max-elements."),
243 "/deviation-resolution-test/foo-invalid-deviation-target.yang",
244 "/deviation-resolution-test/bar.yang");
248 void shouldFailOnInvalidDeviationPath() {
249 assertInferenceException(startsWith(
250 "Deviation target 'Absolute{qnames=[(bar?revision=2017-01-20)invalid, path]}' not found"),
251 "/deviation-resolution-test/foo-invalid-deviation-path.yang",
252 "/deviation-resolution-test/bar.yang");
256 void shouldFailOnInvalidDeviateAdd() {
257 assertInferenceException(startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
258 + ":yin:1)config to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
259 + " target and can appear only once."),
260 "/deviation-resolution-test/deviation-add/foo-invalid.yang",
261 "/deviation-resolution-test/deviation-add/bar-invalid.yang");
265 void shouldFailOnInvalidDeviateAdd2() {
266 assertInferenceException(startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
267 + ":yin:1)default to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
268 + " target and can appear only once."),
269 "/deviation-resolution-test/deviation-add/foo-invalid-2.yang",
270 "/deviation-resolution-test/deviation-add/bar-invalid-2.yang");
274 void shouldFailOnInvalidDeviateAdd3() {
275 assertInferenceException(startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
276 + ":yin:1)default to target node (bar?revision=2017-02-01)my-used-leaf because it is already "
277 + "defined in target and can appear only once."),
278 "/deviation-resolution-test/deviation-add/foo-invalid-4.yang",
279 "/deviation-resolution-test/deviation-add/bar-invalid-4.yang");
283 void shouldFailOnInvalidDeviateReplace() {
284 assertInferenceException(startsWith("Deviation cannot replace substatement "
285 + "(urn:ietf:params:xml:ns:yang:yin:1)units in target node (bar?revision=2017-01-20)my-leaf "
286 + "because it does not exist in target node."),
287 "/deviation-resolution-test/deviation-replace/foo-invalid.yang",
288 "/deviation-resolution-test/deviation-replace/bar-invalid.yang");
292 @SuppressWarnings("checkstyle:regexpSinglelineJava")
293 void shouldLogInvalidDeviateReplaceAttempt() throws Exception {
294 final PrintStream stdout = System.out;
295 final ByteArrayOutputStream output = new ByteArrayOutputStream();
296 final String testLog;
298 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
300 TestUtils.parseYangSource(
301 "/deviation-resolution-test/deviation-replace/foo-invalid-2.yang",
302 "/deviation-resolution-test/deviation-replace/bar-invalid-2.yang");
304 testLog = output.toString();
305 System.setOut(stdout);
306 assertThat(testLog, containsString(
307 "Deviation cannot replace substatement (urn:ietf:params:xml:ns:yang:yin:1)default in target leaf-list "
308 + "(bar?revision=2017-01-20)my-leaf-list because a leaf-list can have multiple "
309 + "default statements."));
313 @SuppressWarnings("checkstyle:regexpSinglelineJava")
314 void shouldLogInvalidDeviateDeleteAttempt() throws Exception {
315 final PrintStream stdout = System.out;
316 final ByteArrayOutputStream output = new ByteArrayOutputStream();
317 final String testLog;
319 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
321 TestUtils.parseYangSource(
322 "/deviation-resolution-test/deviation-delete/foo-invalid.yang",
323 "/deviation-resolution-test/deviation-delete/bar-invalid.yang");
325 testLog = output.toString();
326 System.setOut(stdout);
327 assertThat(testLog, containsString(
328 "Deviation cannot delete substatement (urn:ietf:params:xml:ns:yang:yin:1)units with argument 'seconds' in "
329 + "target node (bar?revision=2017-01-20)my-leaf because it does not exist in the target node."));
333 void shouldFailOnInvalidDeviateAddSubstatement() {
334 assertInvalidSubstatementException(startsWith("TYPE is not valid for DEVIATE."),
335 "/deviation-resolution-test/deviation-add/foo-invalid-3.yang",
336 "/deviation-resolution-test/deviation-add/bar-invalid-3.yang");
340 void shouldFailOnInvalidDeviateReplaceSubstatement() {
341 assertInvalidSubstatementException(startsWith("MUST is not valid for DEVIATE."),
342 "/deviation-resolution-test/deviation-replace/foo-invalid-3.yang",
343 "/deviation-resolution-test/deviation-replace/bar-invalid-3.yang");
347 void shouldFailOnInvalidDeviateDeleteSubstatement() {
348 assertInvalidSubstatementException(startsWith("CONFIG is not valid for DEVIATE."),
349 "/deviation-resolution-test/deviation-delete/foo-invalid-2.yang",
350 "/deviation-resolution-test/deviation-delete/bar-invalid-2.yang");