Do not generate 'isFoo()' methods
[mdsal.git] / dom / mdsal-dom-broker / src / test / java / org / opendaylight / mdsal / dom / broker / ShardedDOMDataTreeTest.java
index 058769544c0c0ed951192f904973af188ddbf4ed..771312c05c50b46b7f921a377fd4f98fcd051b48 100644 (file)
@@ -11,14 +11,17 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyCollection;
-import static org.mockito.Matchers.anyMap;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
+import static org.mockito.ArgumentMatchers.anyMap;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -30,10 +33,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
@@ -56,32 +57,21 @@ import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-public class ShardedDOMDataTreeTest {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataTreeProducerMultiShardTest.class);
-
-    private static SchemaContext schemaContext = null;
-
-    static {
-        try {
-            schemaContext = TestModel.createTestContext();
-        } catch (final ReactorException e) {
-            LOG.error("Unable to create schema context for TestModel", e);
-        }
-    }
+public class ShardedDOMDataTreeTest extends AbstractDatastoreTest {
 
     private static final DOMDataTreeIdentifier ROOT_ID =
-            new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.EMPTY);
+            new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.empty());
     private static final DOMDataTreeIdentifier TEST_ID =
-            new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TestModel.TEST_PATH);
+            new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
 
     private static final DOMDataTreeIdentifier INNER_CONTAINER_ID =
-            new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TestModel.INNER_CONTAINER_PATH);
+            new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.INNER_CONTAINER_PATH);
+
+    private static final YangInstanceIdentifier OUTER_LIST_YID = TestModel.OUTER_LIST_PATH.node(
+            NodeIdentifierWithPredicates.of(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1));
+    private static final DOMDataTreeIdentifier OUTER_LIST_ID =
+            new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, OUTER_LIST_YID);
 
     private InMemoryDOMDataTreeShard rootShard;
 
@@ -102,7 +92,7 @@ public class ShardedDOMDataTreeTest {
         MockitoAnnotations.initMocks(this);
 
         rootShard = InMemoryDOMDataTreeShard.create(ROOT_ID, executor, 1);
-        rootShard.onGlobalContextUpdated(schemaContext);
+        rootShard.onModelContextUpdated(SCHEMA_CONTEXT);
 
         final ShardedDOMDataTree dataTree = new ShardedDOMDataTree();
         final DOMDataTreeProducer shardRegProducer = dataTree.createProducer(Collections.singletonList(ROOT_ID));
@@ -118,20 +108,26 @@ public class ShardedDOMDataTreeTest {
         dataTreeService.createProducer(Collections.singletonList(TEST_ID));
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testProducerPathContentionReverse() throws Exception {
+        dataTreeService.createProducer(Collections.singletonList(TEST_ID));
+        dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
+    }
+
     @Test
     public void testShardRegistrationClose() throws Exception {
         rootShardReg.close();
 
         final InMemoryDOMDataTreeShard newRootShard = InMemoryDOMDataTreeShard.create(ROOT_ID, executor, 1);
-        newRootShard.onGlobalContextUpdated(schemaContext);
+        newRootShard.onModelContextUpdated(SCHEMA_CONTEXT);
         final DOMDataTreeProducer shardRegProducer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
 
         final ListenerRegistration<InMemoryDOMDataTreeShard> newRootShardReg =
-                dataTreeService.registerDataTreeShard(ROOT_ID, rootShard, shardRegProducer);
+                dataTreeService.registerDataTreeShard(ROOT_ID, newRootShard, shardRegProducer);
         shardRegProducer.close();
 
         final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1);
-        innerShard.onGlobalContextUpdated(schemaContext);
+        innerShard.onModelContextUpdated(SCHEMA_CONTEXT);
         final DOMDataTreeProducer shardRegProducer2 =
                 dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID));
         ListenerRegistration<InMemoryDOMDataTreeShard> innerShardReg =
