Make original delta report format consistent with delta report new format 84/141284/6
authorArpit Singh <AS00745003@techmahindra.com>
Thu, 19 Jun 2025 11:57:01 +0000 (17:27 +0530)
committerArpit Singh <AS00745003@techmahindra.com>
Mon, 1 Sep 2025 08:02:37 +0000 (13:32 +0530)
The old delta report only provides information about the leaf nodes that
changed.
The details about the data node are not provided as part of the delta
report.
The change adds node name and JSON sructure of the data node to the
original delta report format.

Issue-ID: CPS-2860
Change-Id: Iac51925f0d0a8ddf1958b47ad372090fbf0d75d9
Signed-off-by: Arpit Singh <AS00745003@techmahindra.com>
cps-service/src/main/java/org/onap/cps/utils/deltareport/DeltaReportGenerator.java
cps-service/src/main/java/org/onap/cps/utils/deltareport/DeltaReportHelper.java
cps-service/src/main/java/org/onap/cps/utils/deltareport/GroupedDeltaReportGenerator.java
cps-service/src/test/groovy/org/onap/cps/impl/CpsDeltaServiceImplSpec.groovy

index 44b7ba6..840807a 100644 (file)
 
 package org.onap.cps.utils.deltareport;
 
+import static org.onap.cps.utils.deltareport.DeltaReportHelper.getNodeNameToDataForDeltaReport;
+
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -65,7 +68,14 @@ public class DeltaReportGenerator {
                 xpathToDataNode.putAll(convertToXPathToDataNodesMap(childDataNodes));
             }
         }
-        return xpathToDataNode;
+        return clearChildDataNodes(xpathToDataNode);
+    }
+
+    private static Map<String, DataNode> clearChildDataNodes(final Map<String, DataNode> xpathToDataNodes) {
+        for (final DataNode dataNode : xpathToDataNodes.values()) {
+            dataNode.setChildDataNodes(Collections.emptyList());
+        }
+        return xpathToDataNodes;
     }
 
     private List<DeltaReport> getRemovedAndUpdatedDeltaReports(final Map<String, DataNode> xpathToSourceDataNodes,
@@ -88,9 +98,10 @@ public class DeltaReportGenerator {
 
     private static List<DeltaReport> getDeltaReportsForRemove(final String xpath, final DataNode sourceDataNode) {
         final List<DeltaReport> deltaReportEntriesForRemove = new ArrayList<>();
-        final Map<String, Serializable> sourceDataNodeLeaves = sourceDataNode.getLeaves();
+        final Map<String, Serializable> sourceDataNodeRemoved =
+            getNodeNameToDataForDeltaReport(Collections.singletonList(sourceDataNode));
         final DeltaReport removedDeltaReportEntry = new DeltaReportBuilder().actionRemove().withXpath(xpath)
-            .withSourceData(sourceDataNodeLeaves).build();
+            .withSourceData(sourceDataNodeRemoved).build();
         deltaReportEntriesForRemove.add(removedDeltaReportEntry);
         return deltaReportEntriesForRemove;
     }
@@ -104,12 +115,13 @@ public class DeltaReportGenerator {
         for (final Map.Entry<String, DataNode> entry: xpathToAddedNodes.entrySet()) {
             final String xpath = entry.getKey();
             final DataNode dataNode = entry.getValue();
+            final Map<String, Serializable> targetData =
+                getNodeNameToDataForDeltaReport(Collections.singletonList(dataNode));
             final DeltaReport addedDataForDeltaReport = new DeltaReportBuilder().actionCreate().withXpath(xpath)
-                .withTargetData(dataNode.getLeaves()).build();
+                .withTargetData(targetData).build();
             addedDeltaReportEntries.add(addedDataForDeltaReport);
         }
         return addedDeltaReportEntries;
     }
 
-
 }
index 0112718..5e29ffa 100644 (file)
@@ -142,7 +142,7 @@ public class DeltaReportHelper {
                 addKeyLeavesToUpdatedData(xpath, updatedLeaves);
             }
             final Collection<DataNode> updatedDataNode = buildUpdatedDataNode(dataNode, updatedLeaves);
-            updatedSourceData.putAll(getCondensedDataForDeltaReport(updatedDataNode));
+            updatedSourceData.putAll(getNodeNameToDataForDeltaReport(updatedDataNode));
         }
         return updatedSourceData;
     }
