2 * Copyright (c) 2016 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.data.tree.impl;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertThrows;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
16 import org.junit.Test;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
26 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
29 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
30 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
31 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
32 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
33 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
34 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
35 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
37 public class Bug5830Test {
38 private static final String NS = "foo";
39 private static final String REV = "2016-05-17";
40 private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
41 private static final QName TASK = QName.create(NS, REV, "task");
42 private static final QName TASK_ID = QName.create(NS, REV, "task-id");
43 private static final QName TASK_DATA = QName.create(NS, REV, "task-data");
44 private static final QName OTHER_DATA = QName.create(NS, REV, "other-data");
45 private static final QName MANDATORY_DATA = QName.create(NS, REV, "mandatory-data");
46 private static final QName TASK_MANDATORY_LEAF = QName.create(NS, REV, "task-mandatory-leaf");
47 private static final QName NON_PRESENCE_CONTAINER = QName.create(NS, REV, "non-presence-container");
48 private static final QName NON_PRESENCE_CONTAINER_2 = QName.create(NS, REV, "non-presence-container-2");
49 private static final QName PRESENCE_CONTAINER_2 = QName.create(NS, REV, "presence-container-2");
50 private static final QName MANDATORY_LEAF_2 = QName.create(NS, REV, "mandatory-leaf-2");
52 private static DataTree initDataTree(final EffectiveModelContext schemaContext)
53 throws DataValidationFailedException {
54 DataTree inMemoryDataTree = new InMemoryDataTreeFactory().create(
55 DataTreeConfiguration.DEFAULT_CONFIGURATION, schemaContext);
57 final SystemMapNode taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
58 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
59 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER, TASK), taskNode);
60 modificationTree.ready();
62 inMemoryDataTree.validate(modificationTree);
63 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
64 inMemoryDataTree.commit(prepare);
65 return inMemoryDataTree;
69 public void testMandatoryNodes() throws DataValidationFailedException {
70 testPresenceContainer();
71 testNonPresenceContainer();
72 testMultipleContainers();
75 private static void testPresenceContainer() throws DataValidationFailedException {
76 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYang("""
86 container task-container {
92 leaf task-mandatory-leaf {
110 assertNotNull("Schema context must not be null.", schemaContext);
112 testContainerIsNotPresent(schemaContext);
113 final var ex = assertThrows(IllegalArgumentException.class, () -> testContainerIsPresent(schemaContext));
115 "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant /(foo?revision=2016-05-17)"
116 + "mandatory-data", ex.getMessage());
117 testMandatoryDataLeafIsPresent(schemaContext);
120 private static void testNonPresenceContainer() throws DataValidationFailedException {
121 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYang("""
122 module foo-non-presence {
127 revision 2016-05-17 {
131 container task-container {
138 leaf task-mandatory-leaf {
143 container task-data {
144 leaf mandatory-data {
155 assertNotNull("Schema context must not be null.", schemaContext);
158 testContainerIsNotPresent(schemaContext);
159 fail("Should fail due to missing mandatory node.");
160 } catch (IllegalArgumentException e) {
162 "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
163 + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
167 testContainerIsPresent(schemaContext);
168 fail("Should fail due to missing mandatory node.");
169 } catch (IllegalArgumentException e) {
171 "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
172 + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
174 testMandatoryDataLeafIsPresent(schemaContext);
177 private static void testMultipleContainers() throws DataValidationFailedException {
178 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYang("""
179 module foo-multiple {
184 revision 2016-05-17 {
188 container task-container {
195 leaf task-mandatory-leaf {
200 container task-data {
201 presence "Task data";
203 leaf mandatory-data {
211 container non-presence-container {
213 container presence-container {
214 presence "presence container";
216 leaf mandatory-leaf {
222 container non-presence-container-2 {
223 leaf mandatory-leaf-2 {
229 container presence-container-2 {
230 presence "presence container";
232 leaf mandatory-leaf-3 {
242 assertNotNull("Schema context must not be null.", schemaContext);
244 testContainerIsNotPresent(schemaContext);
247 testContainerIsPresent(schemaContext);
248 fail("Should fail due to missing mandatory node under present presence container.");
249 } catch (IllegalArgumentException e) {
250 assertTrue(e.getMessage().startsWith(
251 "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant"));
255 testMandatoryDataLeafIsPresent(schemaContext);
256 fail("Should fail due to missing mandatory node under present presence container.");
257 } catch (IllegalArgumentException e) {
259 Node (foo?revision=2016-05-17)task-data is missing mandatory descendant \
260 /(foo?revision=2016-05-17)non-presence-container/\
261 non-presence-container-2/mandatory-leaf-2""", e.getMessage());
264 testMandatoryLeaf2IsPresent(schemaContext, false);
267 testMandatoryLeaf2IsPresent(schemaContext, true);
268 fail("Should fail due to missing mandatory node under present presence container.");
269 } catch (IllegalArgumentException e) {
271 "Node (foo?revision=2016-05-17)presence-container-2 is missing mandatory "
272 + "descendant /(foo?revision=2016-05-17)mandatory-leaf-3", e.getMessage());
276 private static void testContainerIsNotPresent(final EffectiveModelContext schemaContext)
277 throws DataValidationFailedException {
278 final DataTree inMemoryDataTree = initDataTree(schemaContext);
279 final MapEntryNode taskEntryNode = Builders.mapEntryBuilder()
280 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
281 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
282 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
285 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
286 modificationTree.write(
287 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
289 modificationTree.ready();
291 inMemoryDataTree.validate(modificationTree);
292 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
293 inMemoryDataTree.commit(prepare);
296 private static void testContainerIsPresent(final EffectiveModelContext schemaContext)
297 throws DataValidationFailedException {
298 final DataTree inMemoryDataTree = initDataTree(schemaContext);
300 final MapEntryNode taskEntryNode = Builders.mapEntryBuilder()
301 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
302 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
303 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
304 .withChild(createTaskDataContainer(false)).build();
306 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
307 modificationTree.write(
308 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
310 modificationTree.ready();
312 inMemoryDataTree.validate(modificationTree);
313 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
314 inMemoryDataTree.commit(prepare);
317 private static void testMandatoryDataLeafIsPresent(final EffectiveModelContext schemaContext)
318 throws DataValidationFailedException {
319 final DataTree inMemoryDataTree = initDataTree(schemaContext);
321 final MapEntryNode taskEntryNode = Builders.mapEntryBuilder()
322 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
323 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
324 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
325 .withChild(createTaskDataContainer(true)).build();
327 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
328 modificationTree.write(
329 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
331 modificationTree.ready();
333 inMemoryDataTree.validate(modificationTree);
334 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
335 inMemoryDataTree.commit(prepare);
338 private static void testMandatoryLeaf2IsPresent(final EffectiveModelContext schemaContext,
339 final boolean withPresenceContianer) throws DataValidationFailedException {
340 final DataTree inMemoryDataTree = initDataTree(schemaContext);
342 final MapEntryNode taskEntryNode = Builders.mapEntryBuilder()
343 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
344 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
345 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
346 .withChild(createTaskDataMultipleContainer(withPresenceContianer))
349 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
350 modificationTree.write(
351 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
353 modificationTree.ready();
355 inMemoryDataTree.validate(modificationTree);
356 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
357 inMemoryDataTree.commit(prepare);
360 private static DataContainerChild createTaskDataContainer(final boolean withMandatoryNode) {
361 DataContainerNodeBuilder<NodeIdentifier, ContainerNode> taskDataBuilder = Builders.containerBuilder()
362 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
363 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"));
364 if (withMandatoryNode) {
365 taskDataBuilder.withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"));
367 return taskDataBuilder.build();
370 private static DataContainerChild createTaskDataMultipleContainer(final boolean withPresenceContianer) {
371 DataContainerNodeBuilder<NodeIdentifier, ContainerNode> nonPresenceContainerBuilder = Builders
373 .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER))
375 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER_2))
376 .withChild(ImmutableNodes.leafNode(MANDATORY_LEAF_2, "mandatory leaf data 2")).build());
378 if (withPresenceContianer) {
379 nonPresenceContainerBuilder.withChild(Builders.containerBuilder()
380 .withNodeIdentifier(new NodeIdentifier(PRESENCE_CONTAINER_2)).build());
383 DataContainerNodeBuilder<NodeIdentifier, ContainerNode> taskDataBuilder = Builders.containerBuilder()
384 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
385 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"));
386 taskDataBuilder.withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"));
387 taskDataBuilder.withChild(nonPresenceContainerBuilder.build());
389 return taskDataBuilder.build();