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.io.IOException;
16 import java.net.URISyntaxException;
17 import java.util.HashMap;
19 import java.util.Optional;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.opendaylight.yangtools.util.UnmodifiableCollection;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
35 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
36 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
39 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
40 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
41 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
43 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
44 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
48 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
50 public class Bug4454Test {
52 private static final QName MASTER_CONTAINER_QNAME = QName
53 .create("urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model", "2015-02-02",
55 private static final QName MIN_MAX_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-list");
56 private static final QName MIN_MAX_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-leaf-list");
57 private static final QName MIN_MAX_LIST_QNAME_NO_MINMAX = QName
58 .create(MASTER_CONTAINER_QNAME, "min-max-list-no-minmax");
59 private static final QName MIN_MAX_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-key-leaf");
60 private static final QName MIN_MAX_VALUE_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-value-leaf");
62 private static final YangInstanceIdentifier MASTER_CONTAINER_PATH = YangInstanceIdentifier
63 .of(MASTER_CONTAINER_QNAME);
64 private static final YangInstanceIdentifier MIN_MAX_LIST_PATH = YangInstanceIdentifier
65 .builder(MASTER_CONTAINER_PATH)
66 .node(MIN_MAX_LIST_QNAME).build();
67 private static final YangInstanceIdentifier MIN_MAX_LIST_NO_MINMAX_PATH = YangInstanceIdentifier
68 .builder(MASTER_CONTAINER_PATH)
69 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).build();
70 private static final YangInstanceIdentifier MIN_MAX_LEAF_LIST_PATH = YangInstanceIdentifier
71 .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LEAF_LIST_QNAME).build();
73 private static final Map<QName, Object> FOO_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "foo");
74 private static final Map<QName, Object> BAZ_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "baz");
76 private final MapEntryNode fooEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
77 new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, FOO_PREDICATES))
78 .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "footest")).build();
79 private final MapEntryNode bazEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
80 new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, BAZ_PREDICATES))
81 .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "baztest")).build();
82 private final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
84 private final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
86 private final MapEntryNode bazEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
88 private final MapNode mapNodeBazFuzWithNodes = ImmutableNodes.mapNodeBuilder()
89 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
90 .withChild(bazEntryNode).withChild(bazEntryNodeWithValue).withChild(fooEntryNode)
92 private final MapNode mapNodeFooWithNodes = ImmutableNodes.mapNodeBuilder()
93 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
94 .withChild(fooEntryNode).withChild(fooEntryNodeWithValue).withChild(barEntryNode).withChild(bazEntryNode)
96 private final MapNode mapNodeBar = ImmutableNodes.mapNodeBuilder()
97 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
98 .withChild(barEntryNode).build();
99 private final MapNode mapNodeBaz = ImmutableNodes.mapNodeBuilder()
100 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
101 .withChild(bazEntryNode).build();
103 private DataTree inMemoryDataTree;
106 public void prepare() throws IOException, YangSyntaxErrorException, ReactorException, URISyntaxException {
107 SchemaContext schemaContext = createTestContext();
108 assertNotNull("Schema context must not be null.", schemaContext);
109 inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create(
110 DataTreeConfiguration.DEFAULT_OPERATIONAL, schemaContext);
111 final DataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
112 final DataTreeModification modificationTree = initialDataTreeSnapshot.newModification();
114 modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
115 modificationTree.ready();
116 inMemoryDataTree.commit(inMemoryDataTree.prepare(modificationTree));
119 public static SchemaContext createTestContext() throws IOException, YangSyntaxErrorException, ReactorException,
121 return YangParserTestUtils.parseYangResource("/bug-4454-test.yang");
125 public void minMaxListDeleteWriteTest() throws DataValidationFailedException {
126 final DataTreeModification modificationTree1 = inMemoryDataTree.takeSnapshot().newModification();
128 Map<QName, Object> key = new HashMap<>();
129 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
131 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , key);
133 final YangInstanceIdentifier minMaxLeafFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
134 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
137 key.put(MIN_MAX_KEY_LEAF_QNAME, "NON-EXISTING-LEAF");
139 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
141 final YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
142 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
144 final Map<QName, Object> keyTemp = new HashMap<>();
145 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
147 NodeIdentifierWithPredicates mapEntryPathTest = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , keyTemp);
149 final YangInstanceIdentifier pathToBaz = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
150 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
153 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
155 mapEntryPathTest = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , keyTemp);
157 final YangInstanceIdentifier pathToBar = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
158 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
161 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
163 final NodeIdentifierWithPredicates mapEntryPathTestKey = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME,
166 final YangInstanceIdentifier pathToKeyFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
167 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTestKey).node(MIN_MAX_KEY_LEAF_QNAME).build();
169 final LeafNode<String> newNode = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test");
170 final LeafNode<String> newNode1 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test1");
171 final LeafNode<String> newNode2 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test2");
172 final LeafNode<String> newNodekey = ImmutableNodes.leafNode(MIN_MAX_KEY_LEAF_QNAME, "foo");
174 assertFalse(inMemoryDataTree.toString().contains("list"));
176 DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
177 Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
178 assertTrue(!minMaxListRead.isPresent());
180 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
181 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
182 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
183 modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBar);
184 modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
185 modificationTree1.write(pathToKeyFoo, newNodekey);
186 modificationTree1.write(pathToBaz, newNode2);
187 modificationTree1.write(pathToBaz, newNode1);
188 modificationTree1.write(pathToBaz, newNode);
189 modificationTree1.delete(minMaxLeafFoo);
190 modificationTree1.delete(minMaxLeafNel);
192 modificationTree1.ready();
193 inMemoryDataTree.validate(modificationTree1);
194 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree1);
195 inMemoryDataTree.commit(prepare);
197 DataTreeSnapshot test = inMemoryDataTree.takeSnapshot();
198 testLoop(test, "bar", "test");
200 DataTreeModification tempMod = test.newModification();
201 tempMod.write(pathToBaz, newNode2);
202 tempMod.write(pathToBaz, newNode1);
203 tempMod.merge(pathToBaz, newNode2);
204 tempMod.write(pathToBaz, newNode1);
207 inMemoryDataTree.validate(tempMod);
208 final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(tempMod);
209 inMemoryDataTree.commit(prepare1);
211 DataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
212 testLoop(test1, "bar", "test1");
214 DataTreeModification tempMod1 = test1.newModification();
215 tempMod1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
218 inMemoryDataTree.validate(tempMod1);
219 final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
220 inMemoryDataTree.commit(prepare2);
222 DataTreeSnapshot test2 = inMemoryDataTree.takeSnapshot();
223 minMaxListRead = test2.readNode(MIN_MAX_LIST_PATH);
224 assertTrue(minMaxListRead.isPresent());
225 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
227 DataTreeModification tempMod2 = test2.newModification();
228 tempMod2.write(MIN_MAX_LIST_PATH, mapNodeBaz);
229 tempMod2.write(pathToBaz, newNode2);
232 inMemoryDataTree.validate(tempMod2);
233 final DataTreeCandidate prepare3 = inMemoryDataTree.prepare(tempMod2);
234 inMemoryDataTree.commit(prepare3);
236 DataTreeSnapshot test3 = inMemoryDataTree.takeSnapshot();
237 minMaxListRead = test3.readNode(MIN_MAX_LIST_PATH);
238 assertTrue(minMaxListRead.isPresent());
239 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 1);
240 assertTrue(minMaxListRead.get().getValue().toString().contains("test2"));
242 DataTreeModification tempMod3 = test3.newModification();
243 tempMod3.merge(MIN_MAX_LIST_PATH, mapNodeBar);
244 tempMod3.merge(pathToBar, newNode1);
247 inMemoryDataTree.validate(tempMod3);
248 final DataTreeCandidate prepare4 = inMemoryDataTree.prepare(tempMod3);
249 inMemoryDataTree.commit(prepare4);
251 DataTreeSnapshot test4 = inMemoryDataTree.takeSnapshot();
252 testLoop(test4, "test1", "test2");
256 public void minMaxLeafListPass() throws DataValidationFailedException {
257 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
259 final NodeWithValue<?> barPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "bar");
260 final NodeWithValue<?> gooPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "goo");
262 final LeafSetEntryNode<Object> barLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
263 .withNodeIdentifier(barPath)
264 .withValue("bar").build();
265 final LeafSetEntryNode<Object> gooLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
266 .withNodeIdentifier(gooPath)
267 .withValue("goo").build();
269 final LeafSetNode<Object> fooLeafSetNode = ImmutableLeafSetNodeBuilder.create()
270 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
271 .withChildValue("foo").build();
273 modificationTree.write(MIN_MAX_LEAF_LIST_PATH, fooLeafSetNode);
274 modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
275 modificationTree.ready();
277 inMemoryDataTree.validate(modificationTree);
278 final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
279 inMemoryDataTree.commit(prepare1);
281 DataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
283 DataTreeModification tempMod1 = test1.newModification();
284 tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(gooPath), gooLeafSetEntry);
285 tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
288 inMemoryDataTree.validate(tempMod1);
289 final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
290 inMemoryDataTree.commit(prepare2);
292 final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
293 final Optional<NormalizedNode<?, ?>> masterContainer = snapshotAfterCommit.readNode(MASTER_CONTAINER_PATH);
294 assertTrue(masterContainer.isPresent());
295 final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get())
296 .getChild(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
297 assertTrue(leafList.isPresent());
298 assertTrue(leafList.get().getValue().size() == 3);
302 @Test(expected = DataValidationFailedException.class)
303 public void minMaxListDeleteExceptionTest() throws DataValidationFailedException {
304 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
306 Map<QName, Object> key = new HashMap<>();
307 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
309 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
311 final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
312 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
315 key.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
317 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
319 final YangInstanceIdentifier minMaxLeafBar = MASTER_CONTAINER_PATH
320 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
323 key.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
325 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
327 final YangInstanceIdentifier minMaxLeafBaz = MASTER_CONTAINER_PATH
328 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
330 modificationTree.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
331 modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBar);
332 modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
333 modificationTree.delete(minMaxLeafFoo);
334 modificationTree.delete(minMaxLeafBar);
335 modificationTree.delete(minMaxLeafBaz);
337 modificationTree.ready();
339 inMemoryDataTree.validate(modificationTree);
340 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
341 inMemoryDataTree.commit(prepare);
345 public void minMaxListNoMinMaxDeleteTest() throws DataValidationFailedException {
346 final MapEntryNode fooEntryNoMinMaxNode =
347 ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME_NO_MINMAX, MIN_MAX_KEY_LEAF_QNAME, "foo");
348 final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
349 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME_NO_MINMAX))
350 .withChild(fooEntryNoMinMaxNode).build();
352 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
354 Map<QName, Object> key = new HashMap<>();
355 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
357 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME_NO_MINMAX,
360 final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
361 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2);
364 key.put(MIN_MAX_KEY_LEAF_QNAME, "non-existing-leaf");
366 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME_NO_MINMAX, key);
368 YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
369 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2).build();
371 modificationTree.write(MIN_MAX_LIST_NO_MINMAX_PATH, mapNode1);
372 modificationTree.delete(minMaxLeafFoo);
373 modificationTree.delete(minMaxLeafNel);
375 modificationTree.ready();
377 inMemoryDataTree.validate(modificationTree);
378 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
379 inMemoryDataTree.commit(prepare);
381 final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
382 final Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_NO_MINMAX_PATH);
383 assertTrue(minMaxListRead.isPresent());
384 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 0);
387 private static void testLoop(final DataTreeSnapshot snapshot, final String first, final String second) {
388 Optional<NormalizedNode<?, ?>> minMaxListRead = snapshot.readNode(MIN_MAX_LIST_PATH);
389 assertTrue(minMaxListRead.isPresent());
390 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
391 UnmodifiableCollection<?> collectionChildren = (UnmodifiableCollection<?>) minMaxListRead.get().getValue();
393 for (Object collectionChild : collectionChildren) {
394 if (collectionChild.toString().contains(first)) {
395 assertTrue(collectionChild.toString().contains(first));
397 assertTrue(collectionChild.toString().contains(second));