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.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertNotNull;
12 import static org.junit.jupiter.api.Assertions.assertThrows;
13 import static org.junit.jupiter.api.Assertions.assertTrue;
14 import static org.junit.jupiter.api.Assertions.fail;
16 import org.junit.jupiter.api.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.DataContainerChild;
22 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
23 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
24 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
25 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
26 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
27 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
28 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
31 private static final String NS = "foo";
32 private static final String REV = "2016-05-17";
33 private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
34 private static final QName TASK = QName.create(NS, REV, "task");
35 private static final QName TASK_ID = QName.create(NS, REV, "task-id");
36 private static final QName TASK_DATA = QName.create(NS, REV, "task-data");
37 private static final QName OTHER_DATA = QName.create(NS, REV, "other-data");
38 private static final QName MANDATORY_DATA = QName.create(NS, REV, "mandatory-data");
39 private static final QName TASK_MANDATORY_LEAF = QName.create(NS, REV, "task-mandatory-leaf");
40 private static final QName NON_PRESENCE_CONTAINER = QName.create(NS, REV, "non-presence-container");
41 private static final QName NON_PRESENCE_CONTAINER_2 = QName.create(NS, REV, "non-presence-container-2");
42 private static final QName PRESENCE_CONTAINER_2 = QName.create(NS, REV, "presence-container-2");
43 private static final QName MANDATORY_LEAF_2 = QName.create(NS, REV, "mandatory-leaf-2");
45 private static DataTree initDataTree(final EffectiveModelContext schemaContext)
46 throws DataValidationFailedException {
47 final var inMemoryDataTree = new InMemoryDataTreeFactory().create(
48 DataTreeConfiguration.DEFAULT_CONFIGURATION, schemaContext);
50 final var taskNode = ImmutableNodes.newSystemMapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
51 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
52 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER, TASK), taskNode);
53 modificationTree.ready();
55 inMemoryDataTree.validate(modificationTree);
56 final var prepare = inMemoryDataTree.prepare(modificationTree);
57 inMemoryDataTree.commit(prepare);
58 return inMemoryDataTree;
62 void testMandatoryNodes() throws DataValidationFailedException {
63 testPresenceContainer();
64 testNonPresenceContainer();
65 testMultipleContainers();
68 private static void testPresenceContainer() throws DataValidationFailedException {
69 final var schemaContext = YangParserTestUtils.parseYang("""
79 container task-container {
85 leaf task-mandatory-leaf {
103 assertNotNull(schemaContext, "Schema context must not be null.");
105 testContainerIsNotPresent(schemaContext);
106 final var ex = assertThrows(IllegalArgumentException.class, () -> testContainerIsPresent(schemaContext));
108 "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant /(foo?revision=2016-05-17)"
109 + "mandatory-data", ex.getMessage());
110 testMandatoryDataLeafIsPresent(schemaContext);
113 private static void testNonPresenceContainer() throws DataValidationFailedException {
114 final var schemaContext = YangParserTestUtils.parseYang("""
115 module foo-non-presence {
120 revision 2016-05-17 {
124 container task-container {
131 leaf task-mandatory-leaf {
136 container task-data {
137 leaf mandatory-data {
148 assertNotNull(schemaContext, "Schema context must not be null.");
151 testContainerIsNotPresent(schemaContext);
152 fail("Should fail due to missing mandatory node.");
153 } catch (IllegalArgumentException e) {
155 "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
156 + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
160 testContainerIsPresent(schemaContext);
161 fail("Should fail due to missing mandatory node.");
162 } catch (IllegalArgumentException e) {
164 "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
165 + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
167 testMandatoryDataLeafIsPresent(schemaContext);
170 private static void testMultipleContainers() throws DataValidationFailedException {
171 final var schemaContext = YangParserTestUtils.parseYang("""
172 module foo-multiple {
177 revision 2016-05-17 {
181 container task-container {
188 leaf task-mandatory-leaf {
193 container task-data {
194 presence "Task data";
196 leaf mandatory-data {
204 container non-presence-container {
206 container presence-container {
207 presence "presence container";
209 leaf mandatory-leaf {
215 container non-presence-container-2 {
216 leaf mandatory-leaf-2 {
222 container presence-container-2 {
223 presence "presence container";
225 leaf mandatory-leaf-3 {
235 assertNotNull(schemaContext, "Schema context must not be null.");
237 testContainerIsNotPresent(schemaContext);
240 testContainerIsPresent(schemaContext);
241 fail("Should fail due to missing mandatory node under present presence container.");
242 } catch (IllegalArgumentException e) {
243 assertTrue(e.getMessage().startsWith(
244 "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant"));
248 testMandatoryDataLeafIsPresent(schemaContext);
249 fail("Should fail due to missing mandatory node under present presence container.");
250 } catch (IllegalArgumentException e) {
252 Node (foo?revision=2016-05-17)task-data is missing mandatory descendant \
253 /(foo?revision=2016-05-17)non-presence-container/\
254 non-presence-container-2/mandatory-leaf-2""", e.getMessage());
257 testMandatoryLeaf2IsPresent(schemaContext, false);
260 testMandatoryLeaf2IsPresent(schemaContext, true);
261 fail("Should fail due to missing mandatory node under present presence container.");
262 } catch (IllegalArgumentException e) {
264 "Node (foo?revision=2016-05-17)presence-container-2 is missing mandatory "
265 + "descendant /(foo?revision=2016-05-17)mandatory-leaf-3", e.getMessage());
269 private static void testContainerIsNotPresent(final EffectiveModelContext schemaContext)
270 throws DataValidationFailedException {
271 final var inMemoryDataTree = initDataTree(schemaContext);
272 final var taskEntryNode = ImmutableNodes.newMapEntryBuilder()
273 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
274 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
275 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
278 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
279 modificationTree.write(
280 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
282 modificationTree.ready();
284 inMemoryDataTree.validate(modificationTree);
285 final var prepare = inMemoryDataTree.prepare(modificationTree);
286 inMemoryDataTree.commit(prepare);
289 private static void testContainerIsPresent(final EffectiveModelContext schemaContext)
290 throws DataValidationFailedException {
291 final var inMemoryDataTree = initDataTree(schemaContext);
293 final var taskEntryNode = ImmutableNodes.newMapEntryBuilder()
294 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
295 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
296 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
297 .withChild(createTaskDataContainer(false)).build();
299 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
300 modificationTree.write(
301 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
303 modificationTree.ready();
305 inMemoryDataTree.validate(modificationTree);
306 final var prepare = inMemoryDataTree.prepare(modificationTree);
307 inMemoryDataTree.commit(prepare);
310 private static void testMandatoryDataLeafIsPresent(final EffectiveModelContext schemaContext)
311 throws DataValidationFailedException {
312 final var inMemoryDataTree = initDataTree(schemaContext);
314 final var taskEntryNode = ImmutableNodes.newMapEntryBuilder()
315 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
316 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
317 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
318 .withChild(createTaskDataContainer(true)).build();
320 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
321 modificationTree.write(
322 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
324 modificationTree.ready();
326 inMemoryDataTree.validate(modificationTree);
327 final var prepare = inMemoryDataTree.prepare(modificationTree);
328 inMemoryDataTree.commit(prepare);
331 private static void testMandatoryLeaf2IsPresent(final EffectiveModelContext schemaContext,
332 final boolean withPresenceContianer) throws DataValidationFailedException {
333 final var inMemoryDataTree = initDataTree(schemaContext);
335 final var taskEntryNode = ImmutableNodes.newMapEntryBuilder()
336 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
337 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
338 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
339 .withChild(createTaskDataMultipleContainer(withPresenceContianer))
342 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
343 modificationTree.write(
344 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
346 modificationTree.ready();
348 inMemoryDataTree.validate(modificationTree);
349 final var prepare = inMemoryDataTree.prepare(modificationTree);
350 inMemoryDataTree.commit(prepare);
353 private static DataContainerChild createTaskDataContainer(final boolean withMandatoryNode) {
354 final var taskDataBuilder = ImmutableNodes.newContainerBuilder()
355 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
356 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"));
357 if (withMandatoryNode) {
358 taskDataBuilder.withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"));
360 return taskDataBuilder.build();
363 private static DataContainerChild createTaskDataMultipleContainer(final boolean withPresenceContianer) {
364 final var nonPresenceContainerBuilder = ImmutableNodes.newContainerBuilder()
365 .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER))
366 .withChild(ImmutableNodes.newContainerBuilder()
367 .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER_2))
368 .withChild(ImmutableNodes.leafNode(MANDATORY_LEAF_2, "mandatory leaf data 2")).build());
370 if (withPresenceContianer) {
371 nonPresenceContainerBuilder.withChild(ImmutableNodes.newContainerBuilder()
372 .withNodeIdentifier(new NodeIdentifier(PRESENCE_CONTAINER_2)).build());
375 return ImmutableNodes.newContainerBuilder()
376 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
377 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"))
378 .withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"))
379 .withChild(nonPresenceContainerBuilder.build())