Do not generate 'isFoo()' methods
[mdsal.git] / dom / mdsal-dom-broker / src / test / java / org / opendaylight / mdsal / dom / broker / ShardedDOMDataTreeProducerMultiShardTest.java
1 /*
2  * Copyright (c) 2016 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.mdsal.dom.broker;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.ArgumentMatchers.anyCollection;
14 import static org.mockito.ArgumentMatchers.anyMap;
15 import static org.mockito.Mockito.doNothing;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.inOrder;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.timeout;
20 import static org.mockito.Mockito.verify;
21 import static org.mockito.Mockito.verifyNoMoreInteractions;
22
23 import com.google.common.collect.Iterables;
24 import com.google.common.util.concurrent.Futures;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.Captor;
35 import org.mockito.InOrder;
36 import org.mockito.MockitoAnnotations;
37 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
39 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
40 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
41 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor;
42 import org.opendaylight.mdsal.dom.broker.util.TestModel;
43 import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardProducer;
44 import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardWriteTransaction;
45 import org.opendaylight.mdsal.dom.spi.shard.WriteableDOMDataTreeShard;
46 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataTreeShard;
47 import org.opendaylight.yangtools.concepts.ListenerRegistration;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
51 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
55 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
56 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
57 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
58
59 public class ShardedDOMDataTreeProducerMultiShardTest extends AbstractDatastoreTest {
60
61     private static final DOMDataTreeIdentifier ROOT_ID =
62             new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.empty());
63     private static final DOMDataTreeIdentifier TEST_ID =
64             new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TestModel.TEST_PATH);
65
66     private static final DOMDataTreeIdentifier TEST2_ID =
67             new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TestModel.TEST2_PATH);
68
69     private static final DOMDataTreeIdentifier INNER_CONTAINER_ID =
70             new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TestModel.INNER_CONTAINER_PATH);
71     private static final DOMDataTreeIdentifier ANOTHER_SHARD_ID =
72             new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TestModel.ANOTHER_SHARD_PATH);
73
74     private InMemoryDOMDataTreeShard rootShard;
75     private InMemoryDOMDataTreeShard anotherInnerShard;
76
77     private ShardedDOMDataTree dataTreeService;
78     private ListenerRegistration<InMemoryDOMDataTreeShard> rootShardReg;
79     private ListenerRegistration<InMemoryDOMDataTreeShard> innerShardReg;
80
81     private final ExecutorService executor = Executors.newSingleThreadExecutor();
82
83     @Captor
84     private ArgumentCaptor<Collection<DataTreeCandidate>> captorForChanges;
85     @Captor
86     private ArgumentCaptor<Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>>> captorForSubtrees;
87
88     private final ContainerNode crossShardContainer = createCrossShardContainer();
89
90     @Before
91     public void setUp() throws Exception {
92         MockitoAnnotations.initMocks(this);
93
94         rootShard = InMemoryDOMDataTreeShard.create(ROOT_ID, executor, 1);
95         rootShard.onModelContextUpdated(SCHEMA_CONTEXT);
96
97         final ShardedDOMDataTree dataTree = new ShardedDOMDataTree();
98         final DOMDataTreeProducer shardRegProducer = dataTree.createProducer(Collections.singletonList(ROOT_ID));
99         rootShardReg = dataTree.registerDataTreeShard(ROOT_ID, rootShard, shardRegProducer);
100         shardRegProducer.close();
101
102         dataTreeService = dataTree;
103     }
104
105     @Test(expected = IllegalStateException.class)
106     public void testTxReadyMultiples() throws Exception {
107         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
108         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
109         final DOMDataTreeWriteCursor cursor = transaction.createCursor(ROOT_ID);
110
111         final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
112                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
113                 .build();
114         cursor.write(TestModel.TEST_PATH.getLastPathArgument(), testContainer);
115         transaction.ready();
116
117         transaction.ready();
118     }
119
120     @Test(expected = IllegalStateException.class)
121     public void testSubmitUnclosedCursor() throws Exception {
122         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
123         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
124         final DOMDataTreeWriteCursor cursor = transaction.createCursor(ROOT_ID);
125
126         final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
127                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
128                 .build();
129
130         cursor.write(TestModel.TEST_PATH.getLastPathArgument(), testContainer);
131         transaction.ready();
132     }
133
134     @Test
135     public void testMultipleCursorsFromOneTx() throws Exception {
136         final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
137         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
138
139         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(INNER_CONTAINER_ID),
140                 true, Collections.emptyList());
141
142         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
143         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
144         final DOMDataTreeWriteCursor cursor = transaction.createCursor(ROOT_ID);
145
146         final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
147                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
148                 .build();
149
150         cursor.write(TestModel.TEST_PATH.getLastPathArgument(), testContainer);
151         cursor.close();
152
153         final DOMDataTreeWriteCursor newCursor = transaction.createCursor(ROOT_ID);
154         newCursor.enter(TestModel.TEST_PATH.getLastPathArgument());
155         final ContainerNode innerContainer = ImmutableContainerNodeBuilder.create()
156                 .withNodeIdentifier(new NodeIdentifier(TestModel.INNER_CONTAINER))
157                 .withChild(ImmutableLeafNodeBuilder.<String>create()
158                         .withNodeIdentifier(new NodeIdentifier(TestModel.SHARDED_VALUE_1))
159                         .withValue("inner-value")
160                         .build())
161                 .build();
162
163         newCursor.write(TestModel.INNER_CONTAINER_PATH.getLastPathArgument(), innerContainer);
164         newCursor.close();
165         transaction.ready();
166         transaction.submit();
167
168         verify(mockedDataTreeListener, timeout(1000).times(2)).onDataTreeChanged(
169                 captorForChanges.capture(), captorForSubtrees.capture());
170         final Collection<DataTreeCandidate> capturedValue = captorForChanges.getValue();
171         assertTrue(capturedValue.size() == 1);
172
173         final ContainerNode dataAfter =
174                 (ContainerNode) capturedValue.iterator().next().getRootNode().getDataAfter().get();
175         assertEquals(innerContainer, dataAfter);
176         verifyNoMoreInteractions(mockedDataTreeListener);
177     }
178
179     @Test
180     public void testSingleShardListener() throws Exception {
181         final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
182         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
183
184         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(INNER_CONTAINER_ID), true,
185                 Collections.emptyList());
186
187         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
188         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
189         writeCrossShardContainer(transaction);
190
191         verify(mockedDataTreeListener, timeout(1000).times(2)).onDataTreeChanged(
192                 captorForChanges.capture(), captorForSubtrees.capture());
193         final Collection<DataTreeCandidate> capturedValue = captorForChanges.getValue();
194         assertTrue(capturedValue.size() == 1);
195
196         final ContainerNode dataAfter =
197                 (ContainerNode) capturedValue.iterator().next().getRootNode().getDataAfter().get();
198         assertEquals(crossShardContainer.getChild(
199                 TestModel.INNER_CONTAINER_PATH.getLastPathArgument()).get(), dataAfter);
200
201         final Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>> capturedSubtrees = captorForSubtrees.getValue();
202         assertTrue(capturedSubtrees.size() == 1);
203         assertTrue(capturedSubtrees.containsKey(INNER_CONTAINER_ID));
204         assertEquals(crossShardContainer.getChild(TestModel.INNER_CONTAINER_PATH.getLastPathArgument()).get(),
205                 capturedSubtrees.get(INNER_CONTAINER_ID));
206
207         verifyNoMoreInteractions(mockedDataTreeListener);
208     }
209
210     @Test
211     public void testMultipleShards() throws Exception {
212         final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
213         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
214
215         final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1);
216         innerShard.onModelContextUpdated(SCHEMA_CONTEXT);
217         final DOMDataTreeProducer shardRegProducer =
218                 dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
219         innerShardReg = dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, shardRegProducer);
220         shardRegProducer.close();
221
222         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(TEST_ID),
223                 true, Collections.emptyList());
224
225         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
226         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
227         writeCrossShardContainer(transaction);
228
229         final ContainerNode testContainerVerificationNode = ImmutableContainerNodeBuilder.create()
230                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
231                 .build();
232
233         //verify listeners have been notified
234         verify(mockedDataTreeListener, timeout(1000).times(4)).onDataTreeChanged(
235                 captorForChanges.capture(), captorForSubtrees.capture());
236         final List<Collection<DataTreeCandidate>> capturedChanges = captorForChanges.getAllValues();
237         final List<Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>>> capturedSubtrees =
238                 captorForSubtrees.getAllValues();
239         final DataTreeCandidate firstNotificationCandidate = capturedChanges.get(2).iterator().next();
240
241         assertTrue(capturedSubtrees.get(2).size() == 1);
242         assertEquals(testContainerVerificationNode, firstNotificationCandidate.getRootNode().getDataAfter().get());
243         assertEquals(testContainerVerificationNode, capturedSubtrees.get(2).get(TEST_ID));
244
245         final DataTreeCandidate secondNotificationCandidate = capturedChanges.get(3).iterator().next();
246         assertTrue(capturedSubtrees.get(3).size() == 1);
247         assertEquals(crossShardContainer, secondNotificationCandidate.getRootNode().getDataAfter().get());
248         assertEquals(crossShardContainer, capturedSubtrees.get(3).get(TEST_ID));
249
250         verifyNoMoreInteractions(mockedDataTreeListener);
251     }
252
253     @Test
254     public void testMultipleShardsProducerClose() throws Exception {
255         final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1);
256         innerShard.onModelContextUpdated(SCHEMA_CONTEXT);
257
258         assertTrue(rootShard.getProducers().isEmpty());
259
260         final DOMDataTreeProducer innerShardRegProducer =
261                 dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
262         assertTrue(rootShard.getProducers().size() == 1);
263         final DOMDataTreeShardProducer rootShardProducer = Iterables.getOnlyElement(rootShard.getProducers());
264         assertEquals(rootShardProducer.getPrefixes().toString(),
265                 Collections.singletonList(INNER_CONTAINER_ID).toString());
266
267         dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, innerShardRegProducer);
268
269         assertTrue(rootShard.getProducers().isEmpty());
270         assertTrue(innerShard.getProducers().size() == 1);
271         final DOMDataTreeShardProducer innerShardProducer = Iterables.getOnlyElement(innerShard.getProducers());
272         assertEquals(innerShardProducer.getPrefixes().toString(),
273                 Collections.singletonList(INNER_CONTAINER_ID).toString());
274
275         innerShardRegProducer.close();
276         assertTrue(rootShard.getProducers().isEmpty());
277         assertTrue(innerShard.getProducers().isEmpty());
278
279         final DOMDataTreeProducer testProducer =
280                 dataTreeService.createProducer(Collections.singletonList(TEST_ID));
281         assertTrue(rootShard.getProducers().size() == 1);
282         final DOMDataTreeShardProducer rootShardProducer2 = Iterables.getOnlyElement(rootShard.getProducers());
283         assertEquals(rootShardProducer2.getPrefixes().toString(),
284                 Collections.singletonList(TEST_ID).toString());
285
286         assertTrue(innerShard.getProducers().size() == 1);
287         final DOMDataTreeShardProducer innerShardProducer2 = Iterables.getOnlyElement(innerShard.getProducers());
288         assertEquals(innerShardProducer2.getPrefixes().toString(),
289                 Collections.singletonList(INNER_CONTAINER_ID).toString());
290
291         testProducer.close();
292         assertTrue(rootShard.getProducers().isEmpty());
293         assertTrue(innerShard.getProducers().isEmpty());
294     }
295
296     @Test
297     public void testMultipleShardsChildProducerClose() throws Exception {
298         final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1);
299         innerShard.onModelContextUpdated(SCHEMA_CONTEXT);
300
301         final DOMDataTreeProducer innerShardRegProducer =
302                 dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
303         dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, innerShardRegProducer);
304         innerShardRegProducer.close();
305         assertTrue(rootShard.getProducers().isEmpty());
306         assertTrue(innerShard.getProducers().isEmpty());
307
308         final DOMDataTreeProducer testProducer =
309                 dataTreeService.createProducer(Collections.singletonList(TEST_ID));
310         final DOMDataTreeProducer testChildProducer = testProducer.createProducer(
311                 Collections.singletonList(INNER_CONTAINER_ID));
312         assertTrue(rootShard.getProducers().size() == 1);
313         assertTrue(innerShard.getProducers().size() == 2);
314
315         final DOMDataTreeShardProducer rootShardProducer = Iterables.getOnlyElement(rootShard.getProducers());
316         assertEquals(rootShardProducer.getPrefixes().toString(),
317                 Collections.singletonList(TEST_ID).toString());
318
319         for (DOMDataTreeShardProducer producer : innerShard.getProducers()) {
320             assertEquals(producer.getPrefixes().toString(),
321                     Collections.singletonList(INNER_CONTAINER_ID).toString());
322         }
323
324         testProducer.close();
325         assertTrue(rootShard.getProducers().isEmpty());
326         assertTrue(innerShard.getProducers().size() == 1);
327         final DOMDataTreeShardProducer innerShardProducer = Iterables.getOnlyElement(innerShard.getProducers());
328         assertEquals(innerShardProducer.getPrefixes().toString(),
329                 Collections.singletonList(INNER_CONTAINER_ID).toString());
330
331         testChildProducer.close();
332         assertTrue(rootShard.getProducers().isEmpty());
333         assertTrue(innerShard.getProducers().isEmpty());
334     }
335
336     @Test
337     public void testMultipleShardsProducerCloseForSubshardAttached() throws Exception {
338         final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1);
339         innerShard.onModelContextUpdated(SCHEMA_CONTEXT);
340
341         final DOMDataTreeProducer innerShardRegProducer =
342                 dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
343         dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, innerShardRegProducer);
344         innerShardRegProducer.close();
345         assertTrue(rootShard.getProducers().isEmpty());
346         assertTrue(innerShard.getProducers().isEmpty());
347
348         final DOMDataTreeProducer testProducer =
349                 dataTreeService.createProducer(Collections.singletonList(TEST_ID));
350         assertTrue(rootShard.getProducers().size() == 1);
351         assertTrue(innerShard.getProducers().size() == 1);
352
353         final DOMDataTreeShardProducer rootShardProducer = Iterables.getOnlyElement(rootShard.getProducers());
354         assertEquals(rootShardProducer.getPrefixes().toString(),
355                 Collections.singletonList(TEST_ID).toString());
356
357         final DOMDataTreeShardProducer innerShardProducer = Iterables.getOnlyElement(innerShard.getProducers());
358         assertEquals(innerShardProducer.getPrefixes().toString(),
359                 Collections.singletonList(INNER_CONTAINER_ID).toString());
360
361         final InMemoryDOMDataTreeShard test2Shard = InMemoryDOMDataTreeShard.create(TEST2_ID, executor, 1);
362         innerShard.onModelContextUpdated(SCHEMA_CONTEXT);
363
364         final DOMDataTreeProducer test2ShardRegProducer =
365                 dataTreeService.createProducer(Collections.singletonList(TEST2_ID));
366         dataTreeService.registerDataTreeShard(TEST2_ID, test2Shard, test2ShardRegProducer);
367         test2ShardRegProducer.close();
368
369         assertTrue(rootShard.getProducers().size() == 1);
370         assertTrue(innerShard.getProducers().size() == 1);
371
372         final DOMDataTreeShardProducer rootShardProducer2 = Iterables.getOnlyElement(rootShard.getProducers());
373         assertEquals(rootShardProducer2.getPrefixes().toString(),
374                 Collections.singletonList(TEST_ID).toString());
375
376         final DOMDataTreeShardProducer innerShardProducer2 = Iterables.getOnlyElement(innerShard.getProducers());
377         assertEquals(innerShardProducer2.getPrefixes().toString(),
378                 Collections.singletonList(INNER_CONTAINER_ID).toString());
379     }
380
381     @Test
382     public void testMultipleWritesIntoSingleShard() throws Exception {
383         final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
384         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
385
386         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(INNER_CONTAINER_ID),
387                 true, Collections.emptyList());
388
389         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
390         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
391         writeCrossShardContainer(transaction);
392
393         final DOMDataTreeShardWriteTransaction newTx = producer.createTransaction();
394         final DOMDataTreeWriteCursor newCursor = newTx.createCursor(ROOT_ID);
395
396         newCursor.delete(TestModel.TEST_PATH.getLastPathArgument());
397     }
398
399     @Test
400     public void testMockedSubshards() throws Exception {
401         final WriteableDOMDataTreeShard mockedInnerShard = mock(WriteableDOMDataTreeShard.class);
402         final DOMDataTreeShardProducer mockedProducer = mock(DOMDataTreeShardProducer.class);
403         doReturn(mockedProducer).when(mockedInnerShard).createProducer(anyCollection());
404         final ShardedDOMDataTreeProducer shardRegProducer = mock(ShardedDOMDataTreeProducer.class);
405         doReturn(Collections.singleton(INNER_CONTAINER_ID)).when(shardRegProducer).getSubtrees();
406         doNothing().when(shardRegProducer).subshardAdded(anyMap());
407
408         dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, mockedInnerShard, shardRegProducer);
409
410         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
411
412         final DOMDataTreeShardWriteTransaction transaction = producer.createTransaction();
413         final DOMDataTreeWriteCursor cursor = transaction.createCursor(ROOT_ID);
414         cursor.enter(TestModel.TEST_PATH.getLastPathArgument());
415
416         final LeafNode<String> shardedValue1 =
417                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(
418                         new NodeIdentifier(TestModel.SHARDED_VALUE_1)).withValue("sharded value 1").build();
419         final LeafNode<String> shardedValue2 =
420                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(
421                         new NodeIdentifier(TestModel.SHARDED_VALUE_2)).withValue("sharded value 2").build();
422
423         final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerNodeBuilder =
424                 ImmutableContainerNodeBuilder.create();
425         final ContainerNode containerNode =
426                 containerNodeBuilder
427                         .withNodeIdentifier(new NodeIdentifier(TestModel.INNER_CONTAINER))
428                         .withChild(shardedValue1)
429                         .withChild(shardedValue2)
430                         .build();
431
432         final DOMDataTreeShardWriteTransaction mockedTx = mock(DOMDataTreeShardWriteTransaction.class);
433         doReturn(mockedTx).when(mockedProducer).createTransaction();
434
435         doNothing().when(mockedTx).ready();
436         doReturn(Futures.immediateFuture(true)).when(mockedTx).validate();
437         doReturn(Futures.immediateFuture(null)).when(mockedTx).prepare();
438         doReturn(Futures.immediateFuture(null)).when(mockedTx).commit();
439
440         final DOMDataTreeWriteCursor mockedCursor = mock(DOMDataTreeWriteCursor.class);
441         doNothing().when(mockedCursor).write(any(PathArgument.class), any(NormalizedNode.class));
442         doNothing().when(mockedCursor).close();
443         doReturn(mockedCursor).when(mockedTx).createCursor(any(DOMDataTreeIdentifier.class));
444
445         cursor.write(TestModel.INNER_CONTAINER_PATH.getLastPathArgument(), containerNode);
446         cursor.enter(TestModel.INNER_CONTAINER_PATH.getLastPathArgument());
447
448         final ContainerNode lowerShardContainer = ImmutableContainerNodeBuilder.create()
449                 .withNodeIdentifier(new NodeIdentifier(TestModel.ANOTHER_SHARD_CONTAINER))
450                 .withChild(ImmutableLeafNodeBuilder.create().withNodeIdentifier(
451                         new NodeIdentifier(TestModel.ANOTHER_SHARD_VALUE)).withValue("").build())
452                 .build();
453
454         cursor.write(TestModel.ANOTHER_SHARD_PATH.getLastPathArgument(), lowerShardContainer);
455         cursor.close();
456         transaction.ready();
457         transaction.submit().get();
458
459         final InOrder inOrder = inOrder(mockedTx);
460         inOrder.verify(mockedTx).ready();
461         inOrder.verify(mockedTx).validate();
462         inOrder.verify(mockedTx).prepare();
463         inOrder.verify(mockedTx).commit();
464
465     }
466
467     private static ContainerNode createCrossShardContainer() {
468         final LeafNode<String> shardedValue1 =
469                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(
470                         new NodeIdentifier(TestModel.SHARDED_VALUE_1)).withValue("sharded value 1").build();
471         final LeafNode<String> shardedValue2 =
472                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(new NodeIdentifier(
473                         TestModel.SHARDED_VALUE_2)).withValue("sharded value 2").build();
474
475
476         final ContainerNode lowerShardContainer = ImmutableContainerNodeBuilder.create()
477                 .withNodeIdentifier(new NodeIdentifier(TestModel.ANOTHER_SHARD_CONTAINER))
478                 .withChild(ImmutableLeafNodeBuilder.create()
479                         .withNodeIdentifier(new NodeIdentifier(TestModel.ANOTHER_SHARD_VALUE))
480                         .withValue("testing-value")
481                         .build())
482                 .build();
483
484         final ContainerNode containerNode =
485                 ImmutableContainerNodeBuilder.create()
486                         .withNodeIdentifier(new NodeIdentifier(TestModel.INNER_CONTAINER))
487                         .withChild(shardedValue1)
488                         .withChild(shardedValue2)
489                         .withChild(lowerShardContainer)
490                         .build();
491
492         final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
493                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
494                 .withChild(containerNode)
495                 .build();
496
497         return testContainer;
498     }
499
500     private void writeCrossShardContainer(final DOMDataTreeShardWriteTransaction transaction) throws Exception {
501         final DOMDataTreeWriteCursor cursor = transaction.createCursor(ROOT_ID);
502
503         cursor.write(TestModel.TEST_PATH.getLastPathArgument(), crossShardContainer);
504
505         cursor.close();
506         transaction.ready();
507         transaction.submit().get();
508     }
509 }