CPS PATCH operation does not merge existing data 90/132890/3
authorlukegleeson <luke.gleeson@est.tech>
Mon, 9 Jan 2023 16:14:36 +0000 (16:14 +0000)
committerlukegleeson <luke.gleeson@est.tech>
Wed, 11 Jan 2023 09:58:22 +0000 (09:58 +0000)
Altered code to add attributes and not overwrite attributes + tests

Issue-ID: CPS-1442
Signed-off-by: lukegleeson <luke.gleeson@est.tech>
Change-Id: I23c5f6a65b98ea1b05af62a38a874c228cc82067

cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy

index 3bd2994..06068e3 100644 (file)
@@ -447,9 +447,11 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
 
     @Override
     public void updateDataLeaves(final String dataspaceName, final String anchorName, final String xpath,
-                                 final Map<String, Serializable> leaves) {
+                                 final Map<String, Serializable> updateLeaves) {
         final FragmentEntity fragmentEntity = getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, xpath);
-        fragmentEntity.setAttributes(jsonObjectMapper.asJsonString(leaves));
+        final String currentLeavesAsString = fragmentEntity.getAttributes();
+        final String mergedLeaves = mergeLeaves(updateLeaves, currentLeavesAsString);
+        fragmentEntity.setAttributes(mergedLeaves);
         fragmentRepository.save(fragmentEntity);
     }
 
@@ -694,4 +696,14 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     private static boolean isRootXpath(final String xpath) {
         return "/".equals(xpath) || "".equals(xpath);
     }
+
+    private String mergeLeaves(final Map<String, Serializable> updateLeaves, final String currentLeavesAsString) {
+        final Map<String, Serializable> currentLeavesAsMap = currentLeavesAsString.isEmpty()
+            ? new HashMap<>() : jsonObjectMapper.convertJsonString(currentLeavesAsString, Map.class);
+        currentLeavesAsMap.putAll(updateLeaves);
+        if (currentLeavesAsMap.isEmpty()) {
+            return "";
+        }
+        return jsonObjectMapper.asJsonString(currentLeavesAsMap);
+    }
 }
index 255e8e5..8234d32 100644 (file)
@@ -165,6 +165,25 @@ class CpsDataPersistenceServiceSpec extends Specification {
             1 * mockSessionManager.lockAnchor('mySessionId', 'myDataspaceName', 'myAnchorName', 123L)
     }
 
+    def 'update data node leaves: #scenario'(){
+        given: 'A node exists for the given xpath'
+            mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, '/some/xpath') >> new FragmentEntity(xpath: '/some/xpath', attributes:  existingAttributes)
+        when: 'the node leaves are updated'
+            objectUnderTest.updateDataLeaves('some-dataspace', 'some-anchor', '/some/xpath', newAttributes as Map<String, Serializable>)
+        then: 'the fragment entity saved has the original and new attributes'
+            1 * mockFragmentRepository.save({fragmentEntity -> {
+                assert fragmentEntity.getXpath() == '/some/xpath'
+                assert fragmentEntity.getAttributes() == mergedAttributes
+            }})
+        where: 'the following attributes combinations are used'
+            scenario                      | existingAttributes     | newAttributes         | mergedAttributes
+            'add new leaf'                | '{"existing":"value"}' | ["new":"value"]       | '{"existing":"value","new":"value"}'
+            'update existing leaf'        | '{"existing":"value"}' | ["existing":"value2"] | '{"existing":"value2"}'
+            'update nothing with nothing' | ''                     | []                    | ''
+            'update with nothing'         | '{"existing":"value"}' | []                    | '{"existing":"value"}'
+            'update with same value'      | '{"existing":"value"}' | ["existing":"value"]  | '{"existing":"value"}'
+    }
+
     def 'update data node and descendants: #scenario'(){
         given: 'mocked responses'
             mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, '/test/xpath') >> new FragmentEntity(xpath: '/test/xpath', childFragments: [])