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.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;
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.InputSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.Module;
39 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
40 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.InvalidSubstatementException;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
48 public class DeviationResolutionTest {
51 public void testDeviateNotSupported() throws Exception {
52 final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
53 "/deviation-resolution-test/deviation-not-supported");
54 assertNotNull(schemaContext);
56 final Module importedModule = schemaContext.findModule("imported", Revision.of("2017-01-20")).get();
57 final ContainerSchemaNode myContA = (ContainerSchemaNode) importedModule.getDataChildByName(
58 QName.create(importedModule.getQNameModule(), "my-cont-a"));
59 assertNotNull(myContA);
61 assertEquals(1, myContA.getChildNodes().size());
62 assertNotNull(myContA.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-a3")));
64 final ContainerSchemaNode myContB = (ContainerSchemaNode) importedModule.getDataChildByName(
65 QName.create(importedModule.getQNameModule(), "my-cont-b"));
68 final ContainerSchemaNode myContC = (ContainerSchemaNode) importedModule.getDataChildByName(
69 QName.create(importedModule.getQNameModule(), "my-cont-c"));
70 assertNotNull(myContC);
72 assertEquals(2, myContC.getChildNodes().size());
73 assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c1")));
74 assertNotNull(myContC.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-c2")));
78 public void testDeviateAdd() throws ReactorException {
79 final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
80 sourceForResource("/deviation-resolution-test/deviation-add/foo.yang"),
81 sourceForResource("/deviation-resolution-test/deviation-add/bar.yang"));
82 assertNotNull(schemaContext);
84 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
85 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
86 QName.create(barModule.getQNameModule(), "my-leaf-list"));
87 assertNotNull(myLeafList);
89 assertEquals(Optional.of(Boolean.FALSE), myLeafList.effectiveConfig());
90 assertEquals(3, myLeafList.getDefaults().size());
92 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
93 assertEquals((Object) 10, constraint.getMaxElements());
94 assertEquals((Object) 5, constraint.getMinElements());
95 assertNotNull(myLeafList.getType().getUnits());
97 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
98 QName.create(barModule.getQNameModule(), "my-list"));
99 assertNotNull(myList);
100 assertEquals(2, myList.getUniqueConstraints().size());
102 final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
103 QName.create(barModule.getQNameModule(), "my-choice"));
104 assertNotNull(myChoice);
105 assertEquals("c2", myChoice.getDefaultCase().get().getQName().getLocalName());
107 final RpcDefinition myRpc = barModule.getRpcs().iterator().next();
108 final InputSchemaNode input = myRpc.getInput();
109 assertEquals(2, input.getMustConstraints().size());
110 final OutputSchemaNode output = myRpc.getOutput();
111 assertEquals(2, output.getMustConstraints().size());
113 final NotificationDefinition myNotification = barModule.getNotifications().iterator().next();
114 assertEquals(2, myNotification.getMustConstraints().size());
116 final AnyxmlSchemaNode myAnyxml = (AnyxmlSchemaNode) barModule.getDataChildByName(
117 QName.create(barModule.getQNameModule(), "my-anyxml"));
118 assertNotNull(myAnyxml);
119 assertTrue(myAnyxml.isMandatory());
120 assertEquals(2, myAnyxml.getUnknownSchemaNodes().size());
122 final AnydataSchemaNode myAnyData = (AnydataSchemaNode) barModule.findDataChildByName(
123 QName.create(barModule.getQNameModule(), "my-anydata")).orElse(null);
124 assertNotNull(myAnyData);
125 assertTrue(myAnyData.isMandatory());
126 assertEquals(2, myAnyData.getUnknownSchemaNodes().size());
130 public void testDeviateReplace() throws ReactorException {
131 final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
132 sourceForResource("/deviation-resolution-test/deviation-replace/foo.yang"),
133 sourceForResource("/deviation-resolution-test/deviation-replace/bar.yang"));
134 assertNotNull(schemaContext);
136 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
137 assertNotNull(barModule);
139 final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
140 QName.create(barModule.getQNameModule(), "my-leaf"));
141 assertNotNull(myLeaf);
143 assertThat(myLeaf.getType(), instanceOf(Uint32TypeDefinition.class));
144 assertEquals(Optional.of("bytes"), myLeaf.getType().getUnits());
145 assertEquals(Optional.of("10"), myLeaf.getType().getDefaultValue());
147 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
148 QName.create(barModule.getQNameModule(), "my-leaf-list-test"));
149 assertNotNull(myLeafList);
151 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
152 assertEquals((Object) 6, constraint.getMaxElements());
153 assertEquals((Object) 3, constraint.getMinElements());
154 assertEquals(Optional.of(Boolean.TRUE), myLeafList.effectiveConfig());
156 final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
157 QName.create(barModule.getQNameModule(), "my-choice"));
158 assertNotNull(myChoice);
160 assertFalse(myChoice.isMandatory());
161 assertEquals(1, myChoice.getUnknownSchemaNodes().size());
162 assertEquals("new arg", myChoice.getUnknownSchemaNodes().iterator().next().getNodeParameter());
164 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
165 QName.create(barModule.getQNameModule(), "my-cont"));
166 assertNotNull(myCont);
168 final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
169 QName.create(barModule.getQNameModule(), "my-aug-leaf"));
170 assertNotNull(myAugLeaf);
171 assertThat(myAugLeaf.getType(), instanceOf(Uint32TypeDefinition.class));
172 assertEquals(Optional.of("seconds"), myAugLeaf.getType().getUnits());
173 assertEquals(Optional.of("new-def-val"), myAugLeaf.getType().getDefaultValue());
174 assertEquals(1, myAugLeaf.getUnknownSchemaNodes().size());
175 assertEquals("new arg", myAugLeaf.getUnknownSchemaNodes().iterator().next().getNodeParameter());
177 final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
178 QName.create(barModule.getQNameModule(), "my-used-leaf"));
179 assertNotNull(myUsedLeaf);
180 assertThat(myUsedLeaf.getType(), instanceOf(Uint32TypeDefinition.class));
181 assertEquals(Optional.of("weeks"), myUsedLeaf.getType().getUnits());
182 assertEquals(Optional.of("new-def-val"), myUsedLeaf.getType().getDefaultValue());
183 assertEquals(1, myUsedLeaf.getUnknownSchemaNodes().size());
184 assertEquals("new arg", myUsedLeaf.getUnknownSchemaNodes().iterator().next().getNodeParameter());
188 public void testDeviateDelete() throws ReactorException {
189 final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
190 sourceForResource("/deviation-resolution-test/deviation-delete/foo.yang"),
191 sourceForResource("/deviation-resolution-test/deviation-delete/bar.yang"));
192 assertNotNull(schemaContext);
194 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
195 final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
196 QName.create(barModule.getQNameModule(), "my-leaf"));
197 assertNotNull(myLeaf);
199 assertEquals(Optional.empty(), myLeaf.getType().getDefaultValue());
200 assertEquals(Optional.empty(), myLeaf.getType().getUnits());
201 assertEquals(0, myLeaf.getUnknownSchemaNodes().size());
203 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
204 QName.create(barModule.getQNameModule(), "my-leaf-list"));
205 assertNotNull(myLeafList);
207 assertEquals(0, myLeafList.getDefaults().size());
208 assertEquals(0, myLeafList.getMustConstraints().size());
210 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
211 QName.create(barModule.getQNameModule(), "my-list"));
212 assertNotNull(myList);
214 assertEquals(0, myList.getUniqueConstraints().size());
215 assertEquals(0, myList.getUnknownSchemaNodes().size());
217 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
218 QName.create(barModule.getQNameModule(), "my-cont"));
219 assertNotNull(myCont);
221 final LeafSchemaNode myAugLeaf = (LeafSchemaNode) myCont.getDataChildByName(
222 QName.create(barModule.getQNameModule(), "my-aug-leaf"));
223 assertNotNull(myAugLeaf);
224 assertEquals(Optional.empty(), myAugLeaf.getType().getDefaultValue());
225 assertEquals(Optional.empty(), myAugLeaf.getType().getUnits());
226 assertEquals(0, myAugLeaf.getMustConstraints().size());
227 assertEquals(0, myAugLeaf.getUnknownSchemaNodes().size());
229 final LeafSchemaNode myUsedLeaf = (LeafSchemaNode) myCont.getDataChildByName(
230 QName.create(barModule.getQNameModule(), "my-used-leaf"));
231 assertNotNull(myUsedLeaf);
232 assertEquals(Optional.empty(), myUsedLeaf.getType().getDefaultValue());
233 assertEquals(Optional.empty(), myUsedLeaf.getType().getUnits());
234 assertEquals(0, myUsedLeaf.getMustConstraints().size());
235 assertEquals(0, myUsedLeaf.getUnknownSchemaNodes().size());
239 public void shouldFailOnInvalidYang10Model() {
240 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
241 sourceForResource("/deviation-resolution-test/deviation-add/foo10-invalid.yang"),
242 sourceForResource("/deviation-resolution-test/deviation-add/bar10-invalid.yang")));
243 final Throwable cause = ex.getCause();
244 assertThat(cause, instanceOf(InvalidSubstatementException.class));
245 assertThat(cause.getMessage(), startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."));
249 public void shouldFailOnInvalidYang10Model2() {
250 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
251 sourceForResource("/deviation-resolution-test/deviation-delete/foo10-invalid.yang"),
252 sourceForResource("/deviation-resolution-test/deviation-delete/bar10-invalid.yang")));
253 final Throwable cause = ex.getCause();
254 assertThat(cause, instanceOf(InvalidSubstatementException.class));
255 assertThat(cause.getMessage(), startsWith("Maximal count of DEFAULT for DEVIATE is 1, detected 2."));
259 public void shouldFailOnInvalidDeviationTarget() {
260 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
261 sourceForResource("/deviation-resolution-test/foo-invalid-deviation-target.yang"),
262 sourceForResource("/deviation-resolution-test/bar.yang")));
263 final Throwable cause = ex.getCause();
264 assertThat(cause, instanceOf(InferenceException.class));
265 assertThat(cause.getMessage(), startsWith("(bar?revision=2017-01-20)my-cont is not a valid deviation "
266 + "target for substatement (urn:ietf:params:xml:ns:yang:yin:1)max-elements."));
270 public void shouldFailOnInvalidDeviationPath() {
271 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
272 sourceForResource("/deviation-resolution-test/foo-invalid-deviation-path.yang"),
273 sourceForResource("/deviation-resolution-test/bar.yang")));
274 final Throwable cause = ex.getCause().getCause();
275 assertThat(cause, instanceOf(InferenceException.class));
276 assertThat(cause.getMessage(), startsWith(
277 "Deviation target 'Absolute{qnames=[(bar?revision=2017-01-20)invalid, path]}' not found"));
281 public void shouldFailOnInvalidDeviateAdd() {
282 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
283 sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid.yang"),
284 sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid.yang")));
285 final Throwable cause = ex.getCause();
286 assertThat(cause, instanceOf(InferenceException.class));
287 assertThat(cause.getMessage(), startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
288 + ":yin:1)config to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
289 + " target and can appear only once."));
293 public void shouldFailOnInvalidDeviateAdd2() {
294 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
295 sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid-2.yang"),
296 sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid-2.yang")));
297 final Throwable cause = ex.getCause();
298 assertThat(cause, instanceOf(InferenceException.class));
299 assertThat(cause.getMessage(), startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
300 + ":yin:1)default to target node (bar?revision=2017-01-20)my-leaf because it is already defined in"
301 + " target and can appear only once."));
305 public void shouldFailOnInvalidDeviateAdd3() {
306 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
307 sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid-4.yang"),
308 sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid-4.yang")));
309 final Throwable cause = ex.getCause();
310 assertThat(cause, instanceOf(InferenceException.class));
311 assertThat(cause.getMessage(), startsWith("Deviation cannot add substatement (urn:ietf:params:xml:ns:yang"
312 + ":yin:1)default to target node (bar?revision=2017-02-01)my-used-leaf because it is already "
313 + "defined in target and can appear only once."));
317 public void shouldFailOnInvalidDeviateReplace() {
318 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
319 sourceForResource("/deviation-resolution-test/deviation-replace/foo-invalid.yang"),
320 sourceForResource("/deviation-resolution-test/deviation-replace/bar-invalid.yang")));
321 final Throwable cause = ex.getCause();
322 assertThat(cause, instanceOf(InferenceException.class));
323 assertThat(cause.getMessage(), startsWith("Deviation cannot replace substatement "
324 + "(urn:ietf:params:xml:ns:yang:yin:1)units in target node (bar?revision=2017-01-20)my-leaf "
325 + "because it does not exist in target node."));
329 @SuppressWarnings("checkstyle:regexpSinglelineJava")
330 public void shouldLogInvalidDeviateReplaceAttempt() throws ReactorException {
331 final PrintStream stdout = System.out;
332 final ByteArrayOutputStream output = new ByteArrayOutputStream();
333 final String testLog;
335 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
337 StmtTestUtils.parseYangSources(
338 sourceForResource("/deviation-resolution-test/deviation-replace/foo-invalid-2.yang"),
339 sourceForResource("/deviation-resolution-test/deviation-replace/bar-invalid-2.yang"));
341 testLog = output.toString();
342 System.setOut(stdout);
343 assertThat(testLog, containsString(
344 "Deviation cannot replace substatement (urn:ietf:params:xml:ns:yang:yin:1)default in target leaf-list "
345 + "(bar?revision=2017-01-20)my-leaf-list because a leaf-list can have multiple "
346 + "default statements."));
350 @SuppressWarnings("checkstyle:regexpSinglelineJava")
351 public void shouldLogInvalidDeviateDeleteAttempt() throws ReactorException {
352 final PrintStream stdout = System.out;
353 final ByteArrayOutputStream output = new ByteArrayOutputStream();
354 final String testLog;
356 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
358 StmtTestUtils.parseYangSources(
359 sourceForResource("/deviation-resolution-test/deviation-delete/foo-invalid.yang"),
360 sourceForResource("/deviation-resolution-test/deviation-delete/bar-invalid.yang"));
362 testLog = output.toString();
363 System.setOut(stdout);
364 assertThat(testLog, containsString(
365 "Deviation cannot delete substatement (urn:ietf:params:xml:ns:yang:yin:1)units with argument 'seconds' in "
366 + "target node (bar?revision=2017-01-20)my-leaf because it does not exist in the target node."));
370 public void shouldFailOnInvalidDeviateAddSubstatement() {
371 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
372 sourceForResource("/deviation-resolution-test/deviation-add/foo-invalid-3.yang"),
373 sourceForResource("/deviation-resolution-test/deviation-add/bar-invalid-3.yang")));
374 final Throwable cause = ex.getCause();
375 assertThat(cause, instanceOf(InvalidSubstatementException.class));
376 assertThat(cause.getMessage(), startsWith("TYPE is not valid for DEVIATE."));
380 public void shouldFailOnInvalidDeviateReplaceSubstatement() {
381 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
382 sourceForResource("/deviation-resolution-test/deviation-replace/foo-invalid-3.yang"),
383 sourceForResource("/deviation-resolution-test/deviation-replace/bar-invalid-3.yang")));
384 final Throwable cause = ex.getCause();
385 assertThat(cause, instanceOf(InvalidSubstatementException.class));
386 assertThat(cause.getMessage(), startsWith("MUST is not valid for DEVIATE."));
390 public void shouldFailOnInvalidDeviateDeleteSubstatement() throws Exception {
391 final ReactorException ex = assertThrows(ReactorException.class, () -> StmtTestUtils.parseYangSources(
392 sourceForResource("/deviation-resolution-test/deviation-delete/foo-invalid-2.yang"),
393 sourceForResource("/deviation-resolution-test/deviation-delete/bar-invalid-2.yang")));
394 final Throwable cause = ex.getCause();
395 assertThat(cause, instanceOf(InvalidSubstatementException.class));
396 assertThat(cause.getMessage(), startsWith("CONFIG is not valid for DEVIATE."));