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