2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.assertThrows;
13 import com.google.common.collect.ImmutableMap;
14 import org.junit.jupiter.api.AfterAll;
15 import org.junit.jupiter.api.BeforeAll;
16 import org.junit.jupiter.api.BeforeEach;
17 import org.junit.jupiter.api.Test;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
22 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
24 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
25 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
26 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
27 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
28 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
29 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
30 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
31 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
34 private static final QName MODULE = QName.create("yt776", "yt776");
35 private static final NodeIdentifier BOX = new NodeIdentifier(QName.create(MODULE, "box"));
36 private static final QName OBJECT = QName.create(MODULE, "object");
37 private static final QName OBJECT_ID = QName.create(MODULE, "object-id");
38 private static final NodeIdentifier OBJECT_LIST = new NodeIdentifier(OBJECT);
39 private static final NodeIdentifierWithPredicates OBJECT_ITEM = NodeIdentifierWithPredicates.of(OBJECT,
40 ImmutableMap.of(OBJECT_ID, "1"));
41 private static final LeafNode<?> OBJECT_ID_LEAF = ImmutableNodes.leafNode(OBJECT_ID, "1");
42 private static final NodeIdentifier ATTRIBUTES = new NodeIdentifier(QName.create(MODULE, "attributes"));
44 private static final QName NESTED = QName.create(MODULE, "nested");
45 private static final QName NESTED_ATTRIBUTE = QName.create(MODULE, "nested-attribute");
46 private static final NodeIdentifier NESTED_LIST = new NodeIdentifier(NESTED);
47 private static final NodeIdentifierWithPredicates NESTED_ITEM = NodeIdentifierWithPredicates.of(NESTED,
48 ImmutableMap.of(NESTED_ATTRIBUTE, "foo"));
50 private static final NodeIdentifier ANY_OF = new NodeIdentifier(QName.create(MODULE, "any-of"));
51 private static final QName SOME_LEAF = QName.create(MODULE, "some-leaf");
52 private static final NodeIdentifier SOME_LEAF_ID = new NodeIdentifier(SOME_LEAF);
53 private static final QName SOME_LIST = QName.create(MODULE, "some-list");
54 private static final NodeIdentifier SOME_LIST_ID = new NodeIdentifier(SOME_LIST);
55 private static final NodeIdentifierWithPredicates SOME_LIST_ITEM = NodeIdentifierWithPredicates.of(SOME_LIST,
56 ImmutableMap.of(SOME_LEAF, "foo"));
57 private static EffectiveModelContext SCHEMA_CONTEXT;
59 private DataTree dataTree;
62 static void beforeClass() {
63 SCHEMA_CONTEXT = YangParserTestUtils.parseYang("""
76 leaf-list attributes {
85 leaf nested-attribute {
109 static void afterClass() {
110 SCHEMA_CONTEXT = null;
115 dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION, SCHEMA_CONTEXT);
119 void testNoAttributes() {
120 final var mod = dataTree.takeSnapshot().newModification();
121 mod.write(YangInstanceIdentifier.of(BOX), ImmutableNodes.newContainerBuilder()
122 .withNodeIdentifier(BOX)
123 .withChild(ImmutableNodes.newSystemMapBuilder()
124 .withNodeIdentifier(OBJECT_LIST)
125 .addChild(ImmutableNodes.newMapEntryBuilder()
126 .withNodeIdentifier(OBJECT_ITEM)
127 .withChild(OBJECT_ID_LEAF)
132 final var ex = assertThrows(IllegalArgumentException.class, mod::ready);
133 // FIXME: This is actually mandatory leaf enforcer kicking in: attributes have to be present. This is
134 // most probably not what we want.
135 assertEquals("Node (yt776)object[{(yt776)object-id=1}] is missing mandatory descendant /(yt776)attributes",
140 void testEmptyAttributes() throws DataValidationFailedException {
141 final var mod = write(ImmutableNodes.newContainerBuilder()
142 .withNodeIdentifier(BOX)
143 .withChild(ImmutableNodes.newSystemMapBuilder()
144 .withNodeIdentifier(OBJECT_LIST)
145 .addChild(ImmutableNodes.newMapEntryBuilder()
146 .withNodeIdentifier(OBJECT_ITEM)
147 .withChild(OBJECT_ID_LEAF)
148 .withChild(ImmutableNodes.newSystemLeafSetBuilder().withNodeIdentifier(ATTRIBUTES).build())
153 final var ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
154 assertEquals("(yt776)attributes does not have enough elements (0), needs at least 1", ex.getMessage());
155 ListConstraintsValidation.assertTooFewElements(ex);
159 void testOneAttribute() throws DataValidationFailedException {
160 writeAndCommit(ImmutableNodes.newContainerBuilder()
161 .withNodeIdentifier(BOX)
162 .withChild(ImmutableNodes.newSystemMapBuilder()
163 .withNodeIdentifier(OBJECT_LIST)
164 .addChild(ImmutableNodes.newMapEntryBuilder()
165 .withNodeIdentifier(OBJECT_ITEM)
166 .withChild(OBJECT_ID_LEAF)
167 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
168 .withNodeIdentifier(ATTRIBUTES)
169 .withChildValue("object1")
177 void testTwoAttributes() throws DataValidationFailedException {
178 writeAndCommit(ImmutableNodes.newContainerBuilder()
179 .withNodeIdentifier(BOX)
180 .withChild(ImmutableNodes.newSystemMapBuilder()
181 .withNodeIdentifier(OBJECT_LIST)
182 .addChild(ImmutableNodes.newMapEntryBuilder()
183 .withNodeIdentifier(OBJECT_ITEM)
184 .withChild(OBJECT_ID_LEAF)
185 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
186 .withNodeIdentifier(ATTRIBUTES)
187 .withChildValue("object1")
188 .withChildValue("object2")
196 void testThreeAttributes() throws DataValidationFailedException {
197 final var mod = write(ImmutableNodes.newContainerBuilder()
198 .withNodeIdentifier(BOX)
199 .withChild(ImmutableNodes.newSystemMapBuilder()
200 .withNodeIdentifier(OBJECT_LIST)
201 .addChild(ImmutableNodes.newMapEntryBuilder()
202 .withNodeIdentifier(OBJECT_ITEM)
203 .withChild(OBJECT_ID_LEAF)
204 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
205 .withNodeIdentifier(ATTRIBUTES)
206 .withChildValue("object1")
207 .withChildValue("object2")
208 .withChildValue("object3")
214 final var ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
215 assertEquals("(yt776)attributes has too many elements (3), can have at most 2", ex.getMessage());
216 ListConstraintsValidation.assertTooManyElements(ex);
220 void testEmptyAndMergeOne() throws DataValidationFailedException {
221 final var mod = dataTree.takeSnapshot().newModification();
222 mod.write(YangInstanceIdentifier.of(BOX), ImmutableNodes.newContainerBuilder()
223 .withNodeIdentifier(BOX)
224 .withChild(ImmutableNodes.newSystemMapBuilder()
225 .withNodeIdentifier(OBJECT_LIST)
226 .addChild(ImmutableNodes.newMapEntryBuilder()
227 .withNodeIdentifier(OBJECT_ITEM)
228 .withChild(OBJECT_ID_LEAF)
232 mod.merge(YangInstanceIdentifier.of(BOX), ImmutableNodes.newContainerBuilder()
233 .withNodeIdentifier(BOX)
234 .withChild(ImmutableNodes.newSystemMapBuilder()
235 .withNodeIdentifier(OBJECT_LIST)
236 .addChild(ImmutableNodes.newMapEntryBuilder()
237 .withNodeIdentifier(OBJECT_ITEM)
238 .withChild(OBJECT_ID_LEAF)
239 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
240 .withNodeIdentifier(ATTRIBUTES)
241 .withChildValue("object1")
251 void testEmptyAndMergeOneWithListTouched() throws DataValidationFailedException {
252 final var mod = dataTree.takeSnapshot().newModification();
253 mod.write(YangInstanceIdentifier.of(BOX), ImmutableNodes.newContainerBuilder()
254 .withNodeIdentifier(BOX)
255 .withChild(ImmutableNodes.newSystemMapBuilder()
256 .withNodeIdentifier(OBJECT_LIST)
257 .addChild(ImmutableNodes.newMapEntryBuilder()
258 .withNodeIdentifier(OBJECT_ITEM)
259 .withChild(OBJECT_ID_LEAF)
263 mod.merge(YangInstanceIdentifier.of(BOX), ImmutableNodes.newContainerBuilder()
264 .withNodeIdentifier(BOX)
265 .withChild(ImmutableNodes.newSystemMapBuilder()
266 .withNodeIdentifier(OBJECT_LIST)
267 .addChild(ImmutableNodes.newMapEntryBuilder()
268 .withNodeIdentifier(OBJECT_ITEM)
269 .withChild(OBJECT_ID_LEAF)
270 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
271 .withNodeIdentifier(ATTRIBUTES)
272 .withChildValue("object1")
278 mod.delete(YangInstanceIdentifier.of(BOX, OBJECT_LIST, OBJECT_ITEM, NESTED_LIST, NESTED_ITEM));
284 void testDisappearInChoice() throws DataValidationFailedException {
285 var mod = dataTree.takeSnapshot().newModification();
286 // Initialize choice with list
287 mod.write(YangInstanceIdentifier.of(BOX), ImmutableNodes.newContainerBuilder()
288 .withNodeIdentifier(BOX)
289 .withChild(ImmutableNodes.newChoiceBuilder()
290 .withNodeIdentifier(ANY_OF)
291 .withChild(ImmutableNodes.newSystemMapBuilder()
292 .withNodeIdentifier(SOME_LIST_ID)
293 .withChild(ImmutableNodes.newMapEntryBuilder()
294 .withNodeIdentifier(SOME_LIST_ITEM)
295 .withChild(ImmutableNodes.leafNode(SOME_LEAF_ID, "foo"))
302 // Now delete the single item, causing the list to fizzle, while creating the alterinative case
303 mod = dataTree.takeSnapshot().newModification();
304 mod.delete(YangInstanceIdentifier.of(BOX, ANY_OF, SOME_LIST_ID, SOME_LIST_ITEM));
305 mod.write(YangInstanceIdentifier.of(BOX, ANY_OF, SOME_LEAF_ID), ImmutableNodes.leafNode(SOME_LEAF_ID, "foo"));
310 private DataTreeModification write(final ContainerNode data) throws DataValidationFailedException {
311 final var mod = dataTree.takeSnapshot().newModification();
312 mod.write(YangInstanceIdentifier.of(BOX), data);
316 private void writeAndCommit(final ContainerNode data) throws DataValidationFailedException {
317 final var mod = dataTree.takeSnapshot().newModification();
318 mod.write(YangInstanceIdentifier.of(BOX), data);
322 private void commit(final DataTreeModification mod) throws DataValidationFailedException {
324 dataTree.validate(mod);
325 dataTree.commit(dataTree.prepare(mod));