Unit test for ReadDataTransactionUtil class 03/44603/7
authormiroslav.kovac <miroslav.kovac@pantheon.tech>
Wed, 24 Aug 2016 12:44:20 +0000 (14:44 +0200)
committermiroslav.kovac <miroslav.kovac@pantheon.tech>
Mon, 5 Sep 2016 08:56:23 +0000 (10:56 +0200)
Fixed bug with merging list data. Also delete and change some
redundant data and function calling.

Change-Id: I842e4d0678fb4285dd50ea776368f4a784021299
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfDataServiceImpl.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtil.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtilTest.java [new file with mode: 0644]
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/TestData.java [new file with mode: 0644]

index 95645334cbfacc1d6a2876d86bc9c9158fb707ad..2d6d5fb16e39dc3ff8aa4e47f559cbf2bb58a27b 100644 (file)
@@ -22,6 +22,7 @@ import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
 import org.opendaylight.netconf.sal.restconf.impl.PATCHContext;
 import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusContext;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
 import org.opendaylight.restconf.RestConnectorProvider;
 import org.opendaylight.restconf.common.references.SchemaContextRef;
 import org.opendaylight.restconf.handlers.SchemaContextHandler;
@@ -75,6 +76,12 @@ public class RestconfDataServiceImpl implements RestconfDataService {
         final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
                 transaction);
         final NormalizedNode<?, ?> node = ReadDataTransactionUtil.readData(value, transactionNode);
+        if (node == null) {
+            throw new RestconfDocumentedException(
+                    "Request could not be completed because the relevant data model content does not exist",
+                    RestconfError.ErrorType.PROTOCOL,
+                    RestconfError.ErrorTag.DATA_MISSING);
+        }
         final SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
         dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
         final String etag = '"' + node.getNodeType().getModule().getFormattedRevision()
