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.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
12 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.choiceBuilder;
13 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
14 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafBuilder;
15 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafSetBuilder;
16 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapBuilder;
17 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapEntryBuilder;
18 import static org.opendaylight.yangtools.yang.data.tree.impl.ListConstraintsValidation.assertTooFewElements;
19 import static org.opendaylight.yangtools.yang.data.tree.impl.ListConstraintsValidation.assertTooManyElements;
21 import com.google.common.collect.ImmutableMap;
22 import org.junit.AfterClass;
23 import org.junit.Before;
24 import org.junit.BeforeClass;
25 import org.junit.Test;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
32 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
33 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
34 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
35 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
36 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
37 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
39 public class YT776Test {
40 private static final QName MODULE = QName.create("yt776", "yt776");
41 private static final NodeIdentifier BOX = new NodeIdentifier(QName.create(MODULE, "box"));
42 private static final QName OBJECT = QName.create(MODULE, "object");
43 private static final QName OBJECT_ID = QName.create(MODULE, "object-id");
44 private static final NodeIdentifier OBJECT_LIST = new NodeIdentifier(OBJECT);
45 private static final NodeIdentifierWithPredicates OBJECT_ITEM = NodeIdentifierWithPredicates.of(OBJECT,
46 ImmutableMap.of(OBJECT_ID, "1"));
47 private static final LeafNode<?> OBJECT_ID_LEAF = leafBuilder().withNodeIdentifier(new NodeIdentifier(OBJECT_ID))
48 .withValue("1").build();
49 private static final NodeIdentifier ATTRIBUTES = new NodeIdentifier(QName.create(MODULE, "attributes"));
51 private static final QName NESTED = QName.create(MODULE, "nested");
52 private static final QName NESTED_ATTRIBUTE = QName.create(MODULE, "nested-attribute");
53 private static final NodeIdentifier NESTED_LIST = new NodeIdentifier(NESTED);
54 private static final NodeIdentifierWithPredicates NESTED_ITEM = NodeIdentifierWithPredicates.of(NESTED,
55 ImmutableMap.of(NESTED_ATTRIBUTE, "foo"));
57 private static final NodeIdentifier ANY_OF = new NodeIdentifier(QName.create(MODULE, "any-of"));
58 private static final QName SOME_LEAF = QName.create(MODULE, "some-leaf");
59 private static final NodeIdentifier SOME_LEAF_ID = new NodeIdentifier(SOME_LEAF);
60 private static final QName SOME_LIST = QName.create(MODULE, "some-list");
61 private static final NodeIdentifier SOME_LIST_ID = new NodeIdentifier(SOME_LIST);
62 private static final NodeIdentifierWithPredicates SOME_LIST_ITEM = NodeIdentifierWithPredicates.of(SOME_LIST,
63 ImmutableMap.of(SOME_LEAF, "foo"));
64 private static EffectiveModelContext SCHEMA_CONTEXT;
66 private DataTree dataTree;
69 public static void beforeClass() {
70 SCHEMA_CONTEXT = TestModel.createTestContext("/yt776.yang");
74 public static void afterClass() {
75 SCHEMA_CONTEXT = null;
80 dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION, SCHEMA_CONTEXT);
84 public void testNoAttributes() {
85 final DataTreeModification mod = dataTree.takeSnapshot().newModification();
86 mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
87 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
88 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
89 .withChild(OBJECT_ID_LEAF)
94 final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, mod::ready);
95 // FIXME: This is actually mandatory leaf enforcer kicking in: attributes have to be present. This is
96 // most probably not what we want.
97 assertEquals("Node (yt776)object[{(yt776)object-id=1}] is missing mandatory descendant /(yt776)attributes",
102 public void testEmptyAttributes() throws DataValidationFailedException {
103 final DataTreeModification mod = write(containerBuilder().withNodeIdentifier(BOX)
104 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
105 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
106 .withChild(OBJECT_ID_LEAF)
107 .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES).build())
112 final IllegalArgumentException ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
113 assertEquals("(yt776)attributes does not have enough elements (0), needs at least 1", ex.getMessage());
114 assertTooFewElements(ex);
118 public void testOneAttribute() throws DataValidationFailedException {
119 writeAndCommit(containerBuilder().withNodeIdentifier(BOX)
120 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
121 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
122 .withChild(OBJECT_ID_LEAF)
123 .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
124 .withChildValue("object1")
132 public void testTwoAttributes() throws DataValidationFailedException {
133 writeAndCommit(containerBuilder().withNodeIdentifier(BOX)
134 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
135 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
136 .withChild(OBJECT_ID_LEAF)
137 .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
138 .withChildValue("object1")
139 .withChildValue("object2")
147 public void testThreeAttributes() throws DataValidationFailedException {
148 final DataTreeModification mod = write(containerBuilder().withNodeIdentifier(BOX)
149 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
150 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
151 .withChild(OBJECT_ID_LEAF)
152 .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
153 .withChildValue("object1")
154 .withChildValue("object2")
155 .withChildValue("object3")
161 final IllegalArgumentException ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
162 assertEquals("(yt776)attributes has too many elements (3), can have at most 2", ex.getMessage());
163 assertTooManyElements(ex);
167 public void testEmptyAndMergeOne() throws DataValidationFailedException {
168 final DataTreeModification mod = dataTree.takeSnapshot().newModification();
169 mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
170 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
171 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
172 .withChild(OBJECT_ID_LEAF)
176 mod.merge(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
177 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
178 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
179 .withChild(OBJECT_ID_LEAF)
180 .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
181 .withChildValue("object1")
191 public void testEmptyAndMergeOneWithListTouched() throws DataValidationFailedException {
192 final DataTreeModification mod = dataTree.takeSnapshot().newModification();
193 mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
194 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
195 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
196 .withChild(OBJECT_ID_LEAF)
200 mod.merge(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
201 .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
202 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
203 .withChild(OBJECT_ID_LEAF)
204 .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
205 .withChildValue("object1")
211 mod.delete(YangInstanceIdentifier.create(BOX, OBJECT_LIST, OBJECT_ITEM, NESTED_LIST, NESTED_ITEM));
217 public void testDisappearInChoice() throws DataValidationFailedException {
218 DataTreeModification mod = dataTree.takeSnapshot().newModification();
219 // Initialize choice with list
220 mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
221 .withChild(choiceBuilder().withNodeIdentifier(ANY_OF)
222 .withChild(mapBuilder().withNodeIdentifier(SOME_LIST_ID)
223 .withChild(mapEntryBuilder()
224 .withNodeIdentifier(SOME_LIST_ITEM)
225 .withChild(leafBuilder().withNodeIdentifier(SOME_LEAF_ID).withValue("foo").build())
232 // Now delete the single item, causing the list to fizzle, while creating the alterinative case
233 mod = dataTree.takeSnapshot().newModification();
234 mod.delete(YangInstanceIdentifier.create(BOX, ANY_OF, SOME_LIST_ID, SOME_LIST_ITEM));
235 mod.write(YangInstanceIdentifier.create(BOX, ANY_OF, SOME_LEAF_ID),
236 leafBuilder().withNodeIdentifier(SOME_LEAF_ID).withValue("foo").build());
241 private DataTreeModification write(final ContainerNode data) throws DataValidationFailedException {
242 final DataTreeModification mod = dataTree.takeSnapshot().newModification();
243 mod.write(YangInstanceIdentifier.create(BOX), data);
247 private void writeAndCommit(final ContainerNode data) throws DataValidationFailedException {
248 final DataTreeModification mod = dataTree.takeSnapshot().newModification();
249 mod.write(YangInstanceIdentifier.create(BOX), data);
253 private void commit(final DataTreeModification mod) throws DataValidationFailedException {
255 dataTree.validate(mod);
256 dataTree.commit(dataTree.prepare(mod));