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.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;
46 public class DeviationResolutionTest {
49 public void testDeviateNotSupported() throws Exception {
50 final SchemaContext schemaContext = StmtTestUtils.parseYangSources(
51 "/deviation-resolution-test/deviation-not-supported");
52 assertNotNull(schemaContext);
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);
59 assertEquals(1, myContA.getChildNodes().size());
60 assertNotNull(myContA.getDataChildByName(QName.create(importedModule.getQNameModule(), "my-leaf-a3")));
62 final ContainerSchemaNode myContB = (ContainerSchemaNode) importedModule.getDataChildByName(
63 QName.create(importedModule.getQNameModule(), "my-cont-b"));
66 final ContainerSchemaNode myContC = (ContainerSchemaNode) importedModule.getDataChildByName(
67 QName.create(importedModule.getQNameModule(), "my-cont-c"));
68 assertNotNull(myContC);
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")));
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);
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);
87 assertFalse(myLeafList.isConfiguration());
88 assertEquals(3, myLeafList.getDefaults().size());
90 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
91 assertEquals(10, constraint.getMaxElements().intValue());
92 assertEquals(5, constraint.getMinElements().intValue());
93 assertNotNull(myLeafList.getType().getUnits());
95 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
96 QName.create(barModule.getQNameModule(), "my-list"));
97 assertNotNull(myList);
98 assertEquals(2, myList.getUniqueConstraints().size());
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());
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());
111 final NotificationDefinition myNotification = barModule.getNotifications().iterator().next();
112 assertEquals(2, myNotification.getMustConstraints().size());
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());
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());
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);
134 final Module barModule = schemaContext.findModule("bar", Revision.of("2017-01-20")).get();
135 assertNotNull(barModule);
137 final LeafSchemaNode myLeaf = (LeafSchemaNode) barModule.getDataChildByName(
138 QName.create(barModule.getQNameModule(), "my-leaf"));
139 assertNotNull(myLeaf);
141 assertThat(myLeaf.getType(), instanceOf(Uint32TypeDefinition.class));
142 assertEquals(Optional.of("bytes"), myLeaf.getType().getUnits());
143 assertEquals(Optional.of("10"), myLeaf.getType().getDefaultValue());
145 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
146 QName.create(barModule.getQNameModule(), "my-leaf-list-test"));
147 assertNotNull(myLeafList);
149 final ElementCountConstraint constraint = myLeafList.getElementCountConstraint().get();
150 assertEquals(6, constraint.getMaxElements().intValue());
151 assertEquals(3, constraint.getMinElements().intValue());
152 assertTrue(myLeafList.isConfiguration());
154 final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) barModule.getDataChildByName(
155 QName.create(barModule.getQNameModule(), "my-choice"));
156 assertNotNull(myChoice);
158 assertFalse(myChoice.isMandatory());
159 assertEquals(1, myChoice.getUnknownSchemaNodes().size());
160 assertEquals("new arg", myChoice.getUnknownSchemaNodes().iterator().next().getNodeParameter());
162 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
163 QName.create(barModule.getQNameModule(), "my-cont"));
164 assertNotNull(myCont);
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());
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());
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);
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);
197 assertEquals(Optional.empty(), myLeaf.getType().getDefaultValue());
198 assertEquals(Optional.empty(), myLeaf.getType().getUnits());
199 assertEquals(0, myLeaf.getUnknownSchemaNodes().size());
201 final LeafListSchemaNode myLeafList = (LeafListSchemaNode) barModule.getDataChildByName(
202 QName.create(barModule.getQNameModule(), "my-leaf-list"));
203 assertNotNull(myLeafList);
205 assertEquals(0, myLeafList.getDefaults().size());
206 assertEquals(0, myLeafList.getMustConstraints().size());
208 final ListSchemaNode myList = (ListSchemaNode) barModule.getDataChildByName(
209 QName.create(barModule.getQNameModule(), "my-list"));
210 assertNotNull(myList);
212 assertEquals(0, myList.getUniqueConstraints().size());
213 assertEquals(0, myList.getUnknownSchemaNodes().size());
215 final ContainerSchemaNode myCont = (ContainerSchemaNode) barModule.getDataChildByName(
216 QName.create(barModule.getQNameModule(), "my-cont"));
217 assertNotNull(myCont);
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());
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());
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."));
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."));
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."));
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"));
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."));
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."));
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."));
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."));
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;
333 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
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"));
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."));
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;
354 System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
356 StmtTestUtils.parseYangSources(
357 sourceForResource("/deviation-resolution-test/deviation-delete/foo-invalid.yang"),
358 sourceForResource("/deviation-resolution-test/deviation-delete/bar-invalid.yang"));
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."));
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."));
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."));
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."));