@@ -152,9 +148,16 @@ public class ShardedDOMDataTreeTest {
         newRootShardReg.close();
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testEmptyShardMapProducer() throws Exception {
+        final ShardedDOMDataTree dataTree = new ShardedDOMDataTree();
+        final DOMDataTreeProducer producer = dataTree.createProducer(Collections.singletonList(ROOT_ID));
+        producer.createTransaction(false);
+    }
+
     @Test
     public void testSingleShardWrite() throws Exception {
-        final DOMDataTreeListener mockedDataTreeListener = Mockito.mock(DOMDataTreeListener.class);
+        final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
         doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
 
         dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(INNER_CONTAINER_ID),
@@ -168,14 +171,14 @@ public class ShardedDOMDataTreeTest {
         cursor.write(TEST_ID.getRootIdentifier().getLastPathArgument(), crossShardContainer);
 
         try {
-            tx.submit().checkedGet();
+            tx.commit().get();
             fail("There's still an open cursor");
         } catch (final IllegalStateException e) {
             assertTrue(e.getMessage().contains("cursor open"));
         }
 
         cursor.close();
-        tx.submit().checkedGet();
+        tx.commit().get();
 
         tx = producer.createTransaction(false);
         cursor = tx.createCursor(TEST_ID);
@@ -183,7 +186,7 @@ public class ShardedDOMDataTreeTest {
 
         cursor.delete(TestModel.INNER_CONTAINER_PATH.getLastPathArgument());
         cursor.close();
-        tx.submit().checkedGet();
+        tx.commit().get();
 
         verify(mockedDataTreeListener, timeout(1000).times(3)).onDataTreeChanged(captorForChanges.capture(),
                 captorForSubtrees.capture());
@@ -199,17 +202,62 @@ public class ShardedDOMDataTreeTest {
         verifyNoMoreInteractions(mockedDataTreeListener);
     }
 
+    @Test
+    // TODO extract common logic from testSingleSubshardWrite and
+    // testSingleShardWrite tests
+    public void testSingleSubshardWrite() throws Exception {
+        final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class);
+        doNothing().when(mockedDataTreeListener).onDataTreeChanged(anyCollection(), anyMap());
+
+        InMemoryDOMDataTreeShard testShard = InMemoryDOMDataTreeShard.create(TEST_ID, executor, 1);
+        testShard.onModelContextUpdated(SCHEMA_CONTEXT);
+
+        final DOMDataTreeProducer regProducer = dataTreeService.createProducer(Collections.singleton(TEST_ID));
+        dataTreeService.registerDataTreeShard(TEST_ID, testShard, regProducer);
+        regProducer.close();
+
+        dataTreeService.registerListener(mockedDataTreeListener, Collections.singletonList(TEST_ID),
+                true, Collections.emptyList());
+
+        final DOMDataTreeProducer producer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
+        DOMDataTreeCursorAwareTransaction tx = producer.createTransaction(false);
+        DOMDataTreeWriteCursor cursor = tx.createCursor(ROOT_ID);
+        assertNotNull(cursor);
+
+        cursor.write(TEST_ID.getRootIdentifier().getLastPathArgument(), crossShardContainer);
+
+        cursor.close();
+        tx.commit().get();
+
+        tx = producer.createTransaction(false);
+        cursor = tx.createCursor(TEST_ID);
+        assertNotNull(cursor);
+
+        cursor.delete(TestModel.INNER_CONTAINER_PATH.getLastPathArgument());
+        cursor.close();
+        tx.commit().get();
+
+        verify(mockedDataTreeListener, timeout(5000).times(3)).onDataTreeChanged(captorForChanges.capture(),
+                captorForSubtrees.capture());
+
+        final List<Collection<DataTreeCandidate>> capturedValue = captorForChanges.getAllValues();
+        final ContainerNode capturedChange =
+                (ContainerNode) capturedValue.get(1).iterator().next().getRootNode().getDataAfter().get();
+        final ContainerNode innerContainerVerify = crossShardContainer;
+        assertEquals(innerContainerVerify, capturedChange);
+    }
+
     @Test
     public void testMultipleWritesIntoSingleMapEntry() throws Exception {
 
-        final YangInstanceIdentifier oid1 = TestModel.OUTER_LIST_PATH.node(new NodeIdentifierWithPredicates(
+        final YangInstanceIdentifier oid1 = TestModel.OUTER_LIST_PATH.node(NodeIdentifierWithPredicates.of(
                 TestModel.OUTER_LIST_QNAME, QName.create(TestModel.OUTER_LIST_QNAME, "id"), 0));
         final DOMDataTreeIdentifier outerListPath = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, oid1);
 
         final DOMDataTreeProducer shardProducer = dataTreeService.createProducer(
                 Collections.singletonList(outerListPath));
         final InMemoryDOMDataTreeShard outerListShard = InMemoryDOMDataTreeShard.create(outerListPath, executor, 1000);
-        outerListShard.onGlobalContextUpdated(schemaContext);
+        outerListShard.onModelContextUpdated(SCHEMA_CONTEXT);
 
         final ListenerRegistration<InMemoryDOMDataTreeShard> oid1ShardRegistration =
                 dataTreeService.registerDataTreeShard(outerListPath, outerListShard, shardProducer);
@@ -226,29 +274,31 @@ public class ShardedDOMDataTreeTest {
 
         cursor.write(new NodeIdentifier(TestModel.INNER_LIST_QNAME), innerList);
         cursor.close();
-        tx.submit().checkedGet();
-
-        final ArrayList<CheckedFuture<Void, TransactionCommitFailedException>> futures = new ArrayList<>();
-        final Collection<MapEntryNode> innerListMapEntries = createInnerListMapEntries(1000, "run-1");
-        for (final MapEntryNode innerListMapEntry : innerListMapEntries) {
-            final DOMDataTreeCursorAwareTransaction tx1 = shardProducer.createTransaction(false);
-            final DOMDataTreeWriteCursor cursor1 = tx1.createCursor(
-                    new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
-                            oid1.node(new NodeIdentifier(TestModel.INNER_LIST_QNAME))));
-            cursor1.write(innerListMapEntry.getIdentifier(), innerListMapEntry);
-            cursor1.close();
-            futures.add(tx1.submit());
+        tx.commit().get();
+
+        final ArrayList<ListenableFuture<?>> futures = new ArrayList<>();
+        for (int i = 0; i < 1000; i++) {
+            final Collection<MapEntryNode> innerListMapEntries = createInnerListMapEntries(1000, "run-" + i);
+            for (final MapEntryNode innerListMapEntry : innerListMapEntries) {
+                final DOMDataTreeCursorAwareTransaction tx1 = shardProducer.createTransaction(false);
+                final DOMDataTreeWriteCursor cursor1 = tx1.createCursor(
+                        new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
+                                oid1.node(new NodeIdentifier(TestModel.INNER_LIST_QNAME))));
+                cursor1.write(innerListMapEntry.getIdentifier(), innerListMapEntry);
+                cursor1.close();
+                futures.add(tx1.commit());
+            }
         }
 
-        futures.get(futures.size() - 1).checkedGet();
+        futures.get(futures.size() - 1).get();
 
     }
 
-    private Collection<MapEntryNode> createInnerListMapEntries(int amount, String valuePrefix) {
+    private static Collection<MapEntryNode> createInnerListMapEntries(final int amount, final String valuePrefix) {
         final Collection<MapEntryNode> ret = new ArrayList<>();
         for (int i = 0; i < amount; i++) {
             ret.add(ImmutableNodes.mapEntryBuilder()
-                    .withNodeIdentifier(new NodeIdentifierWithPredicates(TestModel.INNER_LIST_QNAME,
+                    .withNodeIdentifier(NodeIdentifierWithPredicates.of(TestModel.INNER_LIST_QNAME,
                             QName.create(TestModel.OUTER_LIST_QNAME, "name"), Integer.toString(i)))
                     .withChild(ImmutableNodes
                             .leafNode(QName.create(TestModel.INNER_LIST_QNAME, "name"), Integer.toString(i)))
@@ -314,7 +364,7 @@ public class ShardedDOMDataTreeTest {
         assertNotNull(innerShardCursor);
     }
 
-    private ContainerNode createCrossShardContainer() {
+    private static ContainerNode createCrossShardContainer() {
         final LeafNode<String> shardedValue1 =
                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(new NodeIdentifier(
                         TestModel.SHARDED_VALUE_1)).withValue("sharded value 1").build();
@@ -346,4 +396,79 @@ public class ShardedDOMDataTreeTest {
 
         return testContainer;
     }
+
+    //test multiple vertical levels between the shards
+    @Test
+    public void testLargerSubshardSpace() throws Exception {
+
+        final InMemoryDOMDataTreeShard outerListShard = InMemoryDOMDataTreeShard.create(OUTER_LIST_ID, executor, 1, 1);
+        outerListShard.onModelContextUpdated(SCHEMA_CONTEXT);
+
+        try (DOMDataTreeProducer producer =
+                     dataTreeService.createProducer(Collections.singletonList(OUTER_LIST_ID))) {
+            dataTreeService.registerDataTreeShard(OUTER_LIST_ID, outerListShard, producer);
+        }
+
+        final DOMDataTreeProducer producer = dataTreeService.createProducer(Collections.singletonList(ROOT_ID));
+        final DOMDataTreeCursorAwareTransaction tx = producer.createTransaction(false);
+        final DOMDataTreeWriteCursor cursor = tx.createCursor(ROOT_ID);
+
+        assertNotNull(cursor);
+        cursor.write(TestModel.TEST_PATH.getLastPathArgument(), createCrossShardContainer2());
+        cursor.close();
+
+        tx.commit().get();
+
+        final DOMDataTreeListener listener = mock(DOMDataTreeListener.class);
+        doNothing().when(listener).onDataTreeChanged(any(), any());
+        dataTreeService.registerListener(listener,
+                Collections.singletonList(
+                        new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.empty())),
+                false, Collections.emptyList());
+
+        verify(listener, times(2)).onDataTreeChanged(any(), any());
+
+
+    }
+
+    private static ContainerNode createCrossShardContainer2() {
+
+        final MapEntryNode
+                innerListEntry1 = ImmutableNodes
+                .mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "name-1")
+                .withChild(ImmutableNodes.leafNode(TestModel.NAME_QNAME, "name-1"))
+                .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value-1"))
+                .build();
+        final MapEntryNode innerListEntry2 = ImmutableNodes
+                .mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "name-2")
+                .withChild(ImmutableNodes.leafNode(TestModel.NAME_QNAME, "name-2"))
+                .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value-2"))
+                .build();
+
+        final MapNode innerList1 = ImmutableNodes
+                .mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(innerListEntry1).build();
+        final MapNode innerList2 = ImmutableNodes
+                .mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(innerListEntry2).build();
+
+        final MapEntryNode outerListEntry1 = ImmutableNodes
+                .mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .withChild(innerList1)
+                .build();
+        final MapEntryNode outerListEntry2 = ImmutableNodes
+                .mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2)
+                .withChild(innerList2)
+                .build();
+
+        final MapNode outerList = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+                .withChild(outerListEntry1)
+                .withChild(outerListEntry2)
+                .build();
+
+        final ContainerNode testContainer = ImmutableContainerNodeBuilder.create()
+                .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
+                .withChild(outerList)
+                .build();
+
+        return testContainer;
+    }
 }