@@ -169,7 +169,13 @@ public class DeltaReportHelper {
         return Collections.singletonList(updatedDataNode);
     }
 
-    private static Map<String, Serializable> getCondensedDataForDeltaReport(final Collection<DataNode> dataNodes) {
+    /**
+     * Converts a collection of DataNodes to a map where the keys are the node names and the values are the node data.
+     *
+     * @param dataNodes the collection of DataNodes
+     * @return          a map with node names as keys and their corresponding data as values
+     */
+    public static Map<String, Serializable> getNodeNameToDataForDeltaReport(final Collection<DataNode> dataNodes) {
         final DataNode containerNode = new DataNodeBuilder().withChildDataNodes(dataNodes).build();
         final Map<String, Object> condensedData = DataMapUtils.toDataMap(containerNode);
         return condensedData.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
index d0ab418..839ebf7 100644 (file)
@@ -20,7 +20,8 @@
 
 package org.onap.cps.utils.deltareport;
 
-import java.io.Serializable;
+import static org.onap.cps.utils.deltareport.DeltaReportHelper.getNodeNameToDataForDeltaReport;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -31,9 +32,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.model.DataNode;
 import org.onap.cps.api.model.DeltaReport;
 import org.onap.cps.cpspath.parser.CpsPathUtil;
-import org.onap.cps.impl.DataNodeBuilder;
 import org.onap.cps.impl.DeltaReportBuilder;
-import org.onap.cps.utils.DataMapUtils;
 import org.springframework.stereotype.Service;
 
 @Slf4j
@@ -70,7 +69,7 @@ public class GroupedDeltaReportGenerator {
         if (!removedDataNodes.isEmpty()) {
             final String xpath = getXpathForDeltaReport(removedDataNodes);
             deltaReportEntriesForRemove.add(new DeltaReportBuilder().actionRemove().withXpath(xpath)
-                .withSourceData(getCondensedDataForDeltaReport(removedDataNodes)).build());
+                .withSourceData(getNodeNameToDataForDeltaReport(removedDataNodes)).build());
         }
         return deltaReportEntriesForRemove;
     }
@@ -111,7 +110,7 @@ public class GroupedDeltaReportGenerator {
         if (!addedDataNodes.isEmpty()) {
             final String xpath = getXpathForDeltaReport(addedDataNodes);
             addedDeltaReportEntries.add(new DeltaReportBuilder().actionCreate().withXpath(xpath)
-                .withTargetData(getCondensedDataForDeltaReport(addedDataNodes)).build());
+                .withTargetData(getNodeNameToDataForDeltaReport(addedDataNodes)).build());
         }
         return addedDeltaReportEntries;
     }
@@ -127,13 +126,6 @@ public class GroupedDeltaReportGenerator {
         return dataNodes.stream().filter(dataNode -> !xpathToDataNodes.containsKey(dataNode.getXpath())).toList();
     }
 
-    private static Map<String, Serializable> getCondensedDataForDeltaReport(final Collection<DataNode> dataNodes) {
-        final DataNode containerNode = new DataNodeBuilder().withChildDataNodes(dataNodes).build();
-        final Map<String, Object> condensedData = DataMapUtils.toDataMap(containerNode);
-        return condensedData.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
-            entry -> (Serializable) entry.getValue()));
-    }
-
     private static Map<String, DataNode> flattenToXpathToFirstLevelDataNodeMap(final Collection<DataNode> dataNodes) {
         return dataNodes.stream().collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
     }
