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
9 package org.opendaylight.yangtools.yang.stmt;
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;
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;
44 public class DeviationResolutionTest {
47 public void testDeviateNotSupported() throws Exception {
48 final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
49 "/deviation-resolution-test/deviation-not-supported");
50 assertNotNull(schemaContext);
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);
57 assertEquals(1, myContA.getChildNodes().size());
58 assertNotNull(myContA.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-a3")));
60 final ContainerSchemaNode myContB = (ContainerSchemaNode) importedModule.getDataChildByName(
61 QName.create(importedModule.getQNameModule(), "my-cont-b"));
64 final ContainerSchemaNode myContC = (ContainerSchemaNode) importedModule.getDataChildByName(
65 QName.create(importedModule.getQNameModule(), "my-cont-c"));
66 assertNotNull(myContC);
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")));
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);
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);
85 assertFalse(myLeafList.isConfiguration());
86 assertEquals(3, myLeafList.getDefaults().size());
88 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
89 assertEquals(10, constraint.getMaxElements().intValue());
90 assertEquals(5, constraint.getMinElements().intValue());
91 assertNotNull(myLeafList.getType().getUnits());
93 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
94 QName.create(barModule.getQNameModule(), "my-list"));
95 assertNotNull(myList);
96 assertEquals(2, myList.getUniqueConstraints().size());
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());
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());
109 final NotificationDefinition myNotification = barModule.getNotifications().iterator().next();
110 assertEquals(2, myNotification.getMustConstraints().size());
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());
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());
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);
132 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
133 assertNotNull(barModule);
135 final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
136 QName.create(barModule.getQNameModule(), "my-leaf"));
137 assertNotNull(myLeaf);
139 assertTrue(myLeaf.getType() instanceof Uint32TypeDefinition);
140 assertEquals(Optional.of("bytes"), myLeaf.getType().getUnits());
141 assertEquals(Optional.of("10"), myLeaf.getType().getDefaultValue());
143 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
144 QName.create(barModule.getQNameModule(), "my-leaf-list-test"));
145 assertNotNull(myLeafList);
147 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
148 assertEquals(6, constraint.getMaxElements().intValue());
149 assertEquals(3, constraint.getMinElements().intValue());
150 assertTrue(myLeafList.isConfiguration());
152 final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
153 QName.create(barModule.getQNameModule(), "my-choice"));
154 assertNotNull(myChoice);
156 assertFalse(myChoice.isMandatory());
157 assertEquals(1, myChoice.getUnknownSchemaNodes().size());
158 assertEquals("new arg", myChoice.getUnknownSchemaNodes().iterator().next().getNodeParameter());
160 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
161 QName.create(barModule.getQNameModule(), "my-cont"));
162 assertNotNull(myCont);
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());
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());
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);
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);
195 assertEquals(Optional.empty(), myLeaf.getType().getDefaultValue());
196 assertEquals(Optional.empty(), myLeaf.getType().getUnits());
197 assertEquals(0, myLeaf.getUnknownSchemaNodes().size());
199 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
200 QName.create(barModule.getQNameModule(), "my-leaf-list"));
201 assertNotNull(myLeafList);
203 assertEquals(0, myLeafList.getDefaults().size());
204 assertEquals(0, myLeafList.getMustConstraints().size());
206 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
207 QName.create(barModule.getQNameModule(), "my-list"));
208 assertNotNull(myList);
210 assertEquals(0, myList.getUniqueConstraints().size());
211 assertEquals(0, myList.getUnknownSchemaNodes().size());
213 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
214 QName.create(barModule.getQNameModule(), "my-cont"));
215 assertNotNull(myCont);
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());
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());
235 public void shouldFailOnInvalidYang10Model() throws Exception {
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."));
249 public void shouldFailOnInvalidYang10Model2() throws Exception {
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."));
263 public void shouldFailOnInvalidDeviationTarget() throws Exception {
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."));
278 public void shouldFailOnInvalidDeviationPath() throws Exception {
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"));
293 public void shouldFailOnInvalidDeviateAdd() throws Exception {
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."));
309 public void shouldFailOnInvalidDeviateAdd2() throws Exception {
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."));
325 public void shouldFailOnInvalidDeviateAdd3() throws Exception {
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."));
341 public void shouldFailOnInvalidDeviateReplace() throws Exception {
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."));
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;
363 System.setOut(new PrintStream(output, true, "UTF-8"));
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"));
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."));
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;
383 System.setOut(new PrintStream(output, true, "UTF-8"));
385 StmtTestUtils.parseYangSources(
386 sourceForResource("/deviation-resolution-test/deviation-delete/foo-invalid.yang"),
387 sourceForResource("/deviation-resolution-test/deviation-delete/bar-invalid.yang"));
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."));
397 public void shouldFailOnInvalidDeviateAddSubstatement() throws Exception {
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."));
411 public void shouldFailOnInvalidDeviateReplaceSubstatement() throws Exception {
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."));
425 public void shouldFailOnInvalidDeviateDeleteSubstatement() throws Exception {
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."));