Revert "Fix broken tests according to yangtools...
[mdsal.git] / dom / mdsal-dom-broker / src / test / java / org / opendaylight / mdsal / dom / broker / ShardedDOMDataTreeTest.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.assertNotNull;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Matchers.any;
15 import static org.mockito.Matchers.anyCollection;
16 import static org.mockito.Matchers.anyMap;
17 import static org.mockito.Mockito.doNothing;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.timeout;
20 import static org.mockito.Mockito.times;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.verifyNoMoreInteractions;
23
24 import com.google.common.util.concurrent.ListenableFuture;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Executors;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.mockito.ArgumentCaptor;
35 import org.mockito.Captor;
36 import org.mockito.MockitoAnnotations;
37 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
39 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
40 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
41 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
42 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor;
43 import org.opendaylight.mdsal.dom.broker.util.TestModel;
44 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataTreeShard;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.common.QName;
47 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
50 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
56 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
57 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
58 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
59 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
60 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
61 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 public class ShardedDOMDataTreeTest {
66
67     private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataTreeProducerMultiShardTest.class);
68
69     private static SchemaContext schemaContext = null;
70
71     static {
72         try {
73             schemaContext = TestModel.createTestContext();
74         } catch (final ReactorException e) {
75             LOG.error("Unable to create schema context for TestModel", e);
76         }
77     }
78
79     private static final DOMDataTreeIdentifier ROOT_ID =
80             new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.EMPTY);
81     private static final DOMDataTreeIdentifier TEST_ID =
82             new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
83
84     private static final DOMDataTreeIdentifier INNER_CONTAINER_ID =
85             new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.INNER_CONTAINER_PATH);
86
87     private static final YangInstanceIdentifier OUTER_LIST_YID = TestModel.OUTER_LIST_PATH.node(
88             new NodeIdentifierWithPredicates(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1));
89     private static final DOMDataTreeIdentifier OUTER_LIST_ID =
90             new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, OUTER_LIST_YID);
91
92     private InMemoryDOMDataTreeShard rootShard;
93
94     private ShardedDOMDataTree dataTreeService;
95     private ListenerRegistration<InMemoryDOMDataTreeShard> rootShardReg;
96
97     private final ExecutorService executor = Executors.newSingleThreadExecutor();
98
99     @Captor
100     private ArgumentCaptor<Collection<DataTreeCandidate>> captorForChanges;
101     @Captor
102     private ArgumentCaptor<Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>>> captorForSubtrees;
103
104     private final ContainerNode crossShardContainer = createCrossShardContainer();
105
106     @Before
107     public void setUp() throws Exception {
108         MockitoAnnotations.initMocks(this);
109
110         rootShard = InMemoryDOMDataTreeShard.create(ROOT_ID, executor, 1);
111         rootShard.onGlobalContextUpdated(schemaContext);
112
113         final ShardedDOMDataTree dataTree = new ShardedDOMDataTree();
114         final DOMDataTreeProducer shardRegProducer = dataTree.createProducer(Collections.singletonList(ROOT_ID));
115         rootShardReg = dataTree.registerDataTreeShard(ROOT_ID, rootShard, shardRegProducer);
116         shardRegProducer.close();
117
118         dataTreeService = dataTree;
119     }
120
121     @Test(expected = IllegalArgumentException.class)
122     public void testProducerPathContention() throws Exception {
123         dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
124         dataTreeService.createProducer(Collections.singletonList(TEST_ID));
125     }
126
127     @Test
128     public void testShardRegistrationClose() throws Exception {
129         rootShardReg.close();
130
131         final InMemoryDOMDataTreeShard newRootShard = InMemoryDOMDataTreeShard.create(ROOT_ID, executor, 1);
132         newRootShard.onGlobalContextUpdated(schemaContext);
133         final DOMDataTreeProducer shardRegProducer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
134
135         final ListenerRegistration<InMemoryDOMDataTreeShard> newRootShardReg =
136                 dataTreeService.registerDataTreeShard(ROOT_ID, rootShard, shardRegProducer);
137         shardRegProducer.close();
138
139         final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1);
140         innerShard.onGlobalContextUpdated(schemaContext);
141         final DOMDataTreeProducer shardRegProducer2 =
142                 dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
143         ListenerRegistration<InMemoryDOMDataTreeShard> innerShardReg =
144                 dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, shardRegProducer2);
145
146         innerShardReg.close();
147         // try to register the shard again
148         innerShardReg = dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, shardRegProducer2);
149         final DOMDataTreeCursorAwareTransaction tx = shardRegProducer2.createTransaction(false);
150         final DOMDataTreeWriteCursor cursor = tx.createCursor(INNER_CONTAINER_ID);
151         assertNotNull(cursor);
152
153         cursor.close();
154         tx.cancel();
155         shardRegProducer2.close();
156
157         innerShardReg.close();
158         newRootShardReg.close();
159     }
160
161     @Test(expected = IllegalStateException.class)
162     public void testEmptyShardMapProducer() throws Exception {
163         final ShardedDOMDataTree dataTree = new ShardedDOMDataTree();
164         final DOMDataTreeProducer producer = dataTree.createProducer(Collections.singletonList(ROOT_ID));
165         producer.createTransaction(false);
166     }
167
168     @Test
169     public void testSingleShardWrite() throws Exception {
170         final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
171         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
172
173         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(INNER_CONTAINER_ID),
174                 true, Collections.emptyList());
175
176         final DOMDataTreeProducer producer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
177         DOMDataTreeCursorAwareTransaction tx = producer.createTransaction(false);
178         DOMDataTreeWriteCursor cursor = tx.createCursor(ROOT_ID);
179         assertNotNull(cursor);
180
181         cursor.write(TEST_ID.getRootIdentifier().getLastPathArgument(), crossShardContainer);
182
183         try {
184             tx.submit().checkedGet();
185             fail("There's still an open cursor");
186         } catch (final IllegalStateException e) {
187             assertTrue(e.getMessage().contains("cursor open"));
188         }
189
190         cursor.close();
191         tx.submit().get();
192
193         tx = producer.createTransaction(false);
194         cursor = tx.createCursor(TEST_ID);
195         assertNotNull(cursor);
196
197         cursor.delete(TestModel.INNER_CONTAINER_PATH.getLastPathArgument());
198         cursor.close();
199         tx.submit().get();
200
201         verify(mockedDataTreeListener, timeout(1000).times(3)).onDataTreeChanged(captorForChanges.capture(),
202                 captorForSubtrees.capture());
203         final List<Collection<DataTreeCandidate>> capturedValue = captorForChanges.getAllValues();
204         assertTrue(capturedValue.size() == 3);
205
206         final ContainerNode capturedChange =
207                 (ContainerNode) capturedValue.get(1).iterator().next().getRootNode().getDataAfter().get();
208         final ContainerNode innerContainerVerify = (ContainerNode) crossShardContainer.getChild(
209                 TestModel.INNER_CONTAINER_PATH.getLastPathArgument()).get();
210         assertEquals(innerContainerVerify, capturedChange);
211
212         verifyNoMoreInteractions(mockedDataTreeListener);
213     }
214
215     @Test
216     // TODO extract common logic from testSingleSubshardWrite and
217     // testSingleShardWrite tests
218     public void testSingleSubshardWrite() throws Exception {
219         final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
220         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
221
222         InMemoryDOMDataTreeShard testShard = InMemoryDOMDataTreeShard.create(TEST_ID, executor, 1);
223         testShard.onGlobalContextUpdated(schemaContext);
224
225         final DOMDataTreeProducer regProducer = dataTreeService.createProducer(Collections.singleton(TEST_ID));
226         dataTreeService.registerDataTreeShard(TEST_ID, testShard, regProducer);
227         regProducer.close();
228
229         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(TEST_ID),
230                 true, Collections.emptyList());
231
232         final DOMDataTreeProducer producer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
233         DOMDataTreeCursorAwareTransaction tx = producer.createTransaction(false);
234         DOMDataTreeWriteCursor cursor = tx.createCursor(ROOT_ID);
235         assertNotNull(cursor);
236
237         cursor.write(TEST_ID.getRootIdentifier().getLastPathArgument(), crossShardContainer);
238
239         cursor.close();
240         tx.submit().get();
241
242         tx = producer.createTransaction(false);
243         cursor = tx.createCursor(TEST_ID);
244         assertNotNull(cursor);
245
246         cursor.delete(TestModel.INNER_CONTAINER_PATH.getLastPathArgument());
247         cursor.close();
248         tx.submit().get();
249
250         verify(mockedDataTreeListener, timeout(5000).times(3)).onDataTreeChanged(captorForChanges.capture(),
251                 captorForSubtrees.capture());
252
253         final List<Collection<DataTreeCandidate>> capturedValue = captorForChanges.getAllValues();
254         final ContainerNode capturedChange =
255                 (ContainerNode) capturedValue.get(1).iterator().next().getRootNode().getDataAfter().get();
256         final ContainerNode innerContainerVerify = crossShardContainer;
257         assertEquals(innerContainerVerify, capturedChange);
258     }
259
260     @Test
261     public void testMultipleWritesIntoSingleMapEntry() throws Exception {
262
263         final YangInstanceIdentifier oid1 = TestModel.OUTER_LIST_PATH.node(new NodeIdentifierWithPredicates(
264                 TestModel.OUTER_LIST_QNAME, QName.create(TestModel.OUTER_LIST_QNAME, "id"), 0));
265         final DOMDataTreeIdentifier outerListPath = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, oid1);
266
267         final DOMDataTreeProducer shardProducer = dataTreeService.createProducer(
268                 Collections.singletonList(outerListPath));
269         final InMemoryDOMDataTreeShard outerListShard = InMemoryDOMDataTreeShard.create(outerListPath, executor, 1000);
270         outerListShard.onGlobalContextUpdated(schemaContext);
271
272         final ListenerRegistration<InMemoryDOMDataTreeShard> oid1ShardRegistration =
273                 dataTreeService.registerDataTreeShard(outerListPath, outerListShard, shardProducer);
274
275         final DOMDataTreeCursorAwareTransaction tx = shardProducer.createTransaction(false);
276         final DOMDataTreeWriteCursor cursor =
277                 tx.createCursor(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, oid1));
278         assertNotNull(cursor);
279
280         MapNode innerList = ImmutableMapNodeBuilder
281                 .create()
282                 .withNodeIdentifier(new NodeIdentifier(TestModel.INNER_LIST_QNAME))
283                 .build();
284
285         cursor.write(new NodeIdentifier(TestModel.INNER_LIST_QNAME), innerList);
286         cursor.close();
287         tx.submit().get();
288
289         final ArrayList<ListenableFuture<Void>> futures = new ArrayList<>();
290         for (int i = 0; i < 1000; i++) {
291             final Collection<MapEntryNode> innerListMapEntries = createInnerListMapEntries(1000, "run-" + i);
292             for (final MapEntryNode innerListMapEntry : innerListMapEntries) {
293                 final DOMDataTreeCursorAwareTransaction tx1 = shardProducer.createTransaction(false);
294                 final DOMDataTreeWriteCursor cursor1 = tx1.createCursor(
295                         new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
296                                 oid1.node(new NodeIdentifier(TestModel.INNER_LIST_QNAME))));
297                 cursor1.write(innerListMapEntry.getIdentifier(), innerListMapEntry);
298                 cursor1.close();
299                 futures.add(tx1.submit());
300             }
301         }
302
303         futures.get(futures.size() - 1).get();
304
305     }
306
307     private static Collection<MapEntryNode> createInnerListMapEntries(final int amount, final String valuePrefix) {
308         final Collection<MapEntryNode> ret = new ArrayList<>();
309         for (int i = 0; i < amount; i++) {
310             ret.add(ImmutableNodes.mapEntryBuilder()
311                     .withNodeIdentifier(new NodeIdentifierWithPredicates(TestModel.INNER_LIST_QNAME,
312                             QName.create(TestModel.OUTER_LIST_QNAME, "name"), Integer.toString(i)))
313                     .withChild(ImmutableNodes
314                             .leafNode(QName.create(TestModel.INNER_LIST_QNAME, "name"), Integer.toString(i)))
315                     .withChild(ImmutableNodes
316                             .leafNode(QName.create(TestModel.INNER_LIST_QNAME, "value"), valuePrefix + "-" + i))
317                     .build());
318         }
319
320         return ret;
321     }
322
323     @Test
324     public void testMultipleProducerCursorCreation() throws Exception {
325
326         final DOMDataTreeProducer rootProducer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
327         DOMDataTreeCursorAwareTransaction rootTx = rootProducer.createTransaction(false);
328         //check if we can create cursor where the new producer will be
329         DOMDataTreeWriteCursor rootTxCursor = rootTx.createCursor(INNER_CONTAINER_ID);
330         assertNotNull(rootTxCursor);
331         rootTxCursor.close();
332
333         try {
334             rootProducer.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
335             fail("Should've failed there is still a tx open");
336         } catch (final IllegalStateException e) {
337             assertTrue(e.getMessage().contains("open"));
338         }
339
340         assertTrue(rootTx.cancel());
341
342         final DOMDataTreeProducer innerContainerProducer = rootProducer.createProducer(
343                 Collections.singletonList(INNER_CONTAINER_ID));
344
345         rootTx = rootProducer.createTransaction(false);
346         try {
347             rootTx.createCursor(INNER_CONTAINER_ID);
348             fail("Subtree should not be available to this producer");
349         } catch (final IllegalArgumentException e) {
350             assertTrue(e.getMessage().contains("delegated to child producer"));
351         }
352
353         rootTxCursor = rootTx.createCursor(TEST_ID);
354         assertNotNull(rootTxCursor);
355         try {
356             rootTxCursor.enter(INNER_CONTAINER_ID.getRootIdentifier().getLastPathArgument());
357             fail("Cursor should not have this subtree available");
358         } catch (final IllegalArgumentException e) {
359             assertTrue(e.getMessage().contains("not available to this cursor"));
360         }
361
362         try {
363             rootTxCursor.write(TestModel.INNER_CONTAINER_PATH.getLastPathArgument(),
364                     ImmutableContainerNodeBuilder.create()
365                             .withNodeIdentifier(new NodeIdentifier(TestModel.INNER_CONTAINER))
366                             .build());
367             fail("Cursor should not have this subtree available");
368         } catch (final IllegalArgumentException e) {
369             assertTrue(e.getMessage().contains("not available to this cursor"));
370         }
371
372         final DOMDataTreeCursorAwareTransaction innerShardTx = innerContainerProducer.createTransaction(false);
373         final DOMDataTreeWriteCursor innerShardCursor = innerShardTx.createCursor(INNER_CONTAINER_ID);
374         assertNotNull(innerShardCursor);
375     }
376
377     private static ContainerNode createCrossShardContainer() {
378         final LeafNode<String> shardedValue1 =
379                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(new NodeIdentifier(
380                         TestModel.SHARDED_VALUE_1)).withValue("sharded value 1").build();
381         final LeafNode<String> shardedValue2 =
382                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(new NodeIdentifier(
383                         TestModel.SHARDED_VALUE_2)).withValue("sharded value 2").build();
384
385
386         final ContainerNode lowerShardContainer = ImmutableContainerNodeBuilder.create()
387                 .withNodeIdentifier(new NodeIdentifier(TestModel.ANOTHER_SHARD_CONTAINER))
388                 .withChild(ImmutableLeafNodeBuilder.create()
389                         .withNodeIdentifier(new NodeIdentifier(TestModel.ANOTHER_SHARD_VALUE))
390                         .withValue("testing-value")
391                         .build())
392                 .build();
393
394         final ContainerNode containerNode =
395                 ImmutableContainerNodeBuilder.create()
396                         .withNodeIdentifier(new NodeIdentifier(TestModel.INNER_CONTAINER))
397                         .withChild(shardedValue1)
398                         .withChild(shardedValue2)
399                         .withChild(lowerShardContainer)
400                         .build();
401
402         final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
403                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
404                 .withChild(containerNode)
405                 .build();
406
407         return testContainer;
408     }
409
410     //test multiple vertical levels between the shards
411     @Test
412     public void testLargerSubshardSpace() throws Exception {
413
414         final InMemoryDOMDataTreeShard outerListShard = InMemoryDOMDataTreeShard.create(OUTER_LIST_ID, executor, 1, 1);
415         outerListShard.onGlobalContextUpdated(schemaContext);
416
417         try (DOMDataTreeProducer producer =
418                      dataTreeService.createProducer(Collections.singletonList(OUTER_LIST_ID))) {
419             dataTreeService.registerDataTreeShard(OUTER_LIST_ID, outerListShard, producer);
420         }
421
422         final DOMDataTreeProducer producer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
423         final DOMDataTreeCursorAwareTransaction tx = producer.createTransaction(false);
424         final DOMDataTreeWriteCursor cursor = tx.createCursor(ROOT_ID);
425
426         assertNotNull(cursor);
427         cursor.write(TestModel.TEST_PATH.getLastPathArgument(), createCrossShardContainer2());
428         cursor.close();
429
430         tx.submit().get();
431
432         final DOMDataTreeListener listener = mock(DOMDataTreeListener.class);
433         doNothing().when(listener).onDataTreeChanged(any(), any());
434         dataTreeService.registerListener(listener,
435                 Collections.singletonList(
436                         new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.EMPTY)),
437                 false, Collections.emptyList());
438
439         verify(listener, times(2)).onDataTreeChanged(any(), any());
440
441
442     }
443
444     private static ContainerNode createCrossShardContainer2() {
445
446         final MapEntryNode
447                 innerListEntry1 = ImmutableNodes
448                 .mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "name-1")
449                 .withChild(ImmutableNodes.leafNode(TestModel.NAME_QNAME, "name-1"))
450                 .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value-1"))
451                 .build();
452         final MapEntryNode innerListEntry2 = ImmutableNodes
453                 .mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "name-2")
454                 .withChild(ImmutableNodes.leafNode(TestModel.NAME_QNAME, "name-2"))
455                 .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value-2"))
456                 .build();
457
458         final MapNode innerList1 = ImmutableNodes
459                 .mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(innerListEntry1).build();
460         final MapNode innerList2 = ImmutableNodes
461                 .mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(innerListEntry2).build();
462
463         final MapEntryNode outerListEntry1 = ImmutableNodes
464                 .mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
465                 .withChild(innerList1)
466                 .build();
467         final MapEntryNode outerListEntry2 = ImmutableNodes
468                 .mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2)
469                 .withChild(innerList2)
470                 .build();
471
472         final MapNode outerList = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
473                 .withChild(outerListEntry1)
474                 .withChild(outerListEntry2)
475                 .build();
476
477         final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
478                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
479                 .withChild(outerList)
480                 .build();
481
482         return testContainer;
483     }
484 }