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.base.Optional;
15 import com.google.common.collect.ImmutableMap;
16 import java.io.IOException;
17 import java.net.URISyntaxException;
18 import java.util.HashMap;
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.DataTreeCandidate;
36 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
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.model.parser.api.YangSyntaxErrorException;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
46 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
48 public class Bug4454Test {
50 private static final QName MASTER_CONTAINER_QNAME = QName
51 .create("urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model", "2015-02-02",
53 private static final QName MIN_MAX_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-list");
54 private static final QName MIN_MAX_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-leaf-list");
55 private static final QName MIN_MAX_LIST_QNAME_NO_MINMAX = QName
56 .create(MASTER_CONTAINER_QNAME, "min-max-list-no-minmax");
57 private static final QName MIN_MAX_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-key-leaf");
58 private static final QName MIN_MAX_VALUE_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-value-leaf");
60 private static final YangInstanceIdentifier MASTER_CONTAINER_PATH = YangInstanceIdentifier
61 .of(MASTER_CONTAINER_QNAME);
62 private static final YangInstanceIdentifier MIN_MAX_LIST_PATH = YangInstanceIdentifier
63 .builder(MASTER_CONTAINER_PATH)
64 .node(MIN_MAX_LIST_QNAME).build();
65 private static final YangInstanceIdentifier MIN_MAX_LIST_NO_MINMAX_PATH = YangInstanceIdentifier
66 .builder(MASTER_CONTAINER_PATH)
67 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).build();
68 private static final YangInstanceIdentifier MIN_MAX_LEAF_LIST_PATH = YangInstanceIdentifier
69 .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LEAF_LIST_QNAME).build();
71 private static final Map<QName, Object> FOO_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "foo");
72 private static final Map<QName, Object> BAZ_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "baz");
74 private final MapEntryNode fooEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
75 new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, FOO_PREDICATES))
76 .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "footest")).build();
77 private final MapEntryNode bazEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
78 new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, BAZ_PREDICATES))
79 .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "baztest")).build();
80 private final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
82 private final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
84 private final MapEntryNode bazEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
86 private final MapNode mapNodeBazFuzWithNodes = ImmutableNodes.mapNodeBuilder()
87 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
88 .withChild(bazEntryNode).withChild(bazEntryNodeWithValue).withChild(fooEntryNode)
90 private final MapNode mapNodeFooWithNodes = ImmutableNodes.mapNodeBuilder()
91 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
92 .withChild(fooEntryNode).withChild(fooEntryNodeWithValue).withChild(barEntryNode).withChild(bazEntryNode)
94 private final MapNode mapNodeBar = ImmutableNodes.mapNodeBuilder()
95 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
96 .withChild(barEntryNode).build();
97 private final MapNode mapNodeBaz = ImmutableNodes.mapNodeBuilder()
98 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
99 .withChild(bazEntryNode).build();
101 private InMemoryDataTree inMemoryDataTree;
104 public void prepare() throws IOException, YangSyntaxErrorException, ReactorException, URISyntaxException {
105 SchemaContext schemaContext = createTestContext();
106 assertNotNull("Schema context must not be null.", schemaContext);
107 inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.OPERATIONAL);
108 inMemoryDataTree.setSchemaContext(schemaContext);
109 final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
110 final DataTreeModification modificationTree = initialDataTreeSnapshot.newModification();
112 modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
113 modificationTree.ready();
114 inMemoryDataTree.commit(inMemoryDataTree.prepare(modificationTree));
117 public static SchemaContext createTestContext() throws IOException, YangSyntaxErrorException, ReactorException,
119 return YangParserTestUtils.parseYangResource("/bug-4454-test.yang");
123 public void minMaxListDeleteWriteTest() throws DataValidationFailedException {
124 final InMemoryDataTreeModification modificationTree1 = inMemoryDataTree.takeSnapshot().newModification();
126 Map<QName, Object> key = new HashMap<>();
127 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
129 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , key);
131 final YangInstanceIdentifier minMaxLeafFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
132 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
135 key.put(MIN_MAX_KEY_LEAF_QNAME, "NON-EXISTING-LEAF");
137 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
139 final YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
140 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
142 final Map<QName, Object> keyTemp = new HashMap<>();
143 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
145 NodeIdentifierWithPredicates mapEntryPathTest = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , keyTemp);
147 final YangInstanceIdentifier pathToBaz = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
148 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
151 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
153 mapEntryPathTest = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME , keyTemp);
155 final YangInstanceIdentifier pathToBar = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
156 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
159 keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
161 final NodeIdentifierWithPredicates mapEntryPathTestKey = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME,
164 final YangInstanceIdentifier pathToKeyFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
165 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTestKey).node(MIN_MAX_KEY_LEAF_QNAME).build();
167 final LeafNode<String> newNode = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test");
168 final LeafNode<String> newNode1 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test1");
169 final LeafNode<String> newNode2 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test2");
170 final LeafNode<String> newNodekey = ImmutableNodes.leafNode(MIN_MAX_KEY_LEAF_QNAME, "foo");
172 assertFalse(inMemoryDataTree.toString().contains("list"));
174 InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
175 Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
176 assertTrue(!minMaxListRead.isPresent());
178 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
179 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
180 modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
181 modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBar);
182 modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
183 modificationTree1.write(pathToKeyFoo, newNodekey);
184 modificationTree1.write(pathToBaz, newNode2);
185 modificationTree1.write(pathToBaz, newNode1);
186 modificationTree1.write(pathToBaz, newNode);
187 modificationTree1.delete(minMaxLeafFoo);
188 modificationTree1.delete(minMaxLeafNel);
190 modificationTree1.ready();
191 inMemoryDataTree.validate(modificationTree1);
192 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree1);
193 inMemoryDataTree.commit(prepare);
195 InMemoryDataTreeSnapshot test = inMemoryDataTree.takeSnapshot();
196 testLoop(test, "bar", "test");
198 InMemoryDataTreeModification tempMod = test.newModification();
199 tempMod.write(pathToBaz, newNode2);
200 tempMod.write(pathToBaz, newNode1);
201 tempMod.merge(pathToBaz, newNode2);
202 tempMod.write(pathToBaz, newNode1);
205 inMemoryDataTree.validate(tempMod);
206 final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(tempMod);
207 inMemoryDataTree.commit(prepare1);
209 InMemoryDataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
210 testLoop(test1, "bar", "test1");
212 InMemoryDataTreeModification tempMod1 = test1.newModification();
213 tempMod1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
216 inMemoryDataTree.validate(tempMod1);
217 final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
218 inMemoryDataTree.commit(prepare2);
220 InMemoryDataTreeSnapshot test2 = inMemoryDataTree.takeSnapshot();
221 minMaxListRead = test2.readNode(MIN_MAX_LIST_PATH);
222 assertTrue(minMaxListRead.isPresent());
223 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
225 InMemoryDataTreeModification tempMod2 = test2.newModification();
226 tempMod2.write(MIN_MAX_LIST_PATH, mapNodeBaz);
227 tempMod2.write(pathToBaz, newNode2);
230 inMemoryDataTree.validate(tempMod2);
231 final DataTreeCandidate prepare3 = inMemoryDataTree.prepare(tempMod2);
232 inMemoryDataTree.commit(prepare3);
234 InMemoryDataTreeSnapshot test3 = inMemoryDataTree.takeSnapshot();
235 minMaxListRead = test3.readNode(MIN_MAX_LIST_PATH);
236 assertTrue(minMaxListRead.isPresent());
237 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 1);
238 assertTrue(minMaxListRead.get().getValue().toString().contains("test2"));
240 InMemoryDataTreeModification tempMod3 = test3.newModification();
241 tempMod3.merge(MIN_MAX_LIST_PATH, mapNodeBar);
242 tempMod3.merge(pathToBar, newNode1);
245 inMemoryDataTree.validate(tempMod3);
246 final DataTreeCandidate prepare4 = inMemoryDataTree.prepare(tempMod3);
247 inMemoryDataTree.commit(prepare4);
249 InMemoryDataTreeSnapshot test4 = inMemoryDataTree.takeSnapshot();
250 testLoop(test4, "test1", "test2");
254 public void minMaxLeafListPass() throws DataValidationFailedException {
255 final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
257 final NodeWithValue<?> barPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "bar");
258 final NodeWithValue<?> gooPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "goo");
260 final LeafSetEntryNode<Object> barLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
261 .withNodeIdentifier(barPath)
262 .withValue("bar").build();
263 final LeafSetEntryNode<Object> gooLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
264 .withNodeIdentifier(gooPath)
265 .withValue("goo").build();
267 final LeafSetNode<Object> fooLeafSetNode = ImmutableLeafSetNodeBuilder.create()
268 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
269 .withChildValue("foo").build();
271 modificationTree.write(MIN_MAX_LEAF_LIST_PATH, fooLeafSetNode);
272 modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
273 modificationTree.ready();
275 inMemoryDataTree.validate(modificationTree);
276 final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
277 inMemoryDataTree.commit(prepare1);
279 InMemoryDataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
281 InMemoryDataTreeModification tempMod1 = test1.newModification();
282 tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(gooPath), gooLeafSetEntry);
283 tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
286 inMemoryDataTree.validate(tempMod1);
287 final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
288 inMemoryDataTree.commit(prepare2);
290 final InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
291 final Optional<NormalizedNode<?, ?>> masterContainer = snapshotAfterCommit.readNode(MASTER_CONTAINER_PATH);
292 assertTrue(masterContainer.isPresent());
293 final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get())
294 .getChild(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
295 assertTrue(leafList.isPresent());
296 assertTrue(leafList.get().getValue().size() == 3);
300 @Test(expected = DataValidationFailedException.class)
301 public void minMaxListDeleteExceptionTest() throws DataValidationFailedException {
302 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
304 Map<QName, Object> key = new HashMap<>();
305 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
307 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
309 final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
310 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
313 key.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
315 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
317 final YangInstanceIdentifier minMaxLeafBar = MASTER_CONTAINER_PATH
318 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
321 key.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
323 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME, key);
325 final YangInstanceIdentifier minMaxLeafBaz = MASTER_CONTAINER_PATH
326 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
328 modificationTree.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
329 modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBar);
330 modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
331 modificationTree.delete(minMaxLeafFoo);
332 modificationTree.delete(minMaxLeafBar);
333 modificationTree.delete(minMaxLeafBaz);
335 modificationTree.ready();
337 inMemoryDataTree.validate(modificationTree);
338 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
339 inMemoryDataTree.commit(prepare);
343 public void minMaxListNoMinMaxDeleteTest() throws DataValidationFailedException {
344 final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME_NO_MINMAX, MIN_MAX_KEY_LEAF_QNAME,
346 final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
347 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME_NO_MINMAX))
348 .withChild(fooEntryNode).build();
350 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
352 Map<QName, Object> key = new HashMap<>();
353 key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
355 NodeIdentifierWithPredicates mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME_NO_MINMAX,
358 final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
359 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2);
362 key.put(MIN_MAX_KEY_LEAF_QNAME, "non-existing-leaf");
364 mapEntryPath2 = new NodeIdentifierWithPredicates(MIN_MAX_LIST_QNAME_NO_MINMAX, key);
366 YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
367 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2).build();
369 modificationTree.write(MIN_MAX_LIST_NO_MINMAX_PATH, mapNode1);
370 modificationTree.delete(minMaxLeafFoo);
371 modificationTree.delete(minMaxLeafNel);
373 modificationTree.ready();
375 inMemoryDataTree.validate(modificationTree);
376 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
377 inMemoryDataTree.commit(prepare);
379 final InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
380 final Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_NO_MINMAX_PATH);
381 assertTrue(minMaxListRead.isPresent());
382 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 0);
385 private static void testLoop(final InMemoryDataTreeSnapshot snapshot, final String first, final String second) {
386 Optional<NormalizedNode<?, ?>> minMaxListRead = snapshot.readNode(MIN_MAX_LIST_PATH);
387 assertTrue(minMaxListRead.isPresent());
388 assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
389 UnmodifiableCollection<?> collectionChildren = (UnmodifiableCollection<?>) minMaxListRead.get().getValue();
391 for (Object collectionChild : collectionChildren) {
392 if (collectionChild.toString().contains(first)) {
393 assertTrue(collectionChild.toString().contains(first));
395 assertTrue(collectionChild.toString().contains(second));