Migrate yang-data-tree-ri to JUnit5
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / ConcurrentTreeModificationTest.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.tree.impl;
9
10 import static org.junit.jupiter.api.Assertions.assertFalse;
11 import static org.junit.jupiter.api.Assertions.assertNotNull;
12 import static org.junit.jupiter.api.Assertions.assertTrue;
13 import static org.junit.jupiter.api.Assertions.fail;
14 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
15 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
16
17 import java.util.Optional;
18 import org.junit.jupiter.api.BeforeEach;
19 import org.junit.jupiter.api.Test;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
24 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
25 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
26 import org.opendaylight.yangtools.yang.data.tree.api.ConflictingModificationAppliedException;
27 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
28 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
29 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
30 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
31 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 class ConcurrentTreeModificationTest extends AbstractTestModelTest {
36     private static final Logger LOG = LoggerFactory.getLogger(ConcurrentTreeModificationTest.class);
37
38     private static final Short ONE_ID = 1;
39     private static final Short TWO_ID = 2;
40
41     private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier.builder(
42         TestModel.OUTER_LIST_PATH)
43             .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID)
44             .build();
45
46     private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier.builder(
47         TestModel.OUTER_LIST_PATH)
48             .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID)
49             .build();
50
51     private static final MapEntryNode FOO_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID)
52             .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).build())
53             .build();
54
55     private static final MapEntryNode BAR_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID)
56             .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).build())
57             .build();
58
59     private DataTree inMemoryDataTree;
60
61
62     @BeforeEach
63     void prepare() {
64         inMemoryDataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL,
65             SCHEMA_CONTEXT);
66     }
67
68     private static ContainerNode createFooTestContainerNode() {
69         return Builders.containerBuilder()
70             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
71             .withChild(mapNodeBuilder(TestModel.OUTER_LIST_QNAME).withChild(FOO_NODE).build())
72             .build();
73     }
74
75     private static ContainerNode createBarTestContainerNode() {
76         return Builders.containerBuilder()
77             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
78             .withChild(mapNodeBuilder(TestModel.OUTER_LIST_QNAME).withChild(BAR_NODE).build())
79             .build();
80     }
81
82     private static <T> T assertPresentAndType(final Optional<?> potential, final Class<T> type) {
83         assertNotNull(potential);
84         assertTrue(potential.isPresent());
85         assertTrue(type.isInstance(potential.orElseThrow()));
86         return type.cast(potential.orElseThrow());
87     }
88
89     @Test
90     void writeWrite1stLevelEmptyTreeTest() throws DataValidationFailedException {
91         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
92
93         final var modificationTree1 = initialDataTreeSnapshot.newModification();
94         final var modificationTree2 = initialDataTreeSnapshot.newModification();
95
96         modificationTree1.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
97         modificationTree2.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
98
99         modificationTree1.ready();
100         modificationTree2.ready();
101         inMemoryDataTree.validate(modificationTree1);
102         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
103         inMemoryDataTree.commit(prepare1);
104
105         try {
106             inMemoryDataTree.validate(modificationTree2);
107             fail("Exception should have been thrown.");
108         } catch (final ConflictingModificationAppliedException ex) {
109             LOG.debug("ConflictingModificationAppliedException - was thrown as expected", ex);
110         }
111         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
112         inMemoryDataTree.commit(prepare2);
113
114         final var testNodeAfterCommits = modificationTree1.readNode(TestModel.TEST_PATH);
115         assertPresentAndType(testNodeAfterCommits, ContainerNode.class);
116     }
117
118     @Test
119     void writeMerge1stLevelEmptyTreeTest() throws DataValidationFailedException {
120         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
121
122         final var modificationTree1 = initialDataTreeSnapshot.newModification();
123         final var modificationTree2 = initialDataTreeSnapshot.newModification();
124
125         modificationTree1.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
126         modificationTree2.merge(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
127
128         modificationTree1.ready();
129         modificationTree2.ready();
130
131         inMemoryDataTree.validate(modificationTree1);
132         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
133         inMemoryDataTree.commit(prepare1);
134
135         inMemoryDataTree.validate(modificationTree2);
136         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
137         inMemoryDataTree.commit(prepare2);
138
139         final var testNodeAfterCommits = modificationTree1.readNode(TestModel.TEST_PATH);
140         assertPresentAndType(testNodeAfterCommits, ContainerNode.class);
141     }
142
143     @Test
144     void writeWriteFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
145         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
146
147         final var modificationTree1 = initialDataTreeSnapshot.newModification();
148         final var modificationTree2 = initialDataTreeSnapshot.newModification();
149
150         modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
151         modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
152         modificationTree1.ready();
153         modificationTree2.ready();
154
155         inMemoryDataTree.validate(modificationTree1);
156         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
157         inMemoryDataTree.commit(prepare1);
158
159         try {
160             inMemoryDataTree.validate(modificationTree2);
161             fail("Exception should have been thrown.");
162             final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
163             inMemoryDataTree.commit(prepare2);
164         } catch (final ConflictingModificationAppliedException ex) {
165             LOG.debug("ConflictingModificationAppliedException - was thrown as expected", ex);
166         }
167
168         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
169         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
170         assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
171     }
172
173     @Test
174     void writeMergeFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
175         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
176
177         final var modificationTree1 = initialDataTreeSnapshot.newModification();
178         final var modificationTree2 = initialDataTreeSnapshot.newModification();
179
180         modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
181         modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
182         modificationTree1.ready();
183         modificationTree2.ready();
184
185         inMemoryDataTree.validate(modificationTree1);
186         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
187         inMemoryDataTree.commit(prepare1);
188
189         inMemoryDataTree.validate(modificationTree2);
190         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
191         inMemoryDataTree.commit(prepare2);
192
193         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
194         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
195         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
196     }
197
198     @Test
199     void mergeWriteFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
200         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
201
202         final var modificationTree1 = initialDataTreeSnapshot.newModification();
203         final var modificationTree2 = initialDataTreeSnapshot.newModification();
204
205         modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
206         modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
207         modificationTree1.ready();
208         modificationTree2.ready();
209
210         inMemoryDataTree.validate(modificationTree1);
211         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
212         inMemoryDataTree.commit(prepare1);
213
214         try {
215             inMemoryDataTree.validate(modificationTree2);
216             fail("Exception should have been thrown.");
217             final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
218             inMemoryDataTree.commit(prepare2);
219         } catch (final ConflictingModificationAppliedException ex) {
220             LOG.debug("ConflictingModificationAppliedException - was thrown as expected", ex);
221         }
222
223         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
224         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
225         assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
226     }
227
228     @Test
229     void mergeMergeFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
230         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
231
232         final var modificationTree1 = initialDataTreeSnapshot.newModification();
233         final var modificationTree2 = initialDataTreeSnapshot.newModification();
234
235         modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
236         modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
237         modificationTree1.ready();
238         modificationTree2.ready();
239
240         inMemoryDataTree.validate(modificationTree1);
241         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
242         inMemoryDataTree.commit(prepare1);
243
244         inMemoryDataTree.validate(modificationTree2);
245         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
246         inMemoryDataTree.commit(prepare2);
247
248         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
249         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
250         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
251     }
252
253     @Test
254     void writeWriteFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
255         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
256         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
257         initialDataTreeModification.ready();
258         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
259         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
260
261         final var modificationTree1 = initialDataTreeSnapshot.newModification();
262         final var modificationTree2 = initialDataTreeSnapshot.newModification();
263
264         modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
265         modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
266         modificationTree1.ready();
267         modificationTree2.ready();
268
269         inMemoryDataTree.validate(modificationTree1);
270         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
271         inMemoryDataTree.commit(prepare1);
272
273         try {
274             inMemoryDataTree.validate(modificationTree2);
275             fail("Exception should have been thrown.");
276             final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
277             inMemoryDataTree.commit(prepare2);
278         } catch (final ConflictingModificationAppliedException ex) {
279             LOG.debug("ConflictingModificationAppliedException was thrown as expected", ex);
280         }
281
282         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
283         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
284         assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
285     }
286
287     @Test
288     void writeMergeFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
289         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
290         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
291         initialDataTreeModification.ready();
292         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
293         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
294
295         final var modificationTree1 = initialDataTreeSnapshot.newModification();
296         final var modificationTree2 = initialDataTreeSnapshot.newModification();
297
298         modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
299         modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
300         modificationTree1.ready();
301         modificationTree2.ready();
302
303         inMemoryDataTree.validate(modificationTree1);
304         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
305         inMemoryDataTree.commit(prepare1);
306
307         inMemoryDataTree.validate(modificationTree2);
308         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
309         inMemoryDataTree.commit(prepare2);
310
311         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
312         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
313         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
314     }
315
316     @Test
317     void mergeWriteFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
318         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
319         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
320         initialDataTreeModification.ready();
321         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
322         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
323
324         final var modificationTree1 = initialDataTreeSnapshot.newModification();
325         final var modificationTree2 = initialDataTreeSnapshot.newModification();
326
327         modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
328         modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
329         modificationTree1.ready();
330         modificationTree2.ready();
331
332         inMemoryDataTree.validate(modificationTree1);
333         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
334         inMemoryDataTree.commit(prepare1);
335
336         try {
337             inMemoryDataTree.validate(modificationTree2);
338             fail("Exception should have been thrown.");
339             final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
340             inMemoryDataTree.commit(prepare2);
341         } catch (final ConflictingModificationAppliedException ex) {
342             LOG.debug("ConflictingModificationAppliedException was thrown as expected", ex);
343         }
344
345
346         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
347         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
348         assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
349     }
350
351     @Test
352     void mergeMergeFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
353         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
354         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
355         initialDataTreeModification.ready();
356         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
357         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
358
359         final var modificationTree1 = initialDataTreeSnapshot.newModification();
360         final var modificationTree2 = initialDataTreeSnapshot.newModification();
361
362         modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
363         modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
364         modificationTree1.ready();
365         modificationTree2.ready();
366
367         inMemoryDataTree.validate(modificationTree1);
368         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
369         inMemoryDataTree.commit(prepare1);
370
371         inMemoryDataTree.validate(modificationTree2);
372         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
373         inMemoryDataTree.commit(prepare2);
374
375         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
376         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
377         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
378     }
379
380     @Test
381     void deleteWriteFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
382         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
383         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
384         initialDataTreeModification.ready();
385         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
386         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
387
388         final var modificationTree1 = initialDataTreeSnapshot.newModification();
389         final var modificationTree2 = initialDataTreeSnapshot.newModification();
390
391         modificationTree1.delete(TestModel.TEST_PATH);
392         modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
393         modificationTree1.ready();
394         modificationTree2.ready();
395
396         inMemoryDataTree.validate(modificationTree1);
397         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
398         inMemoryDataTree.commit(prepare1);
399
400         try {
401             inMemoryDataTree.validate(modificationTree2);
402             fail("Exception should have been thrown.");
403             final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
404             inMemoryDataTree.commit(prepare2);
405         } catch (final ConflictingModificationAppliedException ex) {
406             LOG.debug("ConflictingModificationAppliedException was thrown as expected", ex);
407         }
408
409
410         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
411         assertFalse(snapshotAfterCommits.readNode(TestModel.TEST_PATH).isPresent());
412     }
413
414     @Test
415     void deleteMergeFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
416         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
417         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
418         initialDataTreeModification.ready();
419         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
420         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
421
422         final var modificationTree1 = initialDataTreeSnapshot.newModification();
423         final var modificationTree2 = initialDataTreeSnapshot.newModification();
424
425         modificationTree1.delete(TestModel.TEST_PATH);
426         modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
427         modificationTree1.ready();
428         modificationTree2.ready();
429
430         inMemoryDataTree.validate(modificationTree1);
431         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
432         inMemoryDataTree.commit(prepare1);
433
434         inMemoryDataTree.validate(modificationTree2);
435         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
436         inMemoryDataTree.commit(prepare2);
437
438         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
439         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
440     }
441
442     @Test
443     void writeWriteFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
444         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
445         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
446         initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
447             .build());
448         initialDataTreeModification.ready();
449         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
450         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
451
452         final var modificationTree1 = initialDataTreeSnapshot.newModification();
453         final var modificationTree2 = initialDataTreeSnapshot.newModification();
454
455         modificationTree1.write(OUTER_LIST_1_PATH, FOO_NODE);
456         modificationTree2.write(OUTER_LIST_2_PATH, BAR_NODE);
457         modificationTree1.ready();
458         modificationTree2.ready();
459
460         inMemoryDataTree.validate(modificationTree1);
461         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
462         inMemoryDataTree.commit(prepare1);
463
464         inMemoryDataTree.validate(modificationTree2);
465         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
466         inMemoryDataTree.commit(prepare2);
467
468         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
469         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
470         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
471     }
472
473     @Test
474     void writeMergeFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
475         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
476         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
477         initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
478             .build());
479         initialDataTreeModification.ready();
480         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
481         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
482
483         final var modificationTree1 = initialDataTreeSnapshot.newModification();
484         final var modificationTree2 = initialDataTreeSnapshot.newModification();
485
486         modificationTree1.write(OUTER_LIST_1_PATH, FOO_NODE);
487         modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
488         modificationTree1.ready();
489         modificationTree2.ready();
490
491         inMemoryDataTree.validate(modificationTree1);
492         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
493         inMemoryDataTree.commit(prepare1);
494
495         inMemoryDataTree.validate(modificationTree2);
496         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
497         inMemoryDataTree.commit(prepare2);
498
499         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
500         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
501         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
502     }
503
504     @Test
505     void mergeWriteFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
506         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
507         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
508         initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
509             .build());
510         initialDataTreeModification.ready();
511         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
512         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
513
514         final var modificationTree1 = initialDataTreeSnapshot.newModification();
515         final var modificationTree2 = initialDataTreeSnapshot.newModification();
516
517         modificationTree1.merge(OUTER_LIST_1_PATH, FOO_NODE);
518         modificationTree2.write(OUTER_LIST_2_PATH, BAR_NODE);
519         modificationTree1.ready();
520         modificationTree2.ready();
521
522         inMemoryDataTree.validate(modificationTree1);
523         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
524         inMemoryDataTree.commit(prepare1);
525
526         inMemoryDataTree.validate(modificationTree2);
527         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
528         inMemoryDataTree.commit(prepare2);
529
530         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
531         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
532         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
533     }
534
535     @Test
536     void mergeMergeFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
537         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
538         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
539         initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
540             .build());
541         initialDataTreeModification.ready();
542         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
543         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
544
545         final var modificationTree1 = initialDataTreeSnapshot.newModification();
546         final var modificationTree2 = initialDataTreeSnapshot.newModification();
547
548         modificationTree1.merge(OUTER_LIST_1_PATH, FOO_NODE);
549         modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
550         modificationTree1.ready();
551         modificationTree2.ready();
552
553         inMemoryDataTree.validate(modificationTree1);
554         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
555         inMemoryDataTree.commit(prepare1);
556
557         inMemoryDataTree.validate(modificationTree2);
558         final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
559         inMemoryDataTree.commit(prepare2);
560
561         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
562         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
563         assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
564     }
565
566     @Test
567     void deleteWriteFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
568         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
569         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
570         initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
571             .build());
572         initialDataTreeModification.ready();
573         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
574         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
575
576         final var modificationTree1 = initialDataTreeSnapshot.newModification();
577         final var modificationTree2 = initialDataTreeSnapshot.newModification();
578
579         modificationTree1.delete(TestModel.TEST_PATH);
580         modificationTree2.write(OUTER_LIST_2_PATH, BAR_NODE);
581         modificationTree1.ready();
582         modificationTree2.ready();
583
584         inMemoryDataTree.validate(modificationTree1);
585         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
586         inMemoryDataTree.commit(prepare1);
587
588         try {
589             inMemoryDataTree.validate(modificationTree2);
590             final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
591             inMemoryDataTree.commit(prepare2);
592             fail("Exception should have been thrown");
593         } catch (final ConflictingModificationAppliedException e) {
594             LOG.debug("Exception was thrown because path no longer exist in tree", e);
595         }
596
597         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
598         assertFalse(snapshotAfterCommits.readNode(TestModel.TEST_PATH).isPresent());
599     }
600
601     @Test
602     void deleteMergeFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
603         final var initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
604         initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
605         initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
606             .build());
607         initialDataTreeModification.ready();
608         inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
609         final var initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
610
611         final var modificationTree1 = initialDataTreeSnapshot.newModification();
612         final var modificationTree2 = initialDataTreeSnapshot.newModification();
613
614         modificationTree1.delete(TestModel.TEST_PATH);
615         modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
616         modificationTree1.ready();
617         modificationTree2.ready();
618
619         inMemoryDataTree.validate(modificationTree1);
620         final var prepare1 = inMemoryDataTree.prepare(modificationTree1);
621         inMemoryDataTree.commit(prepare1);
622
623         try {
624             inMemoryDataTree.validate(modificationTree2);
625             final var prepare2 = inMemoryDataTree.prepare(modificationTree2);
626             inMemoryDataTree.commit(prepare2);
627             fail("Exception should have been thrown");
628         } catch (final ConflictingModificationAppliedException e) {
629             LOG.debug("Exception was thrown because path no longer exist in tree", e);
630         }
631
632         final var snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
633         assertFalse(snapshotAfterCommits.readNode(TestModel.TEST_PATH).isPresent());
634     }
635 }