index 5f0d995b00c54b5970789d501cd5196b88589b34..6dc8a9463622fcf36421aef22420e455bc186dd5 100644 (file)
@@ -63,23 +63,29 @@ public final class ReadDataTransactionUtil {
      * @return {@link NormalizedNode}
      */
     public static NormalizedNode<?, ?> readData(final String valueOfContent, final TransactionVarsWrapper transactionNode) {
+        final NormalizedNode<?, ?> data;
         if (valueOfContent != null) {
             switch (valueOfContent) {
                 case RestconfDataServiceConstant.ReadData.CONFIG:
                     transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
-                    return readDataViaTransaction(transactionNode);
+                    data = readDataViaTransaction(transactionNode);
+                    break;
                 case RestconfDataServiceConstant.ReadData.NONCONFIG:
                     transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
-                    return readDataViaTransaction(transactionNode);
+                    data = readDataViaTransaction(transactionNode);
+                    break;
                 case RestconfDataServiceConstant.ReadData.ALL:
-                    return readDataViaTransaction(transactionNode);
+                    data = readAllData(transactionNode);
+                    break;
                 default:
                     throw new RestconfDocumentedException("Bad querry parameter for content.", ErrorType.APPLICATION,
                             ErrorTag.INVALID_VALUE);
             }
         } else {
-            return readDataViaTransaction(transactionNode);
+            data = readAllData(transactionNode);
         }
+
+        return data;
     }
 
     /**
@@ -92,7 +98,6 @@ public final class ReadDataTransactionUtil {
      * @return {@link NormalizedNode}
      */
     private static NormalizedNode<?, ?> readDataViaTransaction(final TransactionVarsWrapper transactionNode) {
-        if (transactionNode.getLogicalDatastoreType() != null) {
             final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture = transactionNode
                     .getTransactionChain().newReadOnlyTransaction().read(transactionNode.getLogicalDatastoreType(),
                             transactionNode.getInstanceIdentifier().getInstanceIdentifier());
@@ -100,9 +105,6 @@ public final class ReadDataTransactionUtil {
             FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
                     dataFactory);
             return dataFactory.build();
-        } else {
-            return readAllData(transactionNode);
-        }
     }
 
     /**
@@ -123,10 +125,7 @@ public final class ReadDataTransactionUtil {
 
         // if no data exists
         if ((stateDataNode == null) && (configDataNode == null)) {
-            throw new RestconfDocumentedException(
-                    "Request could not be completed because the relevant data model content does not exist",
-                    ErrorType.PROTOCOL,
-                    ErrorTag.DATA_MISSING);
+            return null;
         }
 
         // return config data
@@ -150,8 +149,6 @@ public final class ReadDataTransactionUtil {
      *            - data node of state data
      * @param configDataNode
      *            - data node of config data
-     * @param transactionNode
-     *            - {@link TransactionVarsWrapper} - wrapper for variables
      * @return {@link NormalizedNode}
      */
     private static NormalizedNode<?, ?> mapNode(final NormalizedNode<?, ?> stateDataNode,
@@ -215,29 +212,24 @@ public final class ReadDataTransactionUtil {
             final NormalizedNode<?, ?> stateDataNode) {
 
         if (configDataNode instanceof MapNode) { // part for lists mapping
-            final MapNode immutableStateData = ImmutableNodes.mapNodeBuilder(stateDataNode.getNodeType())
-                .addChild((MapEntryNode) stateDataNode).build();
-            final MapNode immutableConfigData = ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType())
-                .addChild((MapEntryNode) configDataNode).build();
             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
                 .mapEntryBuilder();
-            mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
+            final NodeIdentifierWithPredicates node = ((MapNode) configDataNode).getValue().iterator().next().getIdentifier();
+            mapEntryBuilder.withNodeIdentifier(node);
 
             // MAP CONFIG DATA
-            mapDataNode(immutableConfigData, mapEntryBuilder);
+            mapDataNode((MapNode) configDataNode, mapEntryBuilder);
             // MAP STATE DATA
-            mapDataNode(immutableStateData, mapEntryBuilder);
+            mapDataNode((MapNode) stateDataNode, mapEntryBuilder);
             return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
-        } else if (configDataNode instanceof ContainerNode) { // part for
-                                                              // containers
-                                                              // mapping
+        } else if (configDataNode instanceof ContainerNode) { // part for containers mapping
             final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
                     .containerBuilder((ContainerNode) configDataNode);
+
             // MAP CONFIG DATA
             mapCont(containerBuilder, ((ContainerNode) configDataNode).getValue());
             // MAP STATE DATA
             mapCont(containerBuilder, ((ContainerNode) stateDataNode).getValue());
-
             return containerBuilder.build();
         } else {
             throw new RestconfDocumentedException("Bad type of node.");
diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtilTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtilTest.java
new file mode 100644 (file)
index 0000000..c06cc45
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.restconf.restful.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.doReturn;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+
+public class ReadDataTransactionUtilTest {
+
+    private static final TestData data = new TestData();
+    private static final YangInstanceIdentifier.NodeIdentifier nodeIdentifier = new YangInstanceIdentifier
+            .NodeIdentifier(QName.create("ns", "2016-02-28", "container"));
+
+    private TransactionVarsWrapper wrapper;
+    @Mock
+    private DOMTransactionChain transactionChain;
+    @Mock
+    private InstanceIdentifierContext<?> context;
+    @Mock
+    private DOMDataReadOnlyTransaction read;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(read).when(transactionChain).newReadOnlyTransaction();
+        wrapper = new TransactionVarsWrapper(this.context, null, this.transactionChain);
+    }
+
+    @Test
+    public void readDataConfigTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path);
+        doReturn(data.path).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        assertEquals(data.data3, normalizedNode);
+    }
+
+    @Test
+    public void readAllHavingOnlyConfigTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path);
+        doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
+                .read(LogicalDatastoreType.OPERATIONAL, data.path);
+        doReturn(data.path).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        assertEquals(data.data3, normalizedNode);
+    }
+
+    @Test
+    public void readAllHavingOnlyNonConfigTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data2))).when(read)
+                .read(LogicalDatastoreType.OPERATIONAL, data.path2);
+        doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path2);
+        doReturn(data.path2).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        assertEquals(data.data2, normalizedNode);
+    }
+
+    @Test
+    public void readDataNonConfigTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data2))).when(read)
+                .read(LogicalDatastoreType.OPERATIONAL, data.path2);
+        doReturn(data.path2).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.NONCONFIG;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        assertEquals(data.data2, normalizedNode);
+    }
+
+    @Test
+    public void readContainerDataAllTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path);
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data4))).when(read)
+                .read(LogicalDatastoreType.OPERATIONAL, data.path);
+        doReturn(data.path).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        final ContainerNode checkingData = Builders
+                .containerBuilder()
+                .withNodeIdentifier(nodeIdentifier)
+                .withChild(data.contentLeaf)
+                .withChild(data.contentLeaf2)
+                .build();
+        assertEquals(checkingData, normalizedNode);
+    }
+
+    @Test
+    public void readContainerDataConfigNoValueOfContentTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path);
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.data4))).when(read)
+                .read(LogicalDatastoreType.OPERATIONAL, data.path);
+        doReturn(data.path).when(context).getInstanceIdentifier();
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(null, wrapper);
+        final ContainerNode checkingData = Builders
+                .containerBuilder()
+                .withNodeIdentifier(nodeIdentifier)
+                .withChild(data.contentLeaf)
+                .withChild(data.contentLeaf2)
+                .build();
+        assertEquals(checkingData, normalizedNode);
+    }
+
+    @Test
+    public void readListDataAllTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.listData))).when(read)
+                .read(LogicalDatastoreType.OPERATIONAL, data.path3);
+        doReturn(Futures.immediateCheckedFuture(Optional.of(data.listData2))).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path3);
+        doReturn(data.path3).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        final MapNode checkingData = Builders
+                .mapBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
+                .withChild(data.checkData)
+                .build();
+        assertEquals(checkingData, normalizedNode);
+    }
+
+    @Test
+    public void readDataWrongPathOrNoContentTest() {
+        doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
+                .read(LogicalDatastoreType.CONFIGURATION, data.path2);
+        doReturn(data.path2).when(context).getInstanceIdentifier();
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
+        assertNull(normalizedNode);
+    }
+
+    @Test(expected = RestconfDocumentedException.class)
+    public void readDataFailTest() {
+        final String valueOfContent = RestconfDataServiceConstant.ReadData.READ_TYPE_TX;
+        final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, null);
+        assertNull(normalizedNode);
+    }
+}
diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/TestData.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/TestData.java
new file mode 100644 (file)
index 0000000..1972844
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.utils;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+
+class TestData {
+
+    final YangInstanceIdentifier path;
+    final YangInstanceIdentifier path2;
+    final YangInstanceIdentifier path3;
+    final MapEntryNode data;
+    final MapEntryNode data2;
+    final ContainerNode data3;
+    final ContainerNode data4;
+    final MapNode listData;
+    final MapNode listData2;
+    final UnkeyedListEntryNode unkeyedListEntryNode;
+    final LeafNode contentLeaf;
+    final LeafNode contentLeaf2;
+    final MapEntryNode checkData;
+
+    TestData() {
+        final QName base = QName.create("ns", "2016-02-28", "base");
+        final QName listQname = QName.create(base, "list");
+        final QName listKeyQName = QName.create(base, "list-key");
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeWithKey =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(listQname, listKeyQName, "keyValue");
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeWithKey2 =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(listQname, listKeyQName, "keyValue2");
+        final LeafNode<Object> content = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "leaf-content")))
+                .withValue("content")
+                .build();
+        final LeafNode<Object> content2 = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "leaf-content-different")))
+                .withValue("content-different")
+                .build();
+        final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataContainer = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "identifier")))
+                .withValue("id")
+                .build();
+        unkeyedListEntryNode = Builders.unkeyedListEntryBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "list")))
+                .withChild(dataContainer)
+                .build();
+        data = Builders.mapEntryBuilder()
+                .withNodeIdentifier(nodeWithKey)
+                .withChild(content)
+                .build();
+        data2 = Builders.mapEntryBuilder()
+                .withNodeIdentifier(nodeWithKey)
+                .withChild(content2)
+                .build();
+        checkData = Builders.mapEntryBuilder()
+                .withNodeIdentifier(nodeWithKey)
+                .withChild(content2)
+                .withChild(content)
+                .build();
+        listData = Builders.mapBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "list")))
+                .withChild(data)
+                .build();
+        listData2 = Builders.mapBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(listQname, "list")))
+                .withChild(data)
+                .withChild(data2)
+                .build();
+        path = YangInstanceIdentifier.builder()
+                .node(QName.create(base, "cont"))
+                .node(listQname)
+                .node(nodeWithKey)
+                .build();
+        path2 = YangInstanceIdentifier.builder()
+                .node(QName.create(base, "cont"))
+                .node(listQname)
+                .node(nodeWithKey2)
+                .build();
+        path3 = YangInstanceIdentifier.builder()
+                .node(QName.create(base, "cont"))
+                .node(listQname)
+                .build();
+        contentLeaf = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "content")))
+                .withValue("test")
+                .build();
+        contentLeaf2 = Builders.leafBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "content2")))
+                .withValue("test2")
+                .build();
+        data3 = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "container")))
+                .withChild(contentLeaf)
+                .build();
+        data4 = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(base, "container2")))
+                .withChild(contentLeaf2)
+                .build();
+    }
+}
\ No newline at end of file