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.impl.schema.Builders;
23 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
24 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
25 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
26 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
27 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
28 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
29 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
32 private static final String NS = "foo";
33 private static final String REV = "2016-05-17";
34 private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
35 private static final QName TASK = QName.create(NS, REV, "task");
36 private static final QName TASK_ID = QName.create(NS, REV, "task-id");
37 private static final QName TASK_DATA = QName.create(NS, REV, "task-data");
38 private static final QName OTHER_DATA = QName.create(NS, REV, "other-data");
39 private static final QName MANDATORY_DATA = QName.create(NS, REV, "mandatory-data");
40 private static final QName TASK_MANDATORY_LEAF = QName.create(NS, REV, "task-mandatory-leaf");
41 private static final QName NON_PRESENCE_CONTAINER = QName.create(NS, REV, "non-presence-container");
42 private static final QName NON_PRESENCE_CONTAINER_2 = QName.create(NS, REV, "non-presence-container-2");
43 private static final QName PRESENCE_CONTAINER_2 = QName.create(NS, REV, "presence-container-2");
44 private static final QName MANDATORY_LEAF_2 = QName.create(NS, REV, "mandatory-leaf-2");
46 private static DataTree initDataTree(final EffectiveModelContext schemaContext)
47 throws DataValidationFailedException {
48 final var inMemoryDataTree = new InMemoryDataTreeFactory().create(
49 DataTreeConfiguration.DEFAULT_CONFIGURATION, schemaContext);
51 final var taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
52 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
53 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER, TASK), taskNode);
54 modificationTree.ready();
56 inMemoryDataTree.validate(modificationTree);
57 final var prepare = inMemoryDataTree.prepare(modificationTree);
58 inMemoryDataTree.commit(prepare);
59 return inMemoryDataTree;
63 void testMandatoryNodes() throws DataValidationFailedException {
64 testPresenceContainer();
65 testNonPresenceContainer();
66 testMultipleContainers();
69 private static void testPresenceContainer() throws DataValidationFailedException {
70 final var schemaContext = YangParserTestUtils.parseYang("""
80 container task-container {
86 leaf task-mandatory-leaf {
104 assertNotNull(schemaContext, "Schema context must not be null.");
106 testContainerIsNotPresent(schemaContext);
107 final var ex = assertThrows(IllegalArgumentException.class, () -> testContainerIsPresent(schemaContext));
109 "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant /(foo?revision=2016-05-17)"
110 + "mandatory-data", ex.getMessage());
111 testMandatoryDataLeafIsPresent(schemaContext);
114 private static void testNonPresenceContainer() throws DataValidationFailedException {
115 final var schemaContext = YangParserTestUtils.parseYang("""
116 module foo-non-presence {
121 revision 2016-05-17 {
125 container task-container {
132 leaf task-mandatory-leaf {
137 container task-data {
138 leaf mandatory-data {
149 assertNotNull(schemaContext, "Schema context must not be null.");
152 testContainerIsNotPresent(schemaContext);
153 fail("Should fail due to missing mandatory node.");
154 } catch (IllegalArgumentException e) {
156 "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
157 + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
161 testContainerIsPresent(schemaContext);
162 fail("Should fail due to missing mandatory node.");
163 } catch (IllegalArgumentException e) {
165 "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
166 + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
168 testMandatoryDataLeafIsPresent(schemaContext);
171 private static void testMultipleContainers() throws DataValidationFailedException {
172 final var schemaContext = YangParserTestUtils.parseYang("""
173 module foo-multiple {
178 revision 2016-05-17 {
182 container task-container {
189 leaf task-mandatory-leaf {
194 container task-data {
195 presence "Task data";
197 leaf mandatory-data {
205 container non-presence-container {
207 container presence-container {
208 presence "presence container";
210 leaf mandatory-leaf {
216 container non-presence-container-2 {
217 leaf mandatory-leaf-2 {
223 container presence-container-2 {
224 presence "presence container";
226 leaf mandatory-leaf-3 {
236 assertNotNull(schemaContext, "Schema context must not be null.");
238 testContainerIsNotPresent(schemaContext);
241 testContainerIsPresent(schemaContext);
242 fail("Should fail due to missing mandatory node under present presence container.");
243 } catch (IllegalArgumentException e) {
244 assertTrue(e.getMessage().startsWith(
245 "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant"));
249 testMandatoryDataLeafIsPresent(schemaContext);
250 fail("Should fail due to missing mandatory node under present presence container.");
251 } catch (IllegalArgumentException e) {
253 Node (foo?revision=2016-05-17)task-data is missing mandatory descendant \
254 /(foo?revision=2016-05-17)non-presence-container/\
255 non-presence-container-2/mandatory-leaf-2""", e.getMessage());
258 testMandatoryLeaf2IsPresent(schemaContext, false);
261 testMandatoryLeaf2IsPresent(schemaContext, true);
262 fail("Should fail due to missing mandatory node under present presence container.");
263 } catch (IllegalArgumentException e) {
265 "Node (foo?revision=2016-05-17)presence-container-2 is missing mandatory "
266 + "descendant /(foo?revision=2016-05-17)mandatory-leaf-3", e.getMessage());
270 private static void testContainerIsNotPresent(final EffectiveModelContext schemaContext)
271 throws DataValidationFailedException {
272 final var inMemoryDataTree = initDataTree(schemaContext);
273 final var taskEntryNode = Builders.mapEntryBuilder()
274 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
275 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
276 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
279 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
280 modificationTree.write(
281 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
283 modificationTree.ready();
285 inMemoryDataTree.validate(modificationTree);
286 final var prepare = inMemoryDataTree.prepare(modificationTree);
287 inMemoryDataTree.commit(prepare);
290 private static void testContainerIsPresent(final EffectiveModelContext schemaContext)
291 throws DataValidationFailedException {
292 final var inMemoryDataTree = initDataTree(schemaContext);
294 final var taskEntryNode = Builders.mapEntryBuilder()
295 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
296 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
297 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
298 .withChild(createTaskDataContainer(false)).build();
300 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
301 modificationTree.write(
302 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
304 modificationTree.ready();
306 inMemoryDataTree.validate(modificationTree);
307 final var prepare = inMemoryDataTree.prepare(modificationTree);
308 inMemoryDataTree.commit(prepare);
311 private static void testMandatoryDataLeafIsPresent(final EffectiveModelContext schemaContext)
312 throws DataValidationFailedException {
313 final var inMemoryDataTree = initDataTree(schemaContext);
315 final var taskEntryNode = Builders.mapEntryBuilder()
316 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
317 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
318 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
319 .withChild(createTaskDataContainer(true)).build();
321 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
322 modificationTree.write(
323 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
325 modificationTree.ready();
327 inMemoryDataTree.validate(modificationTree);
328 final var prepare = inMemoryDataTree.prepare(modificationTree);
329 inMemoryDataTree.commit(prepare);
332 private static void testMandatoryLeaf2IsPresent(final EffectiveModelContext schemaContext,
333 final boolean withPresenceContianer) throws DataValidationFailedException {
334 final var inMemoryDataTree = initDataTree(schemaContext);
336 final var taskEntryNode = Builders.mapEntryBuilder()
337 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
338 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
339 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
340 .withChild(createTaskDataMultipleContainer(withPresenceContianer))
343 final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
344 modificationTree.write(
345 YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
347 modificationTree.ready();
349 inMemoryDataTree.validate(modificationTree);
350 final var prepare = inMemoryDataTree.prepare(modificationTree);
351 inMemoryDataTree.commit(prepare);
354 private static DataContainerChild createTaskDataContainer(final boolean withMandatoryNode) {
355 final var taskDataBuilder = Builders.containerBuilder()
356 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
357 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"));
358 if (withMandatoryNode) {
359 taskDataBuilder.withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"));
361 return taskDataBuilder.build();
364 private static DataContainerChild createTaskDataMultipleContainer(final boolean withPresenceContianer) {
365 final var nonPresenceContainerBuilder = Builders.containerBuilder()
366 .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER))
367 .withChild(Builders.containerBuilder()
368 .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER_2))
369 .withChild(ImmutableNodes.leafNode(MANDATORY_LEAF_2, "mandatory leaf data 2")).build());
371 if (withPresenceContianer) {
372 nonPresenceContainerBuilder.withChild(Builders.containerBuilder()
373 .withNodeIdentifier(new NodeIdentifier(PRESENCE_CONTAINER_2)).build());
376 return Builders.containerBuilder()
377 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
378 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"))
379 .withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"))
380 .withChild(nonPresenceContainerBuilder.build())