index 7aaeedb..2144732 100644 (file)
@@ -132,8 +132,8 @@ class CpsDeltaServiceImplSpec extends Specification {
             deltaReport[0].targetData == expectedTargetData
         where: 'following data was used'
             scenario                         | sourceDataNodes          | targetDataNodes         | groupDataNodes    || expectedAction | expectedSourceData                                                                                            | expectedTargetData
-            'added with grouping disabled'   | []                       | targetDataNode          | GROUPING_DISABLED || 'create'       | null                                                                                                          | ['parent-leaf':'parent-leaf-as-target-data']
-            'removed with grouping disabled' | sourceDataNode           | []                      | GROUPING_DISABLED || 'remove'       | ['parent-leaf':'parent-leaf-as-source-data']                                                                  | null
+            'added with grouping disabled'   | []                       | targetDataNode          | GROUPING_DISABLED || 'create'       | null                                                                                                          | ['parent':['parent-leaf':'parent-leaf-as-target-data']]
+            'removed with grouping disabled' | sourceDataNode           | []                      | GROUPING_DISABLED || 'remove'       | ['parent':['parent-leaf':'parent-leaf-as-source-data']]                                                       | null
             'updated with grouping disabled' | sourceDataNode           | targetDataNode          | GROUPING_DISABLED || 'replace'      | ['parent':['parent-leaf':'parent-leaf-as-source-data']]                                                       | ['parent':['parent-leaf':'parent-leaf-as-target-data']]
             'added with grouping enabled'    | []                       | targetDataNodeWithChild | GROUPING_ENABLED  || 'create'       | null                                                                                                          | ['parent':['parent-leaf': 'parent-leaf-as-target-data', 'child':['child-leaf': 'child-leaf-as-target-data']]]
             'removed with grouping enabled'  | sourceDataNodeWithChild  | []                      | GROUPING_ENABLED  || 'remove'       | ['parent':['parent-leaf': 'parent-leaf-as-source-data', 'child':['child-leaf': 'child-leaf-as-source-data']]] | null
@@ -162,10 +162,10 @@ class CpsDeltaServiceImplSpec extends Specification {
             assert deltaReport[1].sourceData == expectedSourceDataForChild
             assert deltaReport[1].targetData == expectedTargetDataForChild
         where: 'the following data is used'
-            scenario  | sourceDataNodes         | targetDataNodes         || expectedAction | expectedSourceDataForParent                   | expectedTargetDataForParent                   | expectedSourceDataForChild                            | expectedTargetDataForChild
-            'added'   | []                      | targetDataNodeWithChild || 'create'       | null                                          | ['parent-leaf': 'parent-leaf-as-target-data'] | null                                                  | ['child-leaf': 'child-leaf-as-target-data']
-            'removed' | sourceDataNodeWithChild | []                      || 'remove'       | ['parent-leaf': 'parent-leaf-as-source-data'] | null                                          | ['child-leaf': 'child-leaf-as-source-data']           | null
-            'updated' | sourceDataNodeWithChild | targetDataNodeWithChild || 'replace'      | expectedParentSourceData                      | expectedParentTargetData                      | ['child':['child-leaf': 'child-leaf-as-source-data']] | ['child':['child-leaf': 'child-leaf-as-target-data']]
+            scenario  | sourceDataNodes           | targetDataNodes           || expectedAction | expectedSourceDataForParent | expectedTargetDataForParent | expectedSourceDataForChild                            | expectedTargetDataForChild
+            'added'   | []                        | targetDataNodeWithChild() || 'create'       | null                        | expectedParentTargetData    | null                                                  | ['child':['child-leaf': 'child-leaf-as-target-data']]
+            'removed' | sourceDataNodeWithChild() | []                        || 'remove'       | expectedParentSourceData    | null                        | ['child':['child-leaf': 'child-leaf-as-source-data']] | null
+            'updated' | sourceDataNodeWithChild() | targetDataNodeWithChild() || 'replace'      | expectedParentSourceData    | expectedParentTargetData    | ['child':['child-leaf': 'child-leaf-as-source-data']] | ['child':['child-leaf': 'child-leaf-as-target-data']]
     }
 
     def 'Delta Report between parent nodes with children where parent is updated and child node is #scenario with grouping of data nodes'() {
@@ -360,4 +360,15 @@ class CpsDeltaServiceImplSpec extends Specification {
         def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceContentPerName).getSchemaContext()
         mockYangTextSchemaSourceSet.getSchemaContext() >> schemaContext
     }
+
+    def sourceDataNodeWithChild() {
+        [new DataNode(xpath: '/parent', leaves: ['parent-leaf': 'parent-leaf-as-source-data'],
+            childDataNodes: [new DataNode(xpath: '/parent/child', leaves: ['child-leaf': 'child-leaf-as-source-data'])])]
+    }
+
+    def targetDataNodeWithChild() {
+        [new DataNode(xpath: '/parent', leaves: ['parent-leaf': 'parent-leaf-as-target-data'],
+            childDataNodes: [new DataNode(xpath: '/parent/child', leaves: ['child-leaf': 'child-leaf-as-target-data'])])]
+    }
+
 }