e33347e08cfa42515ce0c8721e2ddd88a679ae6a
[yangtools.git] / yang / yang-data-impl / src / test / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / Bug4454Test.java
1 /*
2  * Copyright (c) 2015 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
9
10 import static junit.framework.TestCase.assertFalse;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14
15 import com.google.common.collect.ImmutableMap;
16 import java.util.HashMap;
17 import java.util.Map;
18 import java.util.Optional;
19 import org.junit.AfterClass;
20 import org.junit.Before;
21 import org.junit.BeforeClass;
22 import org.junit.Test;
23 import org.opendaylight.yangtools.util.UnmodifiableCollection;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
39 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
40 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
41 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
42 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
43 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
44 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
45 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
47 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
48 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
49
50 public class Bug4454Test {
51
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",
54                     "master-container");
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");
61     private static final QName PRESENCE_QNAME = QName.create(MASTER_CONTAINER_QNAME, "presence");
62
63     private static final YangInstanceIdentifier MASTER_CONTAINER_PATH = YangInstanceIdentifier
64             .of(MASTER_CONTAINER_QNAME);
65     private static final YangInstanceIdentifier MIN_MAX_LIST_PATH = YangInstanceIdentifier
66             .builder(MASTER_CONTAINER_PATH)
67             .node(MIN_MAX_LIST_QNAME).build();
68     private static final YangInstanceIdentifier PRESENCE_PATH = YangInstanceIdentifier.of(PRESENCE_QNAME);
69     private static final YangInstanceIdentifier PRESENCE_MIN_MAX_LIST_PATH = PRESENCE_PATH.node(MIN_MAX_LIST_QNAME);
70     private static final YangInstanceIdentifier MIN_MAX_LIST_NO_MINMAX_PATH = YangInstanceIdentifier
71             .builder(MASTER_CONTAINER_PATH)
72             .node(MIN_MAX_LIST_QNAME_NO_MINMAX).build();
73     private static final YangInstanceIdentifier MIN_MAX_LEAF_LIST_PATH = YangInstanceIdentifier
74             .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LEAF_LIST_QNAME).build();
75
76     private static final Map<QName, Object> FOO_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "foo");
77     private static final Map<QName, Object> BAZ_PREDICATES = ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "baz");
78
79     private final MapEntryNode fooEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
80         NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME, FOO_PREDICATES))
81             .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "footest")).build();
82     private final MapEntryNode bazEntryNodeWithValue = ImmutableMapEntryNodeBuilder.create().withNodeIdentifier(
83         NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME, BAZ_PREDICATES))
84             .withChild(ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "baztest")).build();
85     private final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
86             "foo");
87     private final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
88             "bar");
89     private final MapEntryNode bazEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME,
90             "baz");
91     private final MapNode mapNodeBazFuzWithNodes = ImmutableNodes.mapNodeBuilder()
92             .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
93             .withChild(bazEntryNode).withChild(bazEntryNodeWithValue).withChild(fooEntryNode)
94             .build();
95     private final MapNode mapNodeFooWithNodes = ImmutableNodes.mapNodeBuilder()
96             .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
97             .withChild(fooEntryNode).withChild(fooEntryNodeWithValue).withChild(barEntryNode).withChild(bazEntryNode)
98             .build();
99     private final MapNode mapNodeBar = ImmutableNodes.mapNodeBuilder()
100             .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
101             .withChild(barEntryNode).build();
102     private final MapNode mapNodeBaz = ImmutableNodes.mapNodeBuilder()
103             .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
104             .withChild(bazEntryNode).build();
105
106     private static SchemaContext schemaContext;
107
108     private DataTree inMemoryDataTree;
109
110     @BeforeClass
111     public static void beforeClass() {
112         schemaContext = YangParserTestUtils.parseYangResource("/bug-4454-test.yang");
113     }
114
115     @AfterClass
116     public static void afterClass() {
117         schemaContext = null;
118     }
119
120     @Before
121     public void prepare() {
122         inMemoryDataTree =  new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL,
123             schemaContext);
124         final DataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
125         final DataTreeModification modificationTree = initialDataTreeSnapshot.newModification();
126
127         modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
128         modificationTree.ready();
129         inMemoryDataTree.commit(inMemoryDataTree.prepare(modificationTree));
130     }
131
132     @Test
133     public void minMaxListDeleteWriteTest() throws DataValidationFailedException {
134         final DataTreeModification modificationTree1 = inMemoryDataTree.takeSnapshot().newModification();
135
136         Map<QName, Object> key = new HashMap<>();
137         key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
138
139         NodeIdentifierWithPredicates mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME , key);
140
141         final YangInstanceIdentifier minMaxLeafFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
142                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
143
144         key.clear();
145         key.put(MIN_MAX_KEY_LEAF_QNAME, "NON-EXISTING-LEAF");
146
147         mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME, key);
148
149         final YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
150                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2).build();
151
152         final Map<QName, Object> keyTemp = new HashMap<>();
153         keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "baz");
154
155         NodeIdentifierWithPredicates mapEntryPathTest = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME , keyTemp);
156
157         final YangInstanceIdentifier pathToBaz = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
158                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
159
160         keyTemp.clear();
161         keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "bar");
162
163         mapEntryPathTest = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME , keyTemp);
164
165         final YangInstanceIdentifier pathToBar = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
166                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTest).node(MIN_MAX_VALUE_LEAF_QNAME).build();
167
168         keyTemp.clear();
169         keyTemp.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
170
171         final NodeIdentifierWithPredicates mapEntryPathTestKey = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
172             keyTemp);
173
174         final YangInstanceIdentifier pathToKeyFoo = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
175                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPathTestKey).node(MIN_MAX_KEY_LEAF_QNAME).build();
176
177         final LeafNode<String> newNode = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test");
178         final LeafNode<String> newNode1 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test1");
179         final LeafNode<String> newNode2 = ImmutableNodes.leafNode(MIN_MAX_VALUE_LEAF_QNAME, "test2");
180         final LeafNode<String> newNodekey = ImmutableNodes.leafNode(MIN_MAX_KEY_LEAF_QNAME, "foo");
181
182         assertFalse(inMemoryDataTree.toString().contains("list"));
183
184         DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
185         Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
186         assertTrue(!minMaxListRead.isPresent());
187
188         modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
189         modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
190         modificationTree1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
191         modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBar);
192         modificationTree1.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
193         modificationTree1.write(pathToKeyFoo, newNodekey);
194         modificationTree1.write(pathToBaz, newNode2);
195         modificationTree1.write(pathToBaz, newNode1);
196         modificationTree1.write(pathToBaz, newNode);
197         modificationTree1.delete(minMaxLeafFoo);
198         modificationTree1.delete(minMaxLeafNel);
199
200         modificationTree1.ready();
201         inMemoryDataTree.validate(modificationTree1);
202         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree1);
203         inMemoryDataTree.commit(prepare);
204
205         DataTreeSnapshot test = inMemoryDataTree.takeSnapshot();
206         testLoop(test, "bar", "test");
207
208         DataTreeModification tempMod = test.newModification();
209         tempMod.write(pathToBaz, newNode2);
210         tempMod.write(pathToBaz, newNode1);
211         tempMod.merge(pathToBaz, newNode2);
212         tempMod.write(pathToBaz, newNode1);
213
214         tempMod.ready();
215         inMemoryDataTree.validate(tempMod);
216         final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(tempMod);
217         inMemoryDataTree.commit(prepare1);
218
219         DataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
220         testLoop(test1, "bar", "test1");
221
222         DataTreeModification tempMod1 = test1.newModification();
223         tempMod1.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
224
225         tempMod1.ready();
226         inMemoryDataTree.validate(tempMod1);
227         final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
228         inMemoryDataTree.commit(prepare2);
229
230         DataTreeSnapshot test2 = inMemoryDataTree.takeSnapshot();
231         minMaxListRead = test2.readNode(MIN_MAX_LIST_PATH);
232         assertTrue(minMaxListRead.isPresent());
233         assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
234
235         DataTreeModification tempMod2 = test2.newModification();
236         tempMod2.write(MIN_MAX_LIST_PATH, mapNodeBaz);
237         tempMod2.write(pathToBaz, newNode2);
238
239         tempMod2.ready();
240         inMemoryDataTree.validate(tempMod2);
241         final DataTreeCandidate prepare3 = inMemoryDataTree.prepare(tempMod2);
242         inMemoryDataTree.commit(prepare3);
243
244         DataTreeSnapshot test3 = inMemoryDataTree.takeSnapshot();
245         minMaxListRead = test3.readNode(MIN_MAX_LIST_PATH);
246         assertTrue(minMaxListRead.isPresent());
247         assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 1);
248         assertTrue(minMaxListRead.get().getValue().toString().contains("test2"));
249
250         DataTreeModification tempMod3 = test3.newModification();
251         tempMod3.merge(MIN_MAX_LIST_PATH, mapNodeBar);
252         tempMod3.merge(pathToBar, newNode1);
253
254         tempMod3.ready();
255         inMemoryDataTree.validate(tempMod3);
256         final DataTreeCandidate prepare4 = inMemoryDataTree.prepare(tempMod3);
257         inMemoryDataTree.commit(prepare4);
258
259         DataTreeSnapshot test4 = inMemoryDataTree.takeSnapshot();
260         testLoop(test4, "test1", "test2");
261     }
262
263     @Test
264     public void minMaxLeafListPass() throws DataValidationFailedException {
265         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
266
267         final NodeWithValue<?> barPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "bar");
268         final NodeWithValue<?> gooPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "goo");
269
270         final LeafSetEntryNode<Object> barLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
271                 .withNodeIdentifier(barPath)
272                 .withValue("bar").build();
273         final LeafSetEntryNode<Object> gooLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
274                 .withNodeIdentifier(gooPath)
275                 .withValue("goo").build();
276
277         final LeafSetNode<Object> fooLeafSetNode = ImmutableLeafSetNodeBuilder.create()
278                 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
279                 .withChildValue("foo").build();
280
281         modificationTree.write(MIN_MAX_LEAF_LIST_PATH, fooLeafSetNode);
282         modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
283         modificationTree.ready();
284
285         inMemoryDataTree.validate(modificationTree);
286         final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
287         inMemoryDataTree.commit(prepare1);
288
289         DataTreeSnapshot test1 = inMemoryDataTree.takeSnapshot();
290
291         DataTreeModification tempMod1 = test1.newModification();
292         tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(gooPath), gooLeafSetEntry);
293         tempMod1.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
294         tempMod1.ready();
295
296         inMemoryDataTree.validate(tempMod1);
297         final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(tempMod1);
298         inMemoryDataTree.commit(prepare2);
299
300         final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
301         final Optional<NormalizedNode<?, ?>> masterContainer = snapshotAfterCommit.readNode(MASTER_CONTAINER_PATH);
302         assertTrue(masterContainer.isPresent());
303         final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get())
304                 .getChild(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
305         assertTrue(leafList.isPresent());
306         assertTrue(leafList.get().getValue().size() == 3);
307     }
308
309     @Test
310     public void minMaxListDeleteTest() throws DataValidationFailedException {
311         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
312
313
314         NodeIdentifierWithPredicates mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
315             ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "foo"));
316
317         final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
318                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
319
320         mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
321             ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "bar"));
322
323         final YangInstanceIdentifier minMaxLeafBar = MASTER_CONTAINER_PATH
324                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
325
326         mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
327             ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "baz"));
328
329         final YangInstanceIdentifier minMaxLeafBaz = MASTER_CONTAINER_PATH
330                 .node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
331
332         modificationTree.write(MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
333         modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBar);
334         modificationTree.merge(MIN_MAX_LIST_PATH, mapNodeBaz);
335         modificationTree.delete(minMaxLeafFoo);
336         modificationTree.delete(minMaxLeafBar);
337         modificationTree.delete(minMaxLeafBaz);
338
339         modificationTree.ready();
340
341         inMemoryDataTree.validate(modificationTree);
342         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
343         inMemoryDataTree.commit(prepare);
344
345         // Empty list should have disappeared, along with the container, as we are not enforcing root
346         final NormalizedNode<?, ?> data = inMemoryDataTree.takeSnapshot()
347                 .readNode(YangInstanceIdentifier.empty()).get();
348         assertTrue(data instanceof ContainerNode);
349         assertEquals(0, ((ContainerNode) data).getValue().size());
350     }
351
352     @Test
353     public void minMaxListDeleteExceptionTest() throws DataValidationFailedException {
354         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
355
356         NodeIdentifierWithPredicates mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
357             ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "foo"));
358
359         final YangInstanceIdentifier minMaxLeafFoo = PRESENCE_PATH.node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
360
361         mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
362             ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "bar"));
363
364         final YangInstanceIdentifier minMaxLeafBar = PRESENCE_PATH.node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
365
366         mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME,
367             ImmutableMap.of(MIN_MAX_KEY_LEAF_QNAME, "baz"));
368
369         final YangInstanceIdentifier minMaxLeafBaz = PRESENCE_PATH.node(MIN_MAX_LIST_QNAME).node(mapEntryPath2);
370
371         modificationTree.write(PRESENCE_PATH, ImmutableNodes.containerNode(PRESENCE_QNAME));
372         modificationTree.write(PRESENCE_MIN_MAX_LIST_PATH, mapNodeFooWithNodes);
373         modificationTree.merge(PRESENCE_MIN_MAX_LIST_PATH, mapNodeBar);
374         modificationTree.merge(PRESENCE_MIN_MAX_LIST_PATH, mapNodeBaz);
375         modificationTree.delete(minMaxLeafFoo);
376         modificationTree.delete(minMaxLeafBar);
377         modificationTree.delete(minMaxLeafBaz);
378
379         try {
380             // Unlike minMaxListDeleteTest(), presence container enforces the list to be present
381             modificationTree.ready();
382             fail("Should have failed with IAE");
383         } catch (IllegalArgumentException e) {
384             assertEquals("Node (urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model?"
385                     + "revision=2015-02-02)presence is missing mandatory descendant "
386                     + "/(urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model?"
387                     + "revision=2015-02-02)min-max-list", e.getMessage());
388         }
389     }
390
391     @Test
392     public void minMaxListNoMinMaxDeleteTest() throws DataValidationFailedException {
393         final MapEntryNode fooEntryNoMinMaxNode =
394                 ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME_NO_MINMAX, MIN_MAX_KEY_LEAF_QNAME, "foo");
395         final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
396                 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME_NO_MINMAX))
397                 .withChild(fooEntryNoMinMaxNode).build();
398
399         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
400
401         Map<QName, Object> key = new HashMap<>();
402         key.put(MIN_MAX_KEY_LEAF_QNAME, "foo");
403
404         NodeIdentifierWithPredicates mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME_NO_MINMAX, key);
405
406         final YangInstanceIdentifier minMaxLeafFoo = MASTER_CONTAINER_PATH
407                 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2);
408
409         key.clear();
410         key.put(MIN_MAX_KEY_LEAF_QNAME, "non-existing-leaf");
411
412         mapEntryPath2 = NodeIdentifierWithPredicates.of(MIN_MAX_LIST_QNAME_NO_MINMAX, key);
413
414         YangInstanceIdentifier minMaxLeafNel = YangInstanceIdentifier.builder(MASTER_CONTAINER_PATH)
415                 .node(MIN_MAX_LIST_QNAME_NO_MINMAX).node(mapEntryPath2).build();
416
417         modificationTree.write(MIN_MAX_LIST_NO_MINMAX_PATH, mapNode1);
418         modificationTree.delete(minMaxLeafFoo);
419         modificationTree.delete(minMaxLeafNel);
420
421         modificationTree.ready();
422
423         inMemoryDataTree.validate(modificationTree);
424         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
425         inMemoryDataTree.commit(prepare);
426
427         final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
428         final Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_NO_MINMAX_PATH);
429
430         // Empty list should have disappeared
431         assertFalse(minMaxListRead.isPresent());
432     }
433
434     private static void testLoop(final DataTreeSnapshot snapshot, final String first, final String second) {
435         Optional<NormalizedNode<?, ?>> minMaxListRead = snapshot.readNode(MIN_MAX_LIST_PATH);
436         assertTrue(minMaxListRead.isPresent());
437         assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
438         UnmodifiableCollection<?> collectionChildren = (UnmodifiableCollection<?>) minMaxListRead.get().getValue();
439
440         for (Object collectionChild : collectionChildren) {
441             if (collectionChild.toString().contains(first)) {
442                 assertTrue(collectionChild.toString().contains(first));
443             } else {
444                 assertTrue(collectionChild.toString().contains(second));
445             }
446         }
447     }
448 }