2 * Copyright (c) 2015 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.impl.schema.tree;
10 import static junit.framework.TestCase.assertFalse;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertTrue;
14 import com.google.common.collect.ImmutableMap;
15 import java.util.HashMap;
17 import java.util.Optional;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.opendaylight.yangtools.util.UnmodifiableCollection;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
26 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
33 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
34 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
35 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
36 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
39 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
44 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
46 public class Bug4454Test {
48 private static final QName MASTER_CONTAINER_QNAME = QName
49 .create("urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model", "2015-02-02",
51 private static final QName MIN_MAX_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-list");
52 private static final QName MIN_MAX_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-leaf-list");
53 private static final QName MIN_MAX_LIST_QNAME_NO_MINMAX = QName
54 .create(MASTER_CONTAINER_QNAME, "min-max-list-no-minmax");
55 private static final QName MIN_MAX_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-key-leaf");
56 private static final QName MIN_MAX_VALUE_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-value-leaf");
58 private static final YangInstanceIdentifier MASTER_CONTAINER_PATH = YangInstanceIdentifier
59 .of(MASTER_CONTAINER_QNAME);
60 private static final YangInstanceIdentifier MIN_MAX_LIST_PATH = YangInstanceIdentifier
61 .builder(MASTER_CONTAINER_PATH)
62 .node(MIN_MAX_LIST_QNAME).build();
63 private static final YangInstanceIdentifier MIN_MAX_LIST_NO_MINMAX_PATH = YangInstanceIdentifier
64 .builder(MASTER_CONTAINER_PATH)
65 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).build();
66 private static final YangInstanceIdentifier MIN_MAX_LEAF_LIST_PATH = YangInstanceIdentifier
67 .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LEAF_LIST_QNAME).build();
69 private static final Map<QName, Object> FOO_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "foo");
70 private static final Map<QName, Object> BAZ_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "baz");
72 private final MapEntryNode fooEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
73 new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, FOO_PREDICATES))
74 .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "footest")).build();
75 private final MapEntryNode bazEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
76 new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, BAZ_PREDICATES))
77 .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "baztest")).build();
78 private final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
80 private final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
82 private final MapEntryNode bazEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
84 private final MapNode mapNodeBazFuzWithNodes = ImmutableNodes.mapNodeBuilder()
85 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
86 .withChild(bazEntryNode).withChild(bazEntryNodeWithValue).withChild(fooEntryNode)
88 private final MapNode mapNodeFooWithNodes = ImmutableNodes.mapNodeBuilder()
89 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
90 .withChild(fooEntryNode).withChild(fooEntryNodeWithValue).withChild(barEntryNode).withChild(bazEntryNode)
92 private final MapNode mapNodeBar = ImmutableNodes.mapNodeBuilder()
93 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
94 .withChild(barEntryNode).build();
95 private final MapNode mapNodeBaz = ImmutableNodes.mapNodeBuilder()
96 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
97 .withChild(bazEntryNode).build();
99 private DataTree inMemoryDataTree;
102 public void prepare() {
103 SchemaContext schemaContext = createTestContext();
104 assertNotNull("Schema context must not be null.", schemaContext);
105 inMemoryDataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL,
107 final DataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
108 final DataTreeModification modificationTree = initialDataTreeSnapshot.newModification();
110 modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
111 modificationTree.ready();
112 inMemoryDataTree.commit(inMemoryDataTree.prepare(modificationTree));
115 public static SchemaContext createTestContext() {
116 return YangParserTestUtils.parseYangResource("/bug-4454-test.yang");
120 public void minMaxListDeleteWriteTest() throws DataValidationFailedException {
121 final DataTreeModification modificationTree1 = inMemoryDataTree.takeSnapshot().newModification();
123 Map<QName, Object> key = new HashMap<>();
124 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
126 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , key);
128 final YangInstanceIdentifier minMaxLeafFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
129 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
132 key.put(MIN_MAX_KEY_LEAF_QNAME, "NON-EXISTING-LEAF");
134 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
136 final YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
137 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
139 final Map<QName, Object> keyTemp = new HashMap<>();
140 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
142 NodeIdentifierWithPredicates mapEntryPathTest = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , keyTemp);
144 final YangInstanceIdentifier pathToBaz = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
145 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
148 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
150 mapEntryPathTest = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , keyTemp);
152 final YangInstanceIdentifier pathToBar = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
153 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
156 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
158 final NodeIdentifierWithPredicates mapEntryPathTestKey = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME,
161 final YangInstanceIdentifier pathToKeyFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
162 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTestKey).node(MIN_MAX_KEY_LEAF_QNAME).build();
164 final LeafNode<String> newNode = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test");
165 final LeafNode<String> newNode1 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test1");
166 final LeafNode<String> newNode2 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test2");
167 final LeafNode<String> newNodekey = ImmutableNodes.leafNode(MIN_MAX_KEY_LEAF_QNAME, "foo");
169 assertFalse(inMemoryDataTree.toString().contains("list"));
171 DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
172 Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
173 assertTrue(!minMaxListRead.isPresent());
175 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
176 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
177 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
178 modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBar);
179 modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
180 modificationTree1.write(pathToKeyFoo, newNodekey);
181 modificationTree1.write(pathToBaz, newNode2);
182 modificationTree1.write(pathToBaz, newNode1);
183 modificationTree1.write(pathToBaz, newNode);
184 modificationTree1.delete(minMaxLeafFoo);
185 modificationTree1.delete(minMaxLeafNel);
187 modificationTree1.ready();
188 inMemoryDataTree.validate(modificationTree1);
189 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree1);
190 inMemoryDataTree.commit(prepare);
192 DataTreeSnapshot test = inMemoryDataTree.takeSnapshot();
193 testLoop(test, "bar", "test");
195 DataTreeModification tempMod = test.newModification();
196 tempMod.write(pathToBaz, newNode2);
197 tempMod.write(pathToBaz, newNode1);
198 tempMod.merge(pathToBaz, newNode2);
199 tempMod.write(pathToBaz, newNode1);
202 inMemoryDataTree.validate(tempMod);
203 final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(tempMod);
204 inMemoryDataTree.commit(prepare1);
206 DataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
207 testLoop(test1, "bar", "test1");
209 DataTreeModification tempMod1 = test1.newModification();
210 tempMod1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
213 inMemoryDataTree.validate(tempMod1);
214 final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
215 inMemoryDataTree.commit(prepare2);
217 DataTreeSnapshot test2 = inMemoryDataTree.takeSnapshot();
218 minMaxListRead = test2.readNode(MIN_MAX_LIST_PATH);
219 assertTrue(minMaxListRead.isPresent());
220 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
222 DataTreeModification tempMod2 = test2.newModification();
223 tempMod2.write(MIN_MAX_LIST_PATH, mapNodeBaz);
224 tempMod2.write(pathToBaz, newNode2);
227 inMemoryDataTree.validate(tempMod2);
228 final DataTreeCandidate prepare3 = inMemoryDataTree.prepare(tempMod2);
229 inMemoryDataTree.commit(prepare3);
231 DataTreeSnapshot test3 = inMemoryDataTree.takeSnapshot();
232 minMaxListRead = test3.readNode(MIN_MAX_LIST_PATH);
233 assertTrue(minMaxListRead.isPresent());
234 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 1);
235 assertTrue(minMaxListRead.get().getValue().toString().contains("test2"));
237 DataTreeModification tempMod3 = test3.newModification();
238 tempMod3.merge(MIN_MAX_LIST_PATH, mapNodeBar);
239 tempMod3.merge(pathToBar, newNode1);
242 inMemoryDataTree.validate(tempMod3);
243 final DataTreeCandidate prepare4 = inMemoryDataTree.prepare(tempMod3);
244 inMemoryDataTree.commit(prepare4);
246 DataTreeSnapshot test4 = inMemoryDataTree.takeSnapshot();
247 testLoop(test4, "test1", "test2");
251 public void minMaxLeafListPass() throws DataValidationFailedException {
252 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
254 final NodeWithValue<?> barPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "bar");
255 final NodeWithValue<?> gooPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "goo");
257 final LeafSetEntryNode<Object> barLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
258 .withNodeIdentifier(barPath)
259 .withValue("bar").build();
260 final LeafSetEntryNode<Object> gooLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
261 .withNodeIdentifier(gooPath)
262 .withValue("goo").build();
264 final LeafSetNode<Object> fooLeafSetNode = ImmutableLeafSetNodeBuilder.create()
265 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
266 .withChildValue("foo").build();
268 modificationTree.write(MIN_MAX_LEAF_LIST_PATH, fooLeafSetNode);
269 modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
270 modificationTree.ready();
272 inMemoryDataTree.validate(modificationTree);
273 final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
274 inMemoryDataTree.commit(prepare1);
276 DataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
278 DataTreeModification tempMod1 = test1.newModification();
279 tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(gooPath), gooLeafSetEntry);
280 tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
283 inMemoryDataTree.validate(tempMod1);
284 final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
285 inMemoryDataTree.commit(prepare2);
287 final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
288 final Optional<NormalizedNode<?, ?>> masterContainer = snapshotAfterCommit.readNode(MASTER_CONTAINER_PATH);
289 assertTrue(masterContainer.isPresent());
290 final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get())
291 .getChild(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
292 assertTrue(leafList.isPresent());
293 assertTrue(leafList.get().getValue().size() == 3);
297 @Test(expected = DataValidationFailedException.class)
298 public void minMaxListDeleteExceptionTest() throws DataValidationFailedException {
299 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
301 Map<QName, Object> key = new HashMap<>();
302 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
304 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
306 final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
307 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
310 key.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
312 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
314 final YangInstanceIdentifier minMaxLeafBar = MASTER_CONTAINER_PATH
315 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
318 key.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
320 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
322 final YangInstanceIdentifier minMaxLeafBaz = MASTER_CONTAINER_PATH
323 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
325 modificationTree.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
326 modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBar);
327 modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
328 modificationTree.delete(minMaxLeafFoo);
329 modificationTree.delete(minMaxLeafBar);
330 modificationTree.delete(minMaxLeafBaz);
332 modificationTree.ready();
334 inMemoryDataTree.validate(modificationTree);
335 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
336 inMemoryDataTree.commit(prepare);
340 public void minMaxListNoMinMaxDeleteTest() throws DataValidationFailedException {
341 final MapEntryNode fooEntryNoMinMaxNode =
342 ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME_NO_MINMAX, MIN_MAX_KEY_LEAF_QNAME, "foo");
343 final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
344 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME_NO_MINMAX))
345 .withChild(fooEntryNoMinMaxNode).build();
347 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
349 Map<QName, Object> key = new HashMap<>();
350 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
352 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME_NO_MINMAX,
355 final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
356 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2);
359 key.put(MIN_MAX_KEY_LEAF_QNAME, "non-existing-leaf");
361 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME_NO_MINMAX, key);
363 YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
364 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2).build();
366 modificationTree.write(MIN_MAX_LIST_NO_MINMAX_PATH, mapNode1);
367 modificationTree.delete(minMaxLeafFoo);
368 modificationTree.delete(minMaxLeafNel);
370 modificationTree.ready();
372 inMemoryDataTree.validate(modificationTree);
373 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
374 inMemoryDataTree.commit(prepare);
376 final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
377 final Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_NO_MINMAX_PATH);
378 assertTrue(minMaxListRead.isPresent());
379 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 0);
382 private static void testLoop(final DataTreeSnapshot snapshot, final String first, final String second) {
383 Optional<NormalizedNode<?, ?>> minMaxListRead = snapshot.readNode(MIN_MAX_LIST_PATH);
384 assertTrue(minMaxListRead.isPresent());
385 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
386 UnmodifiableCollection<?> collectionChildren = (UnmodifiableCollection<?>) minMaxListRead.get().getValue();
388 for (Object collectionChild : collectionChildren) {
389 if (collectionChild.toString().contains(first)) {
390 assertTrue(collectionChild.toString().contains(first));
392 assertTrue(collectionChild.toString().contains(second));