Merge "Query operation path by alternate id"
authorDaniel Hanrahan <daniel.hanrahan@est.tech>
Thu, 2 May 2024 09:42:34 +0000 (09:42 +0000)
committerGerrit Code Review <gerrit@onap.org>
Thu, 2 May 2024 09:42:34 +0000 (09:42 +0000)
85 files changed:
checkstyle/pom.xml
cps-application/pom.xml
cps-application/src/main/resources/application.yml
cps-bom/pom.xml
cps-dependencies/pom.xml
cps-events/pom.xml
cps-events/src/main/resources/schemas/updatenode/cps-data-updated-event-schema-1.0.0.json
cps-ncmp-events/pom.xml
cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
cps-ncmp-rest-stub/pom.xml
cps-ncmp-rest/pom.xml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
cps-ncmp-service/pom.xml
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java [deleted file]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java with 96% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java with 97% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java with 98% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java with 87% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy [deleted file]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
cps-ncmp-service/src/test/resources/application.yml
cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
cps-parent/pom.xml
cps-path-parser/pom.xml
cps-rest/pom.xml
cps-ri/pom.xml
cps-service/pom.xml
cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
cps-service/src/main/java/org/onap/cps/events/CpsDataUpdateEventsService.java [new file with mode: 0644]
cps-service/src/main/java/org/onap/cps/events/CpsEvent.java [new file with mode: 0644]
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy [new file with mode: 0644]
dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
dmi-plugin-demo-and-csit-stub/pom.xml
docs/api/swagger/ncmp/openapi-inventory.yaml
docs/api/swagger/ncmp/openapi.yaml
docs/release-notes.rst
integration-test/pom.xml
integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy
integration-test/src/test/resources/application.yml
jacoco-report/pom.xml
pom.xml
releases/3.4.8-container.yaml [new file with mode: 0644]
releases/3.4.8.yaml [new file with mode: 0644]
spotbugs/pom.xml
version.properties

index b1c4379..cddf5ce 100644 (file)
@@ -26,7 +26,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>checkstyle</artifactId>
-    <version>3.4.8-SNAPSHOT</version>
+    <version>3.4.9-SNAPSHOT</version>
 
     <profiles>
         <profile>
index e6e2f9a..9939e0b 100644 (file)
@@ -28,7 +28,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index aeec8a2..68dd31b 100644 (file)
@@ -2,6 +2,7 @@
 #  Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2021-2022 Bell Canada
 #  Modifications Copyright (C) 2021-2024 Nordix Foundation
+#  Modifications Copyright (C) 2024 TechMahindra Ltd
 #  ================================================================================
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -113,7 +114,9 @@ app:
             topic: ${DMI_CM_EVENTS_TOPIC:dmi-cm-events}
         device-heartbeat:
             topic: ${DMI_DEVICE_HEARTBEAT_TOPIC:dmi-device-heartbeat}
-
+    cps:
+        data-updated:
+            topic: ${CPS_CHANGE_EVENT_TOPIC:cps-data-updated-events}
 
 notification:
     enabled: true
@@ -138,14 +141,12 @@ springdoc:
             - name: cps-ncmp-inventory
               url: /api-docs/cps-ncmp/openapi-inventory.yaml
 
-
-
 security:
     # comma-separated uri patterns which do not require authorization
     permit-uri: /actuator/**,/swagger-ui.html,/swagger-ui/**,/swagger-resources/**,/api-docs/**,/v3/api-docs/**
     auth:
-        username: ${CPS_USERNAME}
-        password: ${CPS_PASSWORD}
+        username: ${CPS_USERNAME:cpsuser}
+        password: ${CPS_PASSWORD:cpsr0cks!}
 
 # Actuator
 management:
@@ -174,10 +175,9 @@ ncmp:
             maximumConnectionsPerRoute: 50
             maximumConnectionsTotal: 100
             idleConnectionEvictionThresholdInSeconds: 5
-            maximumInMemorySizeInMegabytes: 16
         auth:
-            username: ${DMI_USERNAME}
-            password: ${DMI_PASSWORD}
+            username: ${DMI_USERNAME:cpsuser}
+            password: ${DMI_PASSWORD:cpsr0cks!}
             enabled: ${DMI_AUTH_ENABLED:true}
         api:
             base-path: dmi
index 366d4c7..c2f68b4 100644 (file)
@@ -25,7 +25,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-bom</artifactId>
-    <version>3.4.8-SNAPSHOT</version>
+    <version>3.4.9-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <description>This artifact contains dependencyManagement declarations of all published CPS components.</description>
index b7ec70b..5d435d6 100644 (file)
@@ -27,7 +27,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-dependencies</artifactId>
-    <version>3.4.8-SNAPSHOT</version>
+    <version>3.4.9-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <name>${project.groupId}:${project.artifactId}</name>
index 680d0bb..d74e735 100644 (file)
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 18f83cc..a3eaf63 100644 (file)
@@ -12,7 +12,7 @@
           "type": "object",
           "properties": {
             "observedTimestamp": {
-              "description": "The timestamp when the data has been observed. The expected format is 'yyyy-MM-dd'T'HH:mm:ss.SSSZ'. Ex: '2020-12-01T00:00:00.000+0000'  ",
+              "description": "The timestamp when the data has been observed. The expected format is 'yyyy-MM-dd'T'HH:mm:ss.SSSZ'. Ex: '2024-02-12T09:35:46.143+0530'  ",
               "type": "string"
             },
             "dataspaceName": {
index e12ab3b..7b43ea1 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index ae755a3..81f80a9 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-ncmp-rest-stub</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
     </parent>
 
     <artifactId>cps-ncmp-rest-stub-app</artifactId>
index b6c461c..a82f2c0 100644 (file)
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-ncmp-rest-stub</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
     </parent>
     <artifactId>cps-ncmp-rest-stub-service</artifactId>
 
index c2c789e..d4eec0d 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 453da8f..d538b98 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 453abca..5467eef 100755 (executable)
@@ -96,8 +96,9 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
     private boolean allRegistrationsSuccessful(
         final DmiPluginRegistrationErrorResponse dmiPluginRegistrationErrorResponse) {
         return dmiPluginRegistrationErrorResponse.getFailedCreatedCmHandles().isEmpty()
-            && dmiPluginRegistrationErrorResponse.getFailedUpdatedCmHandles().isEmpty()
-            && dmiPluginRegistrationErrorResponse.getFailedRemovedCmHandles().isEmpty();
+                && dmiPluginRegistrationErrorResponse.getFailedUpdatedCmHandles().isEmpty()
+                && dmiPluginRegistrationErrorResponse.getFailedRemovedCmHandles().isEmpty()
+                && dmiPluginRegistrationErrorResponse.getFailedUpgradeCmHandles().isEmpty();
     }
 
     private DmiPluginRegistrationErrorResponse getFailureRegistrationResponse(
index 1d03be1..7b850a7 100644 (file)
@@ -201,7 +201,8 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
             def dmiRegistrationResponse = new DmiPluginRegistrationResponse(
                 createdCmHandles: [createCmHandleResponse],
                 updatedCmHandles: [updateCmHandleResponse],
-                removedCmHandles: [removeCmHandleResponse]
+                removedCmHandles: [removeCmHandleResponse],
+                upgradedCmHandles: [upgradeCmHandleResponse]
             )
             mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
         when: 'registration endpoint is invoked'
@@ -218,15 +219,18 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
             responseBody.getFailedCreatedCmHandles() == expectedFailedCreatedCmHandle
             responseBody.getFailedUpdatedCmHandles() == expectedFailedUpdateCmHandle
             responseBody.getFailedRemovedCmHandles() == expectedFailedRemovedCmHandle
+            responseBody.getFailedUpgradeCmHandles() == expectedFailedUpgradedCmHandle
         where:
-        scenario               | createCmHandleResponse                 | updateCmHandleResponse                 | removeCmHandleResponse                 || expectedFailedCreatedCmHandle                 | expectedFailedUpdateCmHandle                  | expectedFailedRemovedCmHandle
-        'only create failed'   | expectedFailedResponse('cm-handle-1')  | expectedSuccessResponse('cm-handle-2') | expectedSuccessResponse('cm-handle-3') || [expectedUnknownErrorResponse('cm-handle-1')] | []                                            | []
-        'only update failed'   | expectedSuccessResponse('cm-handle-1') | expectedFailedResponse('cm-handle-2')  | expectedSuccessResponse('cm-handle-3') || []                                            | [expectedUnknownErrorResponse('cm-handle-2')] | []
-        'only delete failed'   | expectedSuccessResponse('cm-handle-1') | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  || []                                            | []                                            | [expectedUnknownErrorResponse('cm-handle-3')]
-        'all three failed'     | expectedFailedResponse('cm-handle-1')  | expectedFailedResponse('cm-handle-2')  | expectedFailedResponse('cm-handle-3')  || [expectedUnknownErrorResponse('cm-handle-1')] | [expectedUnknownErrorResponse('cm-handle-2')] | [expectedUnknownErrorResponse('cm-handle-3')]
-        'create update failed' | expectedFailedResponse('cm-handle-1')  | expectedFailedResponse('cm-handle-2')  | expectedSuccessResponse('cm-handle-3') || [expectedUnknownErrorResponse('cm-handle-1')] | [expectedUnknownErrorResponse('cm-handle-2')] | []
-        'create delete failed' | expectedFailedResponse('cm-handle-1')  | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  || [expectedUnknownErrorResponse('cm-handle-1')] | []                                            | [expectedUnknownErrorResponse('cm-handle-3')]
-        'update delete failed' | expectedSuccessResponse('cm-handle-1') | expectedFailedResponse('cm-handle-2')  | expectedFailedResponse('cm-handle-3')  || []                                            | [expectedUnknownErrorResponse('cm-handle-2')] | [expectedUnknownErrorResponse('cm-handle-3')]
+            scenario                | createCmHandleResponse                 | updateCmHandleResponse                 | removeCmHandleResponse                 | upgradeCmHandleResponse                || expectedFailedCreatedCmHandle                 | expectedFailedUpdateCmHandle                  | expectedFailedRemovedCmHandle                 | expectedFailedUpgradedCmHandle
+            'only create failed'    | expectedFailedResponse('cm-handle-1')  | expectedSuccessResponse('cm-handle-2') | expectedSuccessResponse('cm-handle-3') | expectedSuccessResponse('cm-handle-4') || [expectedUnknownErrorResponse('cm-handle-1')] | []                                            | []                                            | []
+            'only update failed'    | expectedSuccessResponse('cm-handle-1') | expectedFailedResponse('cm-handle-2')  | expectedSuccessResponse('cm-handle-3') | expectedSuccessResponse('cm-handle-4') || []                                            | [expectedUnknownErrorResponse('cm-handle-2')] | []                                            | []
+            'only delete failed'    | expectedSuccessResponse('cm-handle-1') | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  | expectedSuccessResponse('cm-handle-4') || []                                            | []                                            | [expectedUnknownErrorResponse('cm-handle-3')] | []
+            'only upgrade failed'   | expectedSuccessResponse('cm-handle-1') | expectedSuccessResponse('cm-handle-2') | expectedSuccessResponse('cm-handle-3') | expectedFailedResponse('cm-handle-4')  || []                                            | []                                            | []                                            | [expectedUnknownErrorResponse('cm-handle-4')]
+            'all four failed'       | expectedFailedResponse('cm-handle-1')  | expectedFailedResponse('cm-handle-2')  | expectedFailedResponse('cm-handle-3')  | expectedFailedResponse('cm-handle-4')  || [expectedUnknownErrorResponse('cm-handle-1')] | [expectedUnknownErrorResponse('cm-handle-2')] | [expectedUnknownErrorResponse('cm-handle-3')] | [expectedUnknownErrorResponse('cm-handle-4')]
+            'create update failed'  | expectedFailedResponse('cm-handle-1')  | expectedFailedResponse('cm-handle-2')  | expectedSuccessResponse('cm-handle-3') | expectedSuccessResponse('cm-handle-4') || [expectedUnknownErrorResponse('cm-handle-1')] | [expectedUnknownErrorResponse('cm-handle-2')] | []                                            | []
+            'create delete failed'  | expectedFailedResponse('cm-handle-1')  | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  | expectedSuccessResponse('cm-handle-4') || [expectedUnknownErrorResponse('cm-handle-1')] | []                                            | [expectedUnknownErrorResponse('cm-handle-3')] | []
+            'update delete failed'  | expectedSuccessResponse('cm-handle-1') | expectedFailedResponse('cm-handle-2')  | expectedFailedResponse('cm-handle-3')  | expectedSuccessResponse('cm-handle-4') || []                                            | [expectedUnknownErrorResponse('cm-handle-2')] | [expectedUnknownErrorResponse('cm-handle-3')] | []
+            'delete upgrade failed' | expectedSuccessResponse('cm-handle-1') | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  | expectedFailedResponse('cm-handle-4')  || []                                            | []                                            | [expectedUnknownErrorResponse('cm-handle-3')] | [expectedUnknownErrorResponse('cm-handle-4')]
     }
 
     def 'Get all cm handle IDs by DMI plugin identifier.'() {
index 04864c4..ff0654a 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
@@ -70,8 +70,8 @@
             <artifactId>mapstruct-processor</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-webflux</artifactId>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
         </dependency>
         <!-- T E S T - D E P E N D E N C I E S -->
         <dependency>
index 6df0e49..798a280 100644 (file)
 package org.onap.cps.ncmp.api.impl.client;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.Locale;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties;
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException;
 import org.onap.cps.ncmp.api.impl.operations.OperationType;
+import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
 import org.springframework.web.client.HttpStatusCodeException;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.client.RestTemplate;
 
 @Component
 @RequiredArgsConstructor
 @Slf4j
 public class DmiRestClient {
+
     private static final String HEALTH_CHECK_URL_EXTENSION = "/actuator/health";
     private static final String NOT_SPECIFIED = "";
-    private static final String NO_AUTHORIZATION = null;
-    private final WebClient webClient;
+    private final RestTemplate restTemplate;
     private final DmiProperties dmiProperties;
 
     /**
@@ -60,19 +59,14 @@ public class DmiRestClient {
                                                             final String requestBodyAsJsonString,
                                                             final OperationType operationType,
                                                             final String authorization) {
+        final var httpEntity = new HttpEntity<>(requestBodyAsJsonString, configureHttpHeaders(new HttpHeaders(),
+                authorization));
         try {
-            return webClient.post().uri(new URI(dmiResourceUrl))
-                    .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization))
-                    .body(BodyInserters.fromValue(requestBodyAsJsonString))
-                    .retrieve()
-                    .toEntity(Object.class)
-                    .block();
+            return restTemplate.postForEntity(dmiResourceUrl, httpEntity, Object.class);
         } catch (final HttpStatusCodeException httpStatusCodeException) {
             final String exceptionMessage = "Unable to " + operationType.toString() + " resource data.";
             throw new HttpClientRequestException(exceptionMessage, httpStatusCodeException.getResponseBodyAsString(),
-                    httpStatusCodeException.getStatusCode().value());
-        } catch (final URISyntaxException ex) {
-            throw new RuntimeException(ex);
+                httpStatusCodeException.getStatusCode().value());
         }
     }
 
@@ -83,14 +77,13 @@ public class DmiRestClient {
      * @return      plugin health status ("UP" is all OK, "" (not-specified) in case of any exception)
      */
     public String getDmiHealthStatus(final String dmiPluginBaseUrl) {
+        final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders(), null));
         try {
-            final JsonNode responseHealthStatus = webClient.get()
-                    .uri(new URI(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION))
-                    .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
-                    .retrieve()
-                    .bodyToMono(JsonNode.class).block();
+            final JsonNode responseHealthStatus =
+                restTemplate.getForObject(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION,
+                    JsonNode.class, httpHeaders);
             return responseHealthStatus == null ? NOT_SPECIFIED :
-                    responseHealthStatus.get("status").asText();
+                responseHealthStatus.get("status").asText();
         } catch (final Exception e) {
             log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiPluginBaseUrl, e.getMessage());
             return NOT_SPECIFIED;
@@ -103,6 +96,7 @@ public class DmiRestClient {
         } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) {
             httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization);
         }
+        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
         return httpHeaders;
     }
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
deleted file mode 100644 (file)
index 8ac2e3f..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-
-/*
- *  ============LICENSE_START=======================================================
- *  Copyright (C) 2024 Nordix Foundation
- *  ================================================================================
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  SPDX-License-Identifier: Apache-2.0
- *  ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.config;
-
-import io.netty.channel.ChannelOption;
-import io.netty.handler.timeout.ReadTimeoutHandler;
-import io.netty.handler.timeout.WriteTimeoutHandler;
-import java.util.concurrent.TimeUnit;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.reactive.ReactorClientHttpConnector;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.netty.http.client.HttpClient;
-
-@Slf4j
-@Configuration
-@RequiredArgsConstructor
-public class DmiWebClientConfiguration {
-
-    @Value("${ncmp.dmi.httpclient.connectionTimeoutInSeconds:20000}")
-    private Integer connectionTimeoutInSeconds;
-
-    @Value("${ncmp.dmi.httpclient.maximumInMemorySizeInMegabytes:1}")
-    private Integer maximumInMemorySizeInMegabytes;
-
-    @Getter
-    @Component
-    public static class DmiProperties {
-        @Value("${ncmp.dmi.auth.username}")
-        private String authUsername;
-        @Value("${ncmp.dmi.auth.password}")
-        private String authPassword;
-        @Value("${ncmp.dmi.api.base-path}")
-        private String dmiBasePath;
-        @Value("${ncmp.dmi.auth.enabled}")
-        private boolean dmiBasicAuthEnabled;
-    }
-
-    /**
-     * Configures and create a WebClient bean.
-     *
-     * @return a WebClient instance.
-     */
-    @Bean
-    public WebClient webClient() {
-        final var httpClient = HttpClient.create()
-                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeoutInSeconds * 1000)
-                .doOnConnected(connection ->
-                        connection
-                                .addHandlerLast(new ReadTimeoutHandler(connectionTimeoutInSeconds, TimeUnit.SECONDS))
-                                .addHandlerLast(new WriteTimeoutHandler(connectionTimeoutInSeconds, TimeUnit.SECONDS)));
-
-        return WebClient.builder()
-                .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
-                .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
-                .clientConnector(new ReactorClientHttpConnector(httpClient))
-                .codecs(configurer -> configurer
-                        .defaultCodecs()
-                        .maxInMemorySize(maximumInMemorySizeInMegabytes * 1024 * 1024))
-                .build();
-    }
-}
index 729930e..d547e31 100644 (file)
@@ -1,4 +1,4 @@
-/*-
+/*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2023 Nordix Foundation.
  * ================================================================================
index 32852b3..c6ff116 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl.config;
 
 import java.util.Arrays;
 import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
@@ -30,6 +31,7 @@ import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
 import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.client.RestTemplateBuilder;
@@ -40,6 +42,7 @@ import org.springframework.http.MediaType;
 import org.springframework.http.client.ClientHttpRequestFactory;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.stereotype.Component;
 import org.springframework.web.client.RestTemplate;
 
 @Configuration
@@ -47,6 +50,19 @@ import org.springframework.web.client.RestTemplate;
 @RequiredArgsConstructor(access = AccessLevel.PROTECTED)
 public class NcmpConfiguration {
 
+    @Getter
+    @Component
+    public static class DmiProperties {
+        @Value("${ncmp.dmi.auth.username}")
+        private String authUsername;
+        @Value("${ncmp.dmi.auth.password}")
+        private String authPassword;
+        @Value("${ncmp.dmi.api.base-path}")
+        private String dmiBasePath;
+        @Value("${ncmp.dmi.auth.enabled}")
+        private boolean dmiBasicAuthEnabled;
+    }
+
     /**
      * Rest template bean.
      *
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java
new file mode 100644 (file)
index 0000000..50a5df5
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2024 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an 'AS IS' BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.impl.events.cmsubscription;
+
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionDmiInEventProducer;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer;
+import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
+import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class CmNotificationSubscriptionEventsHandler {
+    private final CmNotificationSubscriptionNcmpOutEventProducer cmNotificationSubscriptionNcmpOutEventProducer;
+    private final CmNotificationSubscriptionDmiInEventProducer cmNotificationSubscriptionDmiInEventProducer;
+
+    /**
+     * Publish the event to the client who requested the subscription with key as subscription id and event is Cloud
+     * Event compliant.
+     *
+     * @param subscriptionId                         Cm Subscription id
+     * @param eventType                              Type of event
+     * @param cmNotificationSubscriptionNcmpOutEvent Cm Notification Subscription Event for the
+     *                                               client
+     * @param isScheduledEvent                       Determines if the event is to be scheduled
+     *                                               or published now
+     */
+    public void publishCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId, final String eventType,
+                                                              final CmNotificationSubscriptionNcmpOutEvent
+                                                                      cmNotificationSubscriptionNcmpOutEvent,
+                                                              final boolean isScheduledEvent) {
+        cmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+                eventType, cmNotificationSubscriptionNcmpOutEvent, isScheduledEvent);
+    }
+
+    /**
+     * Publish the event to the provided dmi plugin with key as subscription id and the event is in Cloud Event format.
+     *
+     * @param subscriptionId                       Cm Subscription id
+     * @param dmiPluginName                        Dmi Plugin Name
+     * @param eventType                            Type of event
+     * @param cmNotificationSubscriptionDmiInEvent Cm Notification Subscription event for Dmi
+     */
+    public void publishCmNotificationSubscriptionDmiInEvent(final String subscriptionId, final String dmiPluginName,
+                                                            final String eventType,
+                                                            final CmNotificationSubscriptionDmiInEvent
+                                                                    cmNotificationSubscriptionDmiInEvent) {
+        cmNotificationSubscriptionDmiInEventProducer.publishCmNotificationSubscriptionDmiInEvent(subscriptionId,
+                dmiPluginName, eventType, cmNotificationSubscriptionDmiInEvent);
+    }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java
new file mode 100644 (file)
index 0000000..73f9563
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Nordix Foundation
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.impl.events.cmsubscription;
+
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionDmiInEventMapper;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
+import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
+import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class CmNotificationSubscriptionMappersHandler {
+
+    private final CmNotificationSubscriptionDmiInEventMapper cmNotificationSubscriptionDmiInEventMapper;
+    private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper;
+
+    /**
+     * Mapper to form a request for the DMI Plugin for the Cm Notification Subscription.
+     *
+     * @param dmiCmNotificationSubscriptionPredicates Collection of Cm Notification Subscription predicates
+     * @return cm notification subscription dmi in event
+     */
+    public CmNotificationSubscriptionDmiInEvent toCmNotificationSubscriptionDmiInEvent(
+            final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
+        return cmNotificationSubscriptionDmiInEventMapper.toCmNotificationSubscriptionDmiInEvent(
+                dmiCmNotificationSubscriptionPredicates);
+    }
+
+    /**
+     * Mapper to form a response for the client for the Cm Notification Subscription.
+     *
+     * @param subscriptionId                          Cm Notification Subscription id
+     * @param dmiCmNotificationSubscriptionDetailsMap contains CmNotificationSubscriptionDetails per dmi plugin
+     * @return CmNotificationSubscriptionNcmpOutEvent to sent back to the client
+     */
+    public CmNotificationSubscriptionNcmpOutEvent toCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId,
+         final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap) {
+        return cmNotificationSubscriptionNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+                dmiCmNotificationSubscriptionDetailsMap);
+    }
+
+    /**
+     * Mapper to form a rejected response for the client for the Cm Notification Subscription Request.
+     *
+     * @param subscriptionId subscription id
+     * @param rejectedTargetFilters list of rejected target filters for the subscription request
+     * @return to sent back to the client
+     */
+    public CmNotificationSubscriptionNcmpOutEvent toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
+            final String subscriptionId, final List<String> rejectedTargetFilters) {
+        return cmNotificationSubscriptionNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
+                subscriptionId, rejectedTargetFilters);
+    }
+}
index b2c0a5c..f7dd51e 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.events.cmsubscription;
 
-import static org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionNcmpOutEventProducer.buildAndGetCmNotificationNcmpOutEventAsCloudEvent;
+import static org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer.buildAndGetCmNotificationNcmpOutEventAsCloudEvent;
 
 import io.cloudevents.CloudEvent;
 import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.events.EventsPublisher;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper;
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
 import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
 import org.onap.cps.utils.JsonObjectMapper;
@@ -36,13 +35,12 @@ import org.onap.cps.utils.JsonObjectMapper;
 @RequiredArgsConstructor
 public class CmNotificationSubscriptionNcmpOutEventPublishingTask implements Runnable {
 
-
     private final String topicName;
     private final String subscriptionId;
     private final String eventType;
     private final EventsPublisher<CloudEvent> eventsPublisher;
     private final JsonObjectMapper jsonObjectMapper;
-    private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper;
+    private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
     private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
 
     /**
@@ -54,7 +52,7 @@ public class CmNotificationSubscriptionNcmpOutEventPublishingTask implements Run
         final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap =
                 dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId);
         final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
-                cmNotificationSubscriptionNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+                cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
                         dmiCmNotificationSubscriptionDetailsMap);
         eventsPublisher.publishCloudEvent(topicName, subscriptionId,
                 buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType,
@@ -62,5 +60,4 @@ public class CmNotificationSubscriptionNcmpOutEventPublishingTask implements Run
         dmiCmNotificationSubscriptionCacheHandler
                 .removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId);
     }
-
 }
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.impl.events.cmsubscription;
+package org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer;
 
 import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent;
 
@@ -26,6 +26,7 @@ import io.cloudevents.CloudEvent;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler;
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus;
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent;
 import org.springframework.kafka.annotation.KafkaListener;
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.impl.events.cmsubscription;
+package org.onap.cps.ncmp.api.impl.events.cmsubscription.producer;
 
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
@@ -33,7 +33,9 @@ import java.util.concurrent.TimeUnit;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.events.EventsPublisher;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionMappersHandler;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionNcmpOutEventPublishingTask;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler;
 import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.beans.factory.annotation.Value;
@@ -54,7 +56,7 @@ public class CmNotificationSubscriptionNcmpOutEventProducer {
 
     private final EventsPublisher<CloudEvent> eventsPublisher;
     private final JsonObjectMapper jsonObjectMapper;
-    private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper;
+    private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
     private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
     private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
     private static final Map<String, ScheduledFuture<?>> scheduledTasksPerSubscriptionId = new ConcurrentHashMap<>();
@@ -94,7 +96,7 @@ public class CmNotificationSubscriptionNcmpOutEventProducer {
                 cmNotificationSubscriptionNcmpOutEventPublishingTask =
                 new CmNotificationSubscriptionNcmpOutEventPublishingTask(cmNotificationSubscriptionNcmpOutEventTopic,
                         subscriptionId, eventType, eventsPublisher, jsonObjectMapper,
-                        cmNotificationSubscriptionNcmpOutEventMapper, dmiCmNotificationSubscriptionCacheHandler);
+                        cmNotificationSubscriptionMappersHandler, dmiCmNotificationSubscriptionCacheHandler);
         return scheduledExecutorService.schedule(cmNotificationSubscriptionNcmpOutEventPublishingTask,
                 cmNotificationSubscriptionDmiOutEventTimeoutInMs, TimeUnit.MILLISECONDS);
     }
@@ -122,7 +124,16 @@ public class CmNotificationSubscriptionNcmpOutEventProducer {
                 .removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId);
     }
 
-    protected static CloudEvent buildAndGetCmNotificationNcmpOutEventAsCloudEvent(
+    /**
+     * Get an NCMP out event as cloud event.
+     *
+     * @param jsonObjectMapper  JSON object mapper
+     * @param subscriptionId subscription id
+     * @param eventType event type
+     * @param cmNotificationSubscriptionNcmpOutEvent cm notification subscription NCMP out event
+     * @return cm notification subscription NCMP out event as cloud event
+     */
+    public static CloudEvent buildAndGetCmNotificationNcmpOutEventAsCloudEvent(
             final JsonObjectMapper jsonObjectMapper, final String subscriptionId, final String eventType,
             final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent) {
 
index 8204f05..395c511 100644 (file)
@@ -22,14 +22,19 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription.service;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionNcmpOutEventProducer;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionDelta;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionEventsHandler;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionMappersHandler;
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent;
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.Predicate;
+import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
 import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
 import org.springframework.stereotype.Service;
 
@@ -38,21 +43,23 @@ import org.springframework.stereotype.Service;
 public class CmNotificationSubscriptionHandlerServiceImpl implements CmNotificationSubscriptionHandlerService {
 
     private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService;
-    private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper;
-    private final CmNotificationSubscriptionNcmpOutEventProducer cmNotificationSubscriptionNcmpOutEventProducer;
+    private final CmNotificationSubscriptionDelta cmNotificationSubscriptionDelta;
+    private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
+    private final CmNotificationSubscriptionEventsHandler cmNotificationSubscriptionEventsHandler;
     private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
 
     @Override
     public void processSubscriptionCreateRequest(
-        final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent) {
+            final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent) {
         final String subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId();
         final List<Predicate> predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates();
 
         if (cmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId(subscriptionId)) {
             dmiCmNotificationSubscriptionCacheHandler.add(subscriptionId, predicates);
+            sendSubscriptionCreateRequestToDmi(subscriptionId);
         } else {
             final Set<String> subscriptionTargetFilters = predicates.stream().flatMap(
-                predicate -> predicate.getTargetFilter().stream()).collect(Collectors.toSet());
+                    predicate -> predicate.getTargetFilter().stream()).collect(Collectors.toSet());
             rejectAndPublishCmNotificationSubscriptionCreateRequest(subscriptionId,
                     new ArrayList<>(subscriptionTargetFilters));
         }
@@ -61,10 +68,25 @@ public class CmNotificationSubscriptionHandlerServiceImpl implements CmNotificat
     private void rejectAndPublishCmNotificationSubscriptionCreateRequest(final String subscriptionId,
                                                                          final List<String> subscriptionTargetFilters) {
         final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
-            cmNotificationSubscriptionNcmpOutEventMapper
-                .toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(subscriptionId,
-                    subscriptionTargetFilters);
-        cmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
-            "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false);
+                cmNotificationSubscriptionMappersHandler
+                        .toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(subscriptionId,
+                                subscriptionTargetFilters);
+        cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+                "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false);
     }
-}
+
+    private void sendSubscriptionCreateRequestToDmi(final String subscriptionId) {
+        final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap =
+                dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId);
+        dmiCmNotificationSubscriptionDetailsMap.forEach((dmiPluginName, dmiCmNotificationSubscriptionDetails) -> {
+            final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates =
+                    cmNotificationSubscriptionDelta.getDelta(
+                            dmiCmNotificationSubscriptionDetails.getDmiCmNotificationSubscriptionPredicates());
+            final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent =
+                    cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionDmiInEvent(
+                            dmiCmNotificationSubscriptionPredicates);
+            cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(subscriptionId,
+                    dmiPluginName, "subscriptionCreateRequest", cmNotificationSubscriptionDmiInEvent);
+        });
+    }
+}
\ No newline at end of file
index cac25c8..a9ec124 100644 (file)
@@ -35,7 +35,7 @@ import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.NcmpResponseStatus;
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException;
 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
@@ -61,7 +61,7 @@ public class DmiDataOperations extends DmiOperations {
 
     public DmiDataOperations(final InventoryPersistence inventoryPersistence,
                              final JsonObjectMapper jsonObjectMapper,
-                             final DmiProperties dmiProperties,
+                             final NcmpConfiguration.DmiProperties dmiProperties,
                              final DmiRestClient dmiRestClient,
                              final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
         super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
@@ -226,7 +226,7 @@ public class DmiDataOperations extends DmiOperations {
     }
 
     private static Set<String> getDistinctCmHandleIdsFromDataOperationRequest(final DataOperationRequest
-                                                                                      dataOperationRequest) {
+                                                                              dataOperationRequest) {
         return dataOperationRequest.getDataOperationDefinitions().stream()
                 .flatMap(dataOperationDefinition ->
                         dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet());
@@ -235,7 +235,7 @@ public class DmiDataOperations extends DmiOperations {
     private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery,
                                                                  final String requestId,
                                                                  final Map<String, List<DmiDataOperation>>
-                                                                         groupsOutPerDmiServiceName,
+                                                                groupsOutPerDmiServiceName,
                                                                  final String authorization) {
 
         groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> {
index c71da1c..3a281d7 100644 (file)
@@ -32,7 +32,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
@@ -55,7 +55,7 @@ public class DmiModelOperations extends DmiOperations {
      */
     public DmiModelOperations(final InventoryPersistence inventoryPersistence,
                               final JsonObjectMapper jsonObjectMapper,
-                              final DmiProperties dmiProperties,
+                              final NcmpConfiguration.DmiProperties dmiProperties,
                               final DmiRestClient dmiRestClient, final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
         super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
     }
@@ -71,7 +71,7 @@ public class DmiModelOperations extends DmiOperations {
                 .moduleSetTag(yangModelCmHandle.getModuleSetTag()).build();
         dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties());
         final ResponseEntity<Object> dmiFetchModulesResponseEntity = getResourceFromDmiWithJsonData(
-                yangModelCmHandle.resolveDmiServiceName(MODEL),
+            yangModelCmHandle.resolveDmiServiceName(MODEL),
                 jsonObjectMapper.asJsonString(dmiRequestBody), yangModelCmHandle.getId(), "modules");
         return toModuleReferences((Map) dmiFetchModulesResponseEntity.getBody());
     }
@@ -89,12 +89,12 @@ public class DmiModelOperations extends DmiOperations {
             return Collections.emptyMap();
         }
         final String jsonWithDataAndDmiProperties = getRequestBodyToFetchYangResources(
-                newModuleReferences, yangModelCmHandle.getDmiProperties());
+            newModuleReferences, yangModelCmHandle.getDmiProperties());
         final ResponseEntity<Object> responseEntity = getResourceFromDmiWithJsonData(
-                yangModelCmHandle.resolveDmiServiceName(MODEL),
-                jsonWithDataAndDmiProperties,
-                yangModelCmHandle.getId(),
-                "moduleResources");
+            yangModelCmHandle.resolveDmiServiceName(MODEL),
+            jsonWithDataAndDmiProperties,
+            yangModelCmHandle.getId(),
+            "moduleResources");
         return asModuleNameToYangResourceMap(responseEntity);
     }
 
@@ -112,12 +112,12 @@ public class DmiModelOperations extends DmiOperations {
                                                                   final String cmHandle,
                                                                   final String resourceName) {
         final String dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName);
-        return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl,
-                jsonRequestBody, OperationType.READ, null);
+        return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody,
+                OperationType.READ, null);
     }
 
     private static String getRequestBodyToFetchYangResources(final Collection<ModuleReference> newModuleReferences,
-                                                             final List<YangModelCmHandle.Property> dmiProperties) {
+        final List<YangModelCmHandle.Property> dmiProperties) {
         final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(newModuleReferences);
         final JsonObject data = new JsonObject();
         data.add("modules", moduleReferencesAsJson);
@@ -140,7 +140,7 @@ public class DmiModelOperations extends DmiOperations {
     }
 
     private static JsonObject toJsonObject(final List<YangModelCmHandle.Property>
-                                                   dmiProperties) {
+                                               dmiProperties) {
         final JsonObject asJsonObject = new JsonObject();
         for (final YangModelCmHandle.Property additionalProperty : dmiProperties) {
             asJsonObject.addProperty(additionalProperty.getName(), additionalProperty.getValue());
@@ -173,7 +173,7 @@ public class DmiModelOperations extends DmiOperations {
                 final YangResource yangResource =
                         jsonObjectMapper.convertToValueType(yangResourceAsMap, YangResource.class);
                 yangResourcesModuleNameToContentMap.put(yangResource.getModuleName(),
-                        yangResource.getYangSource());
+                    yangResource.getYangSource());
             });
         }
         return yangResourcesModuleNameToContentMap;
index 912c52c..c8d73ea 100644 (file)
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.operations;
 
 import lombok.RequiredArgsConstructor;
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
 import org.onap.cps.utils.JsonObjectMapper;
@@ -35,7 +35,7 @@ public class DmiOperations {
 
     protected final InventoryPersistence inventoryPersistence;
     protected final JsonObjectMapper jsonObjectMapper;
-    protected final DmiProperties dmiProperties;
+    protected final NcmpConfiguration.DmiProperties dmiProperties;
     protected final DmiRestClient dmiRestClient;
     protected final DmiServiceUrlBuilder dmiServiceUrlBuilder;
 
index e0c9568..04acaa5 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.utils;
 
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import org.apache.logging.log4j.util.Strings;
 import org.apache.logging.log4j.util.TriConsumer;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
 import org.onap.cps.spi.utils.CpsValidator;
 import org.springframework.stereotype.Component;
 import org.springframework.util.LinkedMultiValueMap;
@@ -37,7 +35,8 @@ import org.springframework.web.util.UriComponentsBuilder;
 @Component
 @RequiredArgsConstructor
 public class DmiServiceUrlBuilder {
-    private final DmiProperties dmiProperties;
+
+    private final NcmpConfiguration.DmiProperties dmiProperties;
     private final CpsValidator cpsValidator;
 
     /**
@@ -142,7 +141,8 @@ public class DmiServiceUrlBuilder {
                                                              final String optionsParamInQuery,
                                                              final String topicParamInQuery) {
         final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
-        getQueryParamConsumer().accept("resourceIdentifier", resourceId, queryParams);
+        getQueryParamConsumer().accept("resourceIdentifier",
+                resourceId, queryParams);
         getQueryParamConsumer().accept("options", optionsParamInQuery, queryParams);
         if (Strings.isNotEmpty(topicParamInQuery)) {
             getQueryParamConsumer().accept("topic", topicParamInQuery, queryParams);
@@ -168,7 +168,7 @@ public class DmiServiceUrlBuilder {
     private TriConsumer<String, String, MultiValueMap<String, String>> getQueryParamConsumer() {
         return (paramName, paramValue, paramMap) -> {
             if (Strings.isNotEmpty(paramValue)) {
-                paramMap.add(paramName, URLEncoder.encode(paramValue, StandardCharsets.UTF_8));
+                paramMap.add(paramName, paramValue);
             }
         };
     }
index 003dbf5..c8e34b1 100644 (file)
@@ -24,21 +24,20 @@ package org.onap.cps.ncmp.api.impl.client
 import com.fasterxml.jackson.databind.JsonNode
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.databind.node.ObjectNode
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties;
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
 import org.onap.cps.ncmp.utils.TestUtils
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.context.SpringBootTest
-
+import org.springframework.http.HttpEntity
 import org.springframework.http.HttpHeaders
 import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
 import org.springframework.test.context.ContextConfiguration
-import org.springframework.test.context.TestPropertySource
 import org.springframework.web.client.HttpServerErrorException
-import org.springframework.web.reactive.function.client.WebClient
-import reactor.core.publisher.Mono
+import org.springframework.web.client.RestTemplate
 import spock.lang.Specification
 
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
@@ -46,49 +45,43 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
 
 @SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration, DmiRestClient, ObjectMapper])
+@ContextConfiguration(classes = [DmiProperties, DmiRestClient, ObjectMapper])
 class DmiRestClientSpec extends Specification {
 
     static final NO_AUTH_HEADER = null
     static final BASIC_AUTH_HEADER = 'Basic c29tZS11c2VyOnNvbWUtcGFzc3dvcmQ='
     static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token'
 
+    @SpringBean
+    RestTemplate mockRestTemplate = Mock(RestTemplate)
+
     @Autowired
-    DmiWebClientConfiguration.DmiProperties dmiProperties
+    NcmpConfiguration.DmiProperties dmiProperties
 
     @Autowired
     DmiRestClient objectUnderTest
 
-    @SpringBean
-    WebClient mockWebClient = Mock(WebClient);
-
     @Autowired
     ObjectMapper objectMapper
 
-    def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec)
-    def mockResponseSpec = Mock(WebClient.ResponseSpec)
-    def mockResponseEntity = Mock(ResponseEntity)
-    def monoSpec = Mono.just(mockResponseEntity)
+    def responseFromRestTemplate = Mock(ResponseEntity)
+
     def 'DMI POST operation with JSON.'() {
-        given: 'the web client returns a valid response entity for the expected parameters'
-            mockWebClient.post() >> mockRequestBodyUriSpec
-            mockWebclientResponse()
-            mockRequestBodyUriSpec.body(_) >> mockRequestBodyUriSpec
-            mockResponseSpec.toEntity(Object.class) >> monoSpec
-            monoSpec.block() >> mockResponseEntity
+        given: 'the rest template returns a valid response entity for the expected parameters'
+            mockRestTemplate.postForEntity('my url', _ as HttpEntity, Object.class) >> responseFromRestTemplate
         when: 'POST operation is invoked'
-            def result = objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
+            def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ, null)
         then: 'the output of the method is equal to the output from the test template'
-            result == mockResponseEntity
+            result == responseFromRestTemplate
     }
 
     def 'Failing DMI POST operation.'() {
         given: 'the rest template returns a valid response entity'
             def serverResponse = 'server response'.getBytes()
             def httpServerErrorException = new HttpServerErrorException(HttpStatus.FORBIDDEN, 'status text', serverResponse, null)
-            mockWebClient.post() >> { throw httpServerErrorException }
+            mockRestTemplate.postForEntity(*_) >> { throw httpServerErrorException }
         when: 'POST operation is invoked'
-            def result = objectUnderTest.postOperationWithJsonData('/some', 'some json', operation, null)
+            def result = objectUnderTest.postOperationWithJsonData('some url', 'some json', operation, null)
         then: 'a Http Client Exception is thrown'
             def thrown = thrown(HttpClientRequestException)
         and: 'the exception has the relevant details from the error response'
@@ -104,20 +97,16 @@ class DmiRestClientSpec extends Specification {
             def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json')
             def jsonNode = objectMapper.readValue(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
             ((ObjectNode) jsonNode).put('status', 'my status')
-            def monoResponse = Mono.just(jsonNode)
-            mockWebClient.get() >> mockRequestBodyUriSpec
-            mockWebclientResponse()
-            mockResponseSpec.bodyToMono(_) >> monoResponse
-            monoResponse.block() >> jsonNode
+            mockRestTemplate.getForObject(*_) >> {jsonNode}
         when: 'get trust level of the dmi plugin'
-            def result = objectUnderTest.getDmiHealthStatus('some/url')
+            def result = objectUnderTest.getDmiHealthStatus('some url')
         then: 'the status value from the json is return'
             assert result == 'my status'
     }
 
     def 'Failing to get dmi plugin health status #scenario'() {
         given: 'rest template with #scenario'
-            mockWebClient.get() >> healthStatusResponse
+            mockRestTemplate.getForObject(*_) >> healthStatusResponse
         when: 'attempt to get health status of the dmi plugin'
             def result = objectUnderTest.getDmiHealthStatus('some url')
         then: 'result will be empty'
@@ -144,9 +133,4 @@ class DmiRestClientSpec extends Specification {
             'DMI basic auth disabled, with NCMP basic auth'   | false       | BASIC_AUTH_HEADER  || NO_AUTH_HEADER
     }
 
-    def mockWebclientResponse() {
-        mockRequestBodyUriSpec.uri(_) >> mockRequestBodyUriSpec
-        mockRequestBodyUriSpec.headers(_) >> mockRequestBodyUriSpec
-        mockRequestBodyUriSpec.retrieve() >> mockResponseSpec
-    }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
deleted file mode 100644 (file)
index 2ce5b50..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.config
-
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.test.context.ContextConfiguration
-import org.springframework.test.context.TestPropertySource
-import org.springframework.web.reactive.function.client.WebClient
-import spock.lang.Specification
-
-@SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration.DmiProperties])
-@TestPropertySource(properties = ["ncmp.dmi.httpclient.connectionTimeoutInSeconds=1", "ncmp.dmi.httpclient.maximumInMemorySizeInMegabytes=1"])
-class DmiWebClientConfigurationSpec extends Specification {
-
-    @Autowired
-    DmiWebClientConfiguration.DmiProperties dmiProperties
-
-    def objectUnderTest = new DmiWebClientConfiguration()
-
-    def setup() {
-        objectUnderTest.connectionTimeoutInSeconds = 10
-        objectUnderTest.maximumInMemorySizeInMegabytes = 1
-    }
-
-    def 'DMI Properties.'() {
-        expect: 'properties are set to values in test configuration yaml file'
-            dmiProperties.authUsername == 'some-user'
-            dmiProperties.authPassword == 'some-password'
-    }
-
-    def 'Web Client Configuration construction.'() {
-        expect: 'the system can create an instance'
-            new DmiWebClientConfiguration() != null
-    }
-
-    def 'Creating a WebClient instance.'() {
-        given: 'WebClient configuration invoked'
-            def webClientInstance = objectUnderTest.webClient()
-        expect: 'the system can create an instance'
-            assert webClientInstance != null
-            assert webClientInstance instanceof WebClient
-    }
-}
index f588e2e..74e3424 100644 (file)
@@ -31,9 +31,12 @@ import org.springframework.web.client.RestTemplate
 import spock.lang.Specification
 
 @SpringBootTest
-@ContextConfiguration(classes = [ HttpClientConfiguration])
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, HttpClientConfiguration])
 class NcmpConfigurationSpec extends Specification{
 
+    @Autowired
+    NcmpConfiguration.DmiProperties dmiProperties
+
     @Autowired
     HttpClientConfiguration httpClientConfiguration
 
@@ -44,6 +47,12 @@ class NcmpConfigurationSpec extends Specification{
              new NcmpConfiguration() != null
     }
 
+    def 'DMI Properties.'() {
+        expect: 'properties are set to values in test configuration yaml file'
+            dmiProperties.authUsername == 'some-user'
+            dmiProperties.authPassword == 'some-password'
+    }
+
     def 'Rest Template creation with CloseableHttpClient and MappingJackson2HttpMessageConverter.'() {
         when: 'a rest template is created'
             def result = NcmpConfiguration.restTemplate(mockRestTemplateBuilder, httpClientConfiguration)
index cd9b8dd..cfb28a0 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription
 import com.fasterxml.jackson.databind.ObjectMapper
 import io.cloudevents.CloudEvent
 import org.onap.cps.events.EventsPublisher
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionDmiInEventProducer
 import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Cmhandle
index 523ec76..c761f4d 100644 (file)
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import io.cloudevents.CloudEvent
 import io.cloudevents.core.builder.CloudEventBuilder
 import org.apache.kafka.clients.consumer.ConsumerRecord
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer.CmNotificationSubscriptionDmiOutEventConsumer
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
 import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy
new file mode 100644 (file)
index 0000000..788a7a7
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2024 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an 'AS IS' BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.impl.events.cmsubscription
+
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionDmiInEventProducer
+import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent
+import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent
+import spock.lang.Specification
+
+class CmNotificationSubscriptionEventsHandlerSpec extends Specification {
+
+    def mockCmNotificationSubscriptionNcmpOutEventProducer = Mock(CmNotificationSubscriptionNcmpOutEventProducer)
+    def mockCmNotificationSubscriptionDmiInEventProducer = Mock(CmNotificationSubscriptionDmiInEventProducer)
+
+    def objectUnderTest = new CmNotificationSubscriptionEventsHandler(mockCmNotificationSubscriptionNcmpOutEventProducer,
+        mockCmNotificationSubscriptionDmiInEventProducer)
+
+    def 'Publish cm notification subscription ncmp out event'() {
+        given: 'an ncmp out event'
+            def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent()
+        when: 'the method to publish cm notification subscription ncmp out event is called'
+            objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent("some-id",
+                "some-event", cmNotificationSubscriptionNcmpOutEvent, true)
+        then: 'the parameters is delegated to the correct method once'
+            1 * mockCmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent(
+                "some-id", "some-event", cmNotificationSubscriptionNcmpOutEvent, true)
+    }
+
+    def 'Publish cm notification subscription dmi in event'() {
+        given: 'a dmi in event'
+            def cmNotificationSubscriptionDmiInEvent = new CmNotificationSubscriptionDmiInEvent()
+        when: 'the method to publish cm notification subscription ncmp out event is called'
+            objectUnderTest.publishCmNotificationSubscriptionDmiInEvent("some-id",
+                "some-dmi", "some-event", cmNotificationSubscriptionDmiInEvent)
+        then: 'the parameters is delegated to the correct method once'
+            1 * mockCmNotificationSubscriptionDmiInEventProducer.publishCmNotificationSubscriptionDmiInEvent("some-id",
+                "some-dmi", "some-event", cmNotificationSubscriptionDmiInEvent)
+    }
+}
\ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy
new file mode 100644 (file)
index 0000000..bdc54bd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Nordix Foundation
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.impl.events.cmsubscription
+
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionDmiInEventMapper
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper
+import spock.lang.Specification
+
+class CmNotificationSubscriptionMappersHandlerSpec extends Specification{
+
+    def mockCmNotificationDmiInEventMapper = Mock(CmNotificationSubscriptionDmiInEventMapper)
+    def mockCmNotificationNcmpOutEventMapper = Mock(CmNotificationSubscriptionNcmpOutEventMapper)
+
+    def objectUnderTest = new CmNotificationSubscriptionMappersHandler(mockCmNotificationDmiInEventMapper,
+        mockCmNotificationNcmpOutEventMapper)
+
+    def 'Get cm notification subscription DMI in event'() {
+        given: 'a list of predicates'
+            def testListOfPredicates = []
+        when: 'method to create a cm notification subscription dmi in event is called with predicates'
+            objectUnderTest.toCmNotificationSubscriptionDmiInEvent(testListOfPredicates)
+        then: 'the parameters is delegated to the correct dmi in event mapper method'
+            1 * mockCmNotificationDmiInEventMapper.toCmNotificationSubscriptionDmiInEvent(testListOfPredicates)
+    }
+
+    def 'Get cm notification subscription ncmp out event'() {
+        given: 'a subscription details map'
+            def testSubscriptionDetailsMap = [:]
+        when: 'method to create cm notification subscription ncmp out event is called with the following parameters'
+            objectUnderTest.toCmNotificationSubscriptionNcmpOutEvent("test-id", testSubscriptionDetailsMap)
+        then: 'the parameters is delegated to the correct ncmp out event mapper method'
+            1 * mockCmNotificationNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEvent("test-id",
+            testSubscriptionDetailsMap)
+    }
+
+    def 'Get cm notification subscription ncmp out event for a rejected request'() {
+        given: 'a list of target filters'
+            def testRejectedTargetFilters = []
+        when: 'method to create cm notification subscription ncmp out event is called with the following parameters'
+            objectUnderTest.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
+                "test-id", testRejectedTargetFilters)
+        then: 'the parameters is delegated to the correct ncmp out event mapper method'
+            1 * mockCmNotificationNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
+                "test-id", testRejectedTargetFilters)
+    }
+}
index 8210cf3..9c84c51 100644 (file)
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import io.cloudevents.CloudEvent
 import io.cloudevents.core.builder.CloudEventBuilder
 import org.apache.kafka.clients.consumer.ConsumerRecord
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer.CmNotificationSubscriptionNcmpInEventConsumer
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionHandlerService
 import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent
@@ -79,7 +80,7 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe
             def loggingEvent = getLoggingEvent()
             assert loggingEvent.level == Level.INFO
         and: 'the log indicates the task completed successfully'
-            assert loggingEvent.formattedMessage == 'Subscription for source some-resource with subscription id cm-subscription-001 ...'
+            assert loggingEvent.formattedMessage == 'Subscription for source some-resource with subscription id test-id ...'
         and: 'the subscription handler service is called once'
             1 * mockCmNotificationSubscriptionHandlerService.processSubscriptionCreateRequest(_)
     }
index 0f1bdc6..77bbe7e 100644 (file)
@@ -3,7 +3,7 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription
 import com.fasterxml.jackson.databind.ObjectMapper
 import io.cloudevents.CloudEvent
 import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer
 import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper
 import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent
 import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.Data
@@ -14,11 +14,11 @@ class CmNotificationSubscriptionNcmpOutEventProducerSpec extends Specification {
 
     def mockEventsPublisher = Mock(EventsPublisher)
     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
-    def mockCmNotificationSubscriptionNcmpOutEventMapper = Mock(CmNotificationSubscriptionNcmpOutEventMapper)
+    def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler)
     def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler)
 
     def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper,
-        mockCmNotificationSubscriptionNcmpOutEventMapper, mockDmiCmNotificationSubscriptionCacheHandler)
+        mockCmNotificationSubscriptionMappersHandler, mockDmiCmNotificationSubscriptionCacheHandler)
 
     def 'Create and #scenario Cm Notification Subscription NCMP out event'() {
         given: 'a cm subscription response for the client'
index 1020f55..7d1a1d6 100644 (file)
 package org.onap.cps.ncmp.api.impl.events.cmsubscription.service
 
 import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionNcmpOutEventProducer
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionDelta
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionEventsHandler
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionMappersHandler
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionDmiInEventMapper
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails
 import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent
+import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent
+import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent
 import org.onap.cps.ncmp.utils.TestUtils
 import org.onap.cps.utils.JsonObjectMapper
 import spock.lang.Specification
@@ -33,31 +40,55 @@ class CmNotificationSubscriptionHandlerServiceImplSpec extends Specification{
 
     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
     def mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService);
-    def mockCmNotificationSubscriptionNcmpOutEventMapper = Mock(CmNotificationSubscriptionNcmpOutEventMapper);
-    def mockCmNotificationSubscriptionNcmpOutEventProducer = Mock(CmNotificationSubscriptionNcmpOutEventProducer);
+    def mockCmNotificationSubscriptionDelta = Mock(CmNotificationSubscriptionDelta);
+    def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler);
+    def mockCmNotificationSubscriptionEventsHandler = Mock(CmNotificationSubscriptionEventsHandler);
     def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler);
 
-    def objectUnderTest = new CmNotificationSubscriptionHandlerServiceImpl(mockCmNotificationSubscriptionPersistenceService, mockCmNotificationSubscriptionNcmpOutEventMapper, mockCmNotificationSubscriptionNcmpOutEventProducer, mockDmiCmNotificationSubscriptionCacheHandler)
+    def objectUnderTest = new CmNotificationSubscriptionHandlerServiceImpl(mockCmNotificationSubscriptionPersistenceService,
+        mockCmNotificationSubscriptionDelta, mockCmNotificationSubscriptionMappersHandler,
+        mockCmNotificationSubscriptionEventsHandler, mockDmiCmNotificationSubscriptionCacheHandler)
+
+    def testSubscriptionDetailsMap = ["dmi-1":new DmiCmNotificationSubscriptionDetails([], CmNotificationSubscriptionStatus.PENDING)]
+    def testListOfDeltaPredicates = []
 
     def 'Consume valid and unique CmNotificationSubscriptionNcmpInEvent create message'() {
-        given: 'a cmNotificationSubscriptionNcmp in event'
+        given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id'
             def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
             def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class)
-            mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId('cm-subscription-001') >> true
+            mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true
+        and: 'the cache handler returns for relevant subscription id'
+            1 * mockDmiCmNotificationSubscriptionCacheHandler.get("test-id") >> testSubscriptionDetailsMap
+        and: 'the delta predicates is returned'
+            1 * mockCmNotificationSubscriptionDelta.getDelta(_) >> testListOfDeltaPredicates
+        and: 'the DMI in event mapper returns cm notification subscription event'
+            def testDmiInEvent = new CmNotificationSubscriptionDmiInEvent()
+            1 *  mockCmNotificationSubscriptionMappersHandler
+                .toCmNotificationSubscriptionDmiInEvent(testListOfDeltaPredicates) >> testDmiInEvent
         when: 'the valid and unique event is consumed'
             objectUnderTest.processSubscriptionCreateRequest(testEventConsumed)
         then: 'the subscription cache handler is called once'
-            1 * mockDmiCmNotificationSubscriptionCacheHandler.add('cm-subscription-001',_)
+            1 * mockDmiCmNotificationSubscriptionCacheHandler.add('test-id',_)
+        and: 'the events handler method to publish DMI event is called correct number of times with the correct parameters'
+            testSubscriptionDetailsMap.size() * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(
+                "test-id", "dmi-1", "subscriptionCreateRequest", testDmiInEvent)
     }
 
     def 'Consume valid and but non-unique CmNotificationSubscription create message'() {
         given: 'a cmNotificationSubscriptionNcmp in event'
             def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
             def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class)
-            mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId('cm-subscription-001') >> false
+            mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId('test-id') >> false
+        and: 'the NCMP out in event mapper returns an event for rejected request'
+            def testNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent()
+            1 * mockCmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
+                "test-id",_) >> testNcmpOutEvent
         when: 'the valid but non-unique event is consumed'
             objectUnderTest.processSubscriptionCreateRequest(testEventConsumed)
-        then: 'the subscription out event publisher is called once'
-            1 * mockCmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent('cm-subscription-001', 'subscriptionCreateResponse', _, false)
+        then: 'the events handler method to publish DMI event is never called'
+            0 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(_,_,_,_)
+        and: 'the events handler method to publish NCMP out event is called once'
+            1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(
+                'test-id', 'subscriptionCreateResponse', testNcmpOutEvent, false)
     }
 }
index e2062bc..eb6c7a0 100644 (file)
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.operations
 
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
 import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext
@@ -52,7 +52,7 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
 
 @SpringBootTest
-@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, DmiWebClientConfiguration.DmiProperties, DmiDataOperations])
+@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, NcmpConfiguration.DmiProperties, DmiDataOperations])
 class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
 
     @SpringBean
index a2ec9d1..e99e8a3 100644 (file)
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.operations
 
 import com.fasterxml.jackson.core.JsonProcessingException
 import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
 import org.onap.cps.spi.model.ModuleReference
 import org.onap.cps.utils.JsonObjectMapper
 import org.spockframework.spring.SpringBean
@@ -37,7 +37,7 @@ import spock.lang.Shared
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
 
 @SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration.DmiProperties, DmiModelOperations])
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiModelOperations])
 class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
 
     @Shared
index 061878e..b7af502 100644 (file)
@@ -22,7 +22,6 @@ package org.onap.cps.ncmp.api.impl.operations
 
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
@@ -51,7 +50,7 @@ abstract class DmiOperationsBaseSpec extends Specification {
     ObjectMapper spyObjectMapper = Spy()
 
     @SpringBean
-    DmiServiceUrlBuilder dmiServiceUrlBuilder = new DmiServiceUrlBuilder(new DmiWebClientConfiguration.DmiProperties(), mockCpsValidator)
+    DmiServiceUrlBuilder dmiServiceUrlBuilder = new DmiServiceUrlBuilder(new NcmpConfiguration.DmiProperties(), mockCpsValidator)
 
     def yangModelCmHandle = new YangModelCmHandle()
     def static dmiServiceName = 'some service name'
index 54e9f21..fbf2c3d 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.utils
 
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
-
 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
 
 import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService
 import org.onap.cps.spi.utils.CpsValidator
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
 import spock.lang.Specification
 
@@ -35,7 +34,7 @@ class DmiServiceUrlBuilderSpec extends Specification {
     static YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
         'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'),'my-module-set-tag', 'my-alternate-id', 'my-data-producer-identifier')
 
-    DmiWebClientConfiguration.DmiProperties dmiProperties = new DmiWebClientConfiguration.DmiProperties()
+    NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties()
 
     def mockCpsValidator = Mock(CpsValidator)
 
@@ -86,7 +85,7 @@ class DmiServiceUrlBuilderSpec extends Specification {
         when: 'a URL is created'
             def result = objectUnderTest.getDataOperationRequestUrl(batchRequestQueryParams, batchRequestUriVariables)
         then: 'it is formed correctly'
-            assert result.toString() == 'some-service/testBase/v1/data?topic=some+topic&requestId=some+id'
+            assert result.toString() == 'some-service/testBase/v1/data?topic=some topic&requestId=some id'
     }
 
     def 'Populate batch uri variables.'() {
index eca28b9..574b499 100644 (file)
@@ -38,7 +38,6 @@ ncmp:
     dmi:
         httpclient:
             connectionTimeoutInSeconds: 180
-            maximumInMemorySizeInMegabytes: 16
         auth:
             username: some-user
             password: some-password
index ca466d7..531efdf 100644 (file)
@@ -32,7 +32,7 @@
 
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-parent</artifactId>
-    <version>3.4.8-SNAPSHOT</version>
+    <version>3.4.9-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
index 93166ec..793b5a7 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 90422d7..7c9df08 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 583bad0..86b2ea8 100644 (file)
@@ -26,7 +26,7 @@
     <parent>\r
         <groupId>org.onap.cps</groupId>\r
         <artifactId>cps-parent</artifactId>\r
-        <version>3.4.8-SNAPSHOT</version>\r
+        <version>3.4.9-SNAPSHOT</version>\r
         <relativePath>../cps-parent/pom.xml</relativePath>\r
     </parent>\r
 \r
index adca617..647b2e4 100644 (file)
   <parent>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-parent</artifactId>
-    <version>3.4.8-SNAPSHOT</version>
+    <version>3.4.9-SNAPSHOT</version>
     <relativePath>../cps-parent/pom.xml</relativePath>
   </parent>
 
   <artifactId>cps-service</artifactId>
 
   <dependencies>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-messaging</artifactId>
       <groupId>io.micrometer</groupId>
       <artifactId>micrometer-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>io.cloudevents</groupId>
+      <artifactId>cloudevents-json-jackson</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.cloudevents</groupId>
+      <artifactId>cloudevents-kafka</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.cloudevents</groupId>
+      <artifactId>cloudevents-spring</artifactId>
+    </dependency>
     <dependency>
       <groupId>jakarta.validation</groupId>
       <artifactId>jakarta.validation-api</artifactId>
index b3f4227..f556f40 100644 (file)
@@ -3,7 +3,7 @@
  *  Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2021 Pantheon.tech
- *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+ *  Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
  *  Modifications Copyright (C) 2022 Deutsche Telekom AG
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,6 +39,8 @@ import org.onap.cps.api.CpsAnchorService;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.api.CpsDeltaService;
 import org.onap.cps.cpspath.parser.CpsPathUtil;
+import org.onap.cps.events.CpsDataUpdateEventsService;
+import org.onap.cps.events.model.Data.Operation;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.exceptions.DataValidationException;
@@ -61,7 +63,9 @@ public class CpsDataServiceImpl implements CpsDataService {
     private static final long DEFAULT_LOCK_TIMEOUT_IN_MILLISECONDS = 300L;
 
     private final CpsDataPersistenceService cpsDataPersistenceService;
+    private final CpsDataUpdateEventsService cpsDataUpdateEventsService;
     private final CpsAnchorService cpsAnchorService;
+
     private final CpsValidator cpsValidator;
     private final YangParser yangParser;
     private final CpsDeltaService cpsDeltaService;
@@ -81,6 +85,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
         final Collection<DataNode> dataNodes = buildDataNodes(anchor, ROOT_NODE_XPATH, nodeData, contentType);
         cpsDataPersistenceService.storeDataNodes(dataspaceName, anchorName, dataNodes);
+        sendDataUpdatedEvent(anchor, ROOT_NODE_XPATH, Operation.CREATE, observedTimestamp);
     }
 
     @Override
@@ -99,6 +104,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
         final Collection<DataNode> dataNodes = buildDataNodes(anchor, parentNodeXpath, nodeData, contentType);
         cpsDataPersistenceService.addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodes);
+        sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.CREATE, observedTimestamp);
     }
 
     @Override
@@ -116,6 +122,7 @@ public class CpsDataServiceImpl implements CpsDataService {
             cpsDataPersistenceService.addListElements(dataspaceName, anchorName, parentNodeXpath,
                                                       listElementDataNodeCollection);
         }
+        sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
     }
 
     @Override
@@ -151,6 +158,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final Map<String, Map<String, Serializable>> xpathToUpdatedLeaves = dataNodesInPatch.stream()
                 .collect(Collectors.toMap(DataNode::getXpath, DataNode::getLeaves));
         cpsDataPersistenceService.batchUpdateDataLeaves(dataspaceName, anchorName, xpathToUpdatedLeaves);
+        sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
     }
 
     @Override
@@ -167,6 +175,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         for (final DataNode dataNodeUpdate : dataNodeUpdates) {
             processDataNodeUpdate(anchor, dataNodeUpdate);
         }
+        sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
     }
 
     @Override
@@ -216,6 +225,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
         final Collection<DataNode> dataNodes = buildDataNodes(anchor, parentNodeXpath, jsonData, ContentType.JSON);
         cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes);
+        sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
     }
 
     @Override
@@ -228,6 +238,8 @@ public class CpsDataServiceImpl implements CpsDataService {
         final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
         final Collection<DataNode> dataNodes = buildDataNodes(anchor, nodesJsonData);
         cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes);
+        nodesJsonData.keySet().forEach(nodeXpath ->
+                sendDataUpdatedEvent(anchor, nodeXpath, Operation.UPDATE, observedTimestamp));
     }
 
     @Override
@@ -248,7 +260,9 @@ public class CpsDataServiceImpl implements CpsDataService {
     public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath,
             final Collection<DataNode> dataNodes, final OffsetDateTime observedTimestamp) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
+        final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
         cpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, parentNodeXpath, dataNodes);
+        sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
     }
 
     @Override
@@ -258,6 +272,8 @@ public class CpsDataServiceImpl implements CpsDataService {
                                final OffsetDateTime observedTimestamp) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
         cpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath);
+        final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
+        sendDataUpdatedEvent(anchor, dataNodeXpath, Operation.DELETE, observedTimestamp);
     }
 
     @Override
@@ -267,8 +283,12 @@ public class CpsDataServiceImpl implements CpsDataService {
                                 final Collection<String> dataNodeXpaths, final OffsetDateTime observedTimestamp) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
         cpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorName, dataNodeXpaths);
+        final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
+        dataNodeXpaths.forEach(dataNodeXpath ->
+                sendDataUpdatedEvent(anchor, dataNodeXpath, Operation.DELETE, observedTimestamp));
     }
 
+
     @Override
     @Timed(value = "cps.data.service.datanode.delete.anchor",
         description = "Time taken to delete all datanodes for an anchor")
@@ -276,6 +296,8 @@ public class CpsDataServiceImpl implements CpsDataService {
                                 final OffsetDateTime observedTimestamp) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
         cpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorName);
+        final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
+        sendDataUpdatedEvent(anchor, ROOT_NODE_XPATH, Operation.DELETE, observedTimestamp);
     }
 
     @Override
@@ -286,6 +308,9 @@ public class CpsDataServiceImpl implements CpsDataService {
         cpsValidator.validateNameCharacters(dataspaceName);
         cpsValidator.validateNameCharacters(anchorNames);
         cpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorNames);
+        for (final Anchor anchor : cpsAnchorService.getAnchors(dataspaceName, anchorNames)) {
+            sendDataUpdatedEvent(anchor, ROOT_NODE_XPATH, Operation.DELETE, observedTimestamp);
+        }
     }
 
     @Override
@@ -295,6 +320,8 @@ public class CpsDataServiceImpl implements CpsDataService {
         final OffsetDateTime observedTimestamp) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
         cpsDataPersistenceService.deleteListDataNode(dataspaceName, anchorName, listNodeXpath);
+        final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
+        sendDataUpdatedEvent(anchor, listNodeXpath, Operation.DELETE, observedTimestamp);
     }
 
     private Collection<DataNode> buildDataNodes(final Anchor anchor, final Map<String, String> nodesJsonData) {
@@ -345,4 +372,12 @@ public class CpsDataServiceImpl implements CpsDataService {
         }
     }
 
+    private void sendDataUpdatedEvent(final Anchor anchor, final String xpath,
+                                      final Operation operation, final OffsetDateTime observedTimestamp) {
+        try {
+            cpsDataUpdateEventsService.publishCpsDataUpdateEvent(anchor, xpath, operation, observedTimestamp);
+        } catch (final Exception exception) {
+            log.error("Failed to send message to notification service", exception);
+        }
+    }
 }
diff --git a/cps-service/src/main/java/org/onap/cps/events/CpsDataUpdateEventsService.java b/cps-service/src/main/java/org/onap/cps/events/CpsDataUpdateEventsService.java
new file mode 100644 (file)
index 0000000..e3315c9
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 TechMahindra Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.events;
+
+import io.cloudevents.CloudEvent;
+import io.micrometer.core.annotation.Timed;
+import java.time.OffsetDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.events.model.CpsDataUpdatedEvent;
+import org.onap.cps.events.model.Data;
+import org.onap.cps.events.model.Data.Operation;
+import org.onap.cps.spi.model.Anchor;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class CpsDataUpdateEventsService {
+
+    private final EventsPublisher<CpsDataUpdatedEvent> eventsPublisher;
+
+    @Value("${app.cps.data-updated.topic:cps-data-updated-events}")
+    private String topicName;
+
+    @Value("${notification.enabled:false}")
+    private boolean notificationsEnabled;
+
+    /**
+     * Publish the cps data update event with header to the public topic.
+     *
+     * @param anchor Anchor of the updated data
+     * @param xpath  xpath of the updated data
+     * @param operation operation performed on the data
+     * @param observedTimestamp timestamp when data was updated.
+     */
+    @Timed(value = "cps.dataupdate.events.publish", description = "Time taken to publish Data Update event")
+    public void publishCpsDataUpdateEvent(final Anchor anchor, final String xpath,
+                                          final Operation operation, final OffsetDateTime observedTimestamp) {
+        if (notificationsEnabled) {
+            final CpsDataUpdatedEvent cpsDataUpdatedEvent = createCpsDataUpdatedEvent(anchor,
+                    observedTimestamp, xpath, operation);
+            final String updateEventId = anchor.getDataspaceName() + ":" + anchor.getName();
+            final Map<String, String> extensions = createUpdateEventExtensions(updateEventId);
+            final CloudEvent cpsDataUpdatedEventAsCloudEvent =
+                    CpsEvent.builder().type(CpsDataUpdatedEvent.class.getTypeName()).data(cpsDataUpdatedEvent)
+                            .extensions(extensions).build().asCloudEvent();
+            eventsPublisher.publishCloudEvent(topicName, updateEventId, cpsDataUpdatedEventAsCloudEvent);
+        } else {
+            log.debug("Notifications disabled.");
+        }
+    }
+
+    private CpsDataUpdatedEvent createCpsDataUpdatedEvent(final Anchor anchor, final OffsetDateTime observedTimestamp,
+                                                          final String xpath,
+                                                          final Operation rootNodeOperation) {
+        final CpsDataUpdatedEvent cpsDataUpdatedEvent = new CpsDataUpdatedEvent();
+        final Data updateEventData = new Data();
+        updateEventData.setObservedTimestamp(observedTimestamp.toString());
+        updateEventData.setDataspaceName(anchor.getDataspaceName());
+        updateEventData.setAnchorName(anchor.getName());
+        updateEventData.setSchemaSetName(anchor.getSchemaSetName());
+        updateEventData.setOperation(getRootNodeOperation(xpath, rootNodeOperation));
+        updateEventData.setXpath(xpath);
+        cpsDataUpdatedEvent.setData(updateEventData);
+        return cpsDataUpdatedEvent;
+    }
+
+    private Map<String, String> createUpdateEventExtensions(final String eventKey) {
+        final Map<String, String> extensions = new HashMap<>();
+        extensions.put("correlationid", eventKey);
+        return extensions;
+    }
+
+    private Operation getRootNodeOperation(final String xpath, final Operation operation) {
+        return isRootXpath(xpath) || isRootContainerNodeXpath(xpath) ? operation : Operation.UPDATE;
+    }
+
+    private static boolean isRootXpath(final String xpath) {
+        return "/".equals(xpath) || "".equals(xpath);
+    }
+
+    private static boolean isRootContainerNodeXpath(final String xpath) {
+        return 0 == xpath.lastIndexOf('/');
+    }
+}
diff --git a/cps-service/src/main/java/org/onap/cps/events/CpsEvent.java b/cps-service/src/main/java/org/onap/cps/events/CpsEvent.java
new file mode 100644 (file)
index 0000000..c19abc1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 TechMahindra Ltd.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.events;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+import java.net.URI;
+import java.util.Map;
+import java.util.UUID;
+import lombok.Builder;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.utils.JsonObjectMapper;
+
+@Builder
+public class CpsEvent {
+
+    private Object data;
+    private Map<String, String> extensions;
+    private String type;
+    @Builder.Default
+    private static final String CLOUD_EVENT_SPEC_VERSION_V1 = "1.0.0";
+    @Builder.Default
+    private static final String CLOUD_EVENT_SOURCE = "CPS";
+
+    private final JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper());
+
+    /**
+     * Creates ncmp cloud event with provided attributes.
+     *
+     * @return Cloud Event
+     */
+
+    public CloudEvent asCloudEvent() {
+        final CloudEventBuilder cloudEventBuilder = io.cloudevents.core.builder
+            .CloudEventBuilder.v1()
+            .withId(UUID.randomUUID().toString())
+            .withSource(URI.create(CLOUD_EVENT_SOURCE))
+            .withType(type)
+            .withDataSchema(URI.create("urn:cps:" + type + ":" + CLOUD_EVENT_SPEC_VERSION_V1))
+            .withData(jsonObjectMapper.asJsonBytes(data));
+        extensions.entrySet().stream()
+            .filter(extensionEntry -> StringUtils.isNotBlank(extensionEntry.getValue()))
+            .forEach(extensionEntry ->
+                    cloudEventBuilder.withExtension(extensionEntry.getKey(), extensionEntry.getValue()));
+        return cloudEventBuilder.build();
+    }
+}
index b2b2d7d..fcbfd05 100644 (file)
@@ -3,7 +3,7 @@
  *  Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
- *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+ *  Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
  *  Modifications Copyright (C) 2022 Deutsche Telekom AG
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 package org.onap.cps.api.impl
 
+import ch.qos.logback.classic.Level
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.core.read.ListAppender
 import org.onap.cps.TestUtils
 import org.onap.cps.api.CpsAnchorService
 import org.onap.cps.api.CpsDeltaService
+import org.onap.cps.events.CpsDataUpdateEventsService
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.exceptions.ConcurrencyException
@@ -41,6 +45,8 @@ import org.onap.cps.utils.YangParser
 import org.onap.cps.utils.YangParserHelper
 import org.onap.cps.yang.YangTextSchemaSourceSet
 import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
+import org.slf4j.LoggerFactory
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
 import spock.lang.Shared
 import spock.lang.Specification
 import java.time.OffsetDateTime
@@ -52,13 +58,28 @@ class CpsDataServiceImplSpec extends Specification {
     def mockCpsValidator = Mock(CpsValidator)
     def yangParser = new YangParser(new YangParserHelper(), mockYangTextSchemaSourceSetCache)
     def mockCpsDeltaService = Mock(CpsDeltaService);
+    def mockDataUpdateEventsService = Mock(CpsDataUpdateEventsService)
 
-    def objectUnderTest = new CpsDataServiceImpl(mockCpsDataPersistenceService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)
+    def objectUnderTest = new CpsDataServiceImpl(mockCpsDataPersistenceService, mockDataUpdateEventsService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)
+
+    def logger = (Logger) LoggerFactory.getLogger(objectUnderTest.class)
+    def loggingListAppender
+    def applicationContext = new AnnotationConfigApplicationContext()
 
     def setup() {
         mockCpsAnchorService.getAnchor(dataspaceName, anchorName) >> anchor
         mockCpsAnchorService.getAnchor(dataspaceName, ANCHOR_NAME_1) >> anchor1
         mockCpsAnchorService.getAnchor(dataspaceName, ANCHOR_NAME_2) >> anchor2
+        logger.setLevel(Level.DEBUG)
+        loggingListAppender = new ListAppender()
+        logger.addAppender(loggingListAppender)
+        loggingListAppender.start()
+        applicationContext.refresh()
+    }
+
+    void cleanup() {
+        ((Logger) LoggerFactory.getLogger(CpsDataServiceImpl.class)).detachAndStopAllAppenders()
+        applicationContext.close()
     }
 
     @Shared
@@ -459,6 +480,19 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockCpsDataPersistenceService.lockAnchor('some-sessionId', 'some-dataspaceName', 'some-anchorName', 250L)
     }
 
+    def 'Exception is thrown while publishing the notification.'(){
+        given: 'schema set for given anchor and dataspace references test-tree model'
+            setupSchemaSetMocks('test-tree.yang')
+        when: 'publisher set to throw an exception'
+            mockDataUpdateEventsService.publishCpsDataUpdateEvent(_, _, _, _) >> { throw new Exception("publishing failed")}
+        and: 'an update event is performed'
+            objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, '/', '{"test-tree": {"branch": []}}', observedTimestamp)
+        then: 'the exception is not bubbled up'
+            noExceptionThrown()
+        and: "the exception message is logged"
+            def logs = loggingListAppender.list.toString()
+            assert logs.contains('Failed to send message to notification service')
+    }
     def setupSchemaSetMocks(String... yangResources) {
         def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet)
         mockYangTextSchemaSourceSetCache.get(dataspaceName, schemaSetName) >> mockYangTextSchemaSourceSet
index 140dfaa..57f2f8e 100755 (executable)
@@ -3,7 +3,7 @@
  * Copyright (C) 2021-2024 Nordix Foundation.\r
  * Modifications Copyright (C) 2021-2022 Bell Canada.\r
  * Modifications Copyright (C) 2021 Pantheon.tech\r
- * Modifications Copyright (C) 2022-2023 TechMahindra Ltd.\r
+ * Modifications Copyright (C) 2022-2024 TechMahindra Ltd.\r
  * ================================================================================\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -26,6 +26,7 @@ package org.onap.cps.api.impl
 import org.onap.cps.TestUtils\r
 import org.onap.cps.api.CpsAnchorService\r
 import org.onap.cps.api.CpsDeltaService\r
+import org.onap.cps.events.CpsDataUpdateEventsService\r
 import org.onap.cps.spi.CpsDataPersistenceService\r
 import org.onap.cps.spi.CpsModulePersistenceService\r
 import org.onap.cps.spi.model.Anchor\r
@@ -50,7 +51,8 @@ class E2ENetworkSliceSpec extends Specification {
     def cpsModuleServiceImpl = new CpsModuleServiceImpl(mockModuleStoreService,\r
             mockYangTextSchemaSourceSetCache, mockCpsAnchorService, mockCpsValidator,timedYangTextSchemaSourceSetBuilder)\r
 \r
-    def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)\r
+    def mockDataUpdateEventsService = Mock(CpsDataUpdateEventsService)\r
+    def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockDataUpdateEventsService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)\r
 \r
     def dataspaceName = 'someDataspace'\r
     def anchorName = 'someAnchor'\r
diff --git a/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy
new file mode 100644 (file)
index 0000000..81b2bf2
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 TechMahindra Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.events
+
+import static org.onap.cps.events.model.Data.Operation.CREATE
+import static org.onap.cps.events.model.Data.Operation.DELETE
+import static org.onap.cps.events.model.Data.Operation.UPDATE
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import io.cloudevents.CloudEvent
+import io.cloudevents.core.CloudEventUtils
+import io.cloudevents.jackson.PojoCloudEventDataMapper
+import org.onap.cps.events.model.CpsDataUpdatedEvent
+import org.onap.cps.events.model.Data
+import org.onap.cps.spi.model.Anchor
+import org.onap.cps.utils.JsonObjectMapper
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Specification
+
+import java.time.OffsetDateTime
+
+@ContextConfiguration(classes = [ObjectMapper, JsonObjectMapper])
+class CpsDataUpdateEventsServiceSpec extends Specification {
+    def mockEventsPublisher = Mock(EventsPublisher)
+    def notificationsEnabled = true
+    def objectMapper = new ObjectMapper();
+
+    def objectUnderTest = new CpsDataUpdateEventsService(mockEventsPublisher)
+
+    def 'Create and Publish cps update event where events are #scenario'() {
+        given: 'an anchor, operation and observed timestamp'
+            def anchor = new Anchor('anchor01', 'dataspace01', 'schema01');
+            def operation = operationInRequest
+            def observedTimestamp = OffsetDateTime.now()
+        and: 'notificationsEnabled is #notificationsEnabled and it will be true as default'
+            objectUnderTest.notificationsEnabled = true
+        when: 'service is called to publish data update event'
+            objectUnderTest.topicName = "cps-core-event"
+            objectUnderTest.publishCpsDataUpdateEvent(anchor, xpath, operation, observedTimestamp)
+        then: 'the event contains the required attributes'
+            1 * mockEventsPublisher.publishCloudEvent('cps-core-event', 'dataspace01:anchor01', _) >> {
+            args ->
+                {
+                    def cpsDataUpdatedEvent = (args[2] as CloudEvent)
+                    assert cpsDataUpdatedEvent.getExtension('correlationid') == 'dataspace01:anchor01'
+                    assert cpsDataUpdatedEvent.type == 'org.onap.cps.events.model.CpsDataUpdatedEvent'
+                    assert cpsDataUpdatedEvent.source.toString() == 'CPS'
+                    def actualEventOperation = CloudEventUtils.mapData(cpsDataUpdatedEvent, PojoCloudEventDataMapper.from(objectMapper, CpsDataUpdatedEvent.class)).getValue().data.operation
+                    assert actualEventOperation == expectedOperation
+                }
+            }
+        where: 'the following values are used'
+        scenario                                   | xpath        | operationInRequest  || expectedOperation
+        'empty xpath'                              | ''           | CREATE              || CREATE
+        'root xpath and create operation'          | '/'          | CREATE              || CREATE
+        'root xpath and update operation'          | '/'          | UPDATE              || UPDATE
+        'root xpath and delete operation'          | '/'          | DELETE              || DELETE
+        'not root xpath and update operation'      | 'test'       | UPDATE              || UPDATE
+        'root node xpath and create operation'     | '/test'      | CREATE              || CREATE
+        'non root node xpath and update operation' | '/test/path' | CREATE              || UPDATE
+        'non root node xpath and delete operation' | '/test/path' | DELETE              || UPDATE
+    }
+
+    def 'publish cps update event when notification service is disabled'() {
+        given: 'an anchor, operation and observed timestamp'
+            def anchor = new Anchor('anchor01', 'dataspace01', 'schema01');
+            def operation = CREATE
+            def observedTimestamp = OffsetDateTime.now()
+        and: 'notificationsEnabled is flase'
+            objectUnderTest.notificationsEnabled = false
+        when: 'service is called to publish data update event'
+            objectUnderTest.topicName = "cps-core-event"
+            objectUnderTest.publishCpsDataUpdateEvent(anchor, '/', operation, observedTimestamp)
+        then: 'the event contains the required attributes'
+            0 * mockEventsPublisher.publishCloudEvent('cps-core-event', 'dataspace01:anchor01', _)
+    }
+}
index bb7d3e5..1b110ed 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
     </parent>
 
     <artifactId>dmi-plugin-demo-and-csit-stub-app</artifactId>
index 288159c..43a47c6 100644 (file)
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
     </parent>
     <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId>
 
index d857645..61ae891 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 8a6c13e..4f5180d 100644 (file)
@@ -26,7 +26,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -190,7 +190,7 @@ components:
       content:
         application/json:
           example:
-            status: 400 BAD_REQUEST
+            status: 400
             message: Bad request error message
             details: Bad request error details
           schema:
index da0b0b3..9f6a1b2 100644 (file)
@@ -70,7 +70,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -216,7 +216,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -331,7 +331,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -449,7 +449,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -571,7 +571,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -615,7 +615,8 @@ paths:
     post:
       description: This request will be handled asynchronously using messaging to
         the supplied topic. The rest response will be an acknowledge with a requestId
-        to identify the relevant messages.
+        to identify the relevant messages. A maximum of 50 cm handles per operation
+        is supported.
       operationId: executeDataOperationForCmHandles
       parameters:
       - allowReserved: true
@@ -652,7 +653,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -668,6 +669,17 @@ paths:
               schema:
                 $ref: '#/components/schemas/ErrorMessage'
           description: Forbidden
+        "413":
+          content:
+            application/json:
+              example:
+                status: 413
+                message: Payload Too Large error message
+                details: Payload Too Large error details
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+          description: The request is larger than the server is willing or able to
+            process
         "500":
           content:
             application/json:
@@ -776,7 +788,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -843,7 +855,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -981,7 +993,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -1034,7 +1046,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -1087,7 +1099,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -1164,7 +1176,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -1227,7 +1239,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -1289,7 +1301,7 @@ paths:
           content:
             application/json:
               example:
-                status: 400 BAD_REQUEST
+                status: 400
                 message: Bad request error message
                 details: Bad request error details
               schema:
@@ -1603,7 +1615,7 @@ components:
       content:
         application/json:
           example:
-            status: 400 BAD_REQUEST
+            status: 400
             message: Bad request error message
             details: Bad request error details
           schema:
@@ -1662,6 +1674,16 @@ components:
           schema:
             $ref: '#/components/schemas/ErrorMessage'
       description: The specified resource was not found
+    PayloadTooLarge:
+      content:
+        application/json:
+          example:
+            status: 413
+            message: Payload Too Large error message
+            details: Payload Too Large error details
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+      description: The request is larger than the server is willing or able to process
   schemas:
     ErrorMessage:
       properties:
@@ -1743,6 +1765,8 @@ components:
           type: string
         targetIds:
           items:
+            description: "targeted cm handles, maximum of 50 supported. If this limit\
+              \ is exceeded the request wil be refused."
             example: "[\"da310eecdb8d44c2acc0ddaae01174b1\",\"c748c58f8e0b438f9fd1f28370b17d47\"\
               ]"
             type: string
index f04f977..c8f0690 100644 (file)
@@ -16,6 +16,33 @@ CPS Release Notes
 ..      * * *   NEW DELHI   * * *
 ..      =========================
 
+Version: 3.4.9
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project**                      |                                                        |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images**                    | onap/cps-and-ncmp:3.4.9                                |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation**              | 3.4.9 New Delhi                                        |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Release date**                     | Not yet released                                       |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.4.9
+
+Features
+--------
+
 Version: 3.4.8
 ==============
 
@@ -32,7 +59,7 @@ Release Data
 | **Release designation**              | 3.4.8 New Delhi                                        |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
-| **Release date**                     | Not yet released                                       |
+| **Release date**                     | 2024 May 1                                             |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
 
@@ -40,6 +67,8 @@ Bug Fixes
 ---------
 3.4.8
     - `CPS-2186 <https://jira.onap.org/browse/CPS-2186>`_ Report async task failures to client topic during data operations request
+    - `CPS-2190 <https://jira.onap.org/browse/CPS-2190>`_ Improve performance of NCMP module searches
+    - `CPS-2194 <https://jira.onap.org/browse/CPS-2194>`_ Added defaults for CPS and DMI username and password
 
 Features
 --------
index d4ee0cc..22d54a2 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index d8585fb..28c4280 100644 (file)
@@ -20,8 +20,6 @@
 
 package org.onap.cps.integration.functional
 
-import spock.lang.Ignore
-
 import java.time.Duration
 import org.onap.cps.integration.base.CpsIntegrationSpecBase
 import org.springframework.http.HttpHeaders
@@ -40,7 +38,6 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
 
-@Ignore
 class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
 
     static final MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
index 4e29149..a6b516c 100644 (file)
@@ -20,8 +20,6 @@
 
 package org.onap.cps.integration.functional
 
-import spock.lang.Ignore
-
 import java.time.Duration
 import java.time.OffsetDateTime
 import org.apache.kafka.common.TopicPartition
@@ -37,7 +35,6 @@ import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
 import org.onap.cps.ncmp.events.lcm.v1.LcmEvent
 import spock.util.concurrent.PollingConditions
 
-@Ignore
 class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
 
     NetworkCmProxyDataService objectUnderTest
index 68c354e..5421ad3 100644 (file)
@@ -28,13 +28,11 @@ import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
 import org.onap.cps.ncmp.api.models.UpgradedCmHandles
 import org.springframework.http.HttpStatus
-import spock.lang.Ignore
 import spock.util.concurrent.PollingConditions
 
 import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything
 import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
 
-@Ignore
 class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
 
     NetworkCmProxyDataService objectUnderTest
index 14b9f65..9129f09 100644 (file)
@@ -1,13 +1,10 @@
 package org.onap.cps.integration.functional
 
-import spock.lang.Ignore
-
 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
 import org.onap.cps.integration.base.CpsIntegrationSpecBase;
 import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService;
 import org.springframework.beans.factory.annotation.Autowired;
 
-@Ignore
 class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase {
 
     @Autowired
index 5e250b0..d7f8771 100644 (file)
@@ -22,7 +22,6 @@ package org.onap.cps.integration.functional
 
 import org.onap.cps.integration.base.CpsIntegrationSpecBase
 import org.springframework.http.MediaType
-import spock.lang.Ignore
 import spock.util.concurrent.PollingConditions
 import static org.hamcrest.Matchers.containsInAnyOrder
 import static org.hamcrest.Matchers.hasSize
@@ -31,7 +30,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
 
-@Ignore
 class NcmpRestApiSpec extends CpsIntegrationSpecBase {
 
     static final MODULE_REFERENCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
index 0c1e1f5..a4ee23a 100644 (file)
@@ -47,7 +47,7 @@ class CpsDataServiceLimitsPerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def durationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'the operation completes within 12 seconds'
-            recordAndAssertResourceUsage("Creating 33,000 books", 12, durationInSeconds, 150, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage("Creating 33,000 books", 16, durationInSeconds, 150, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Get data nodes from multiple xpaths 32K (2^15) limit exceeded.'() {
@@ -88,7 +88,7 @@ class CpsDataServiceLimitsPerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def durationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'test data is deleted in 1 second'
-            recordAndAssertResourceUsage("Deleting test data", 1, durationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage("Deleting test data", 0.1, durationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def countDataNodes() {
index 2efbf7d..f76c3c5 100644 (file)
@@ -56,7 +56,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Delete 100 containers', 2.5, deleteDurationInSeconds, 20, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Delete 100 containers', 2.2, deleteDurationInSeconds, 20, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 container nodes'() {
@@ -70,7 +70,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Batch delete 100 containers', 0.6, deleteDurationInSeconds, 2, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Batch delete 100 containers', 0.7, deleteDurationInSeconds, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 100 list elements'() {
@@ -86,7 +86,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Delete 100 lists elements', 2.5, deleteDurationInSeconds, 20, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Delete 100 lists elements', 2.1, deleteDurationInSeconds, 20, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 list elements'() {
@@ -100,7 +100,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Batch delete 100 lists elements', 0.6, deleteDurationInSeconds, 2, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Batch delete 100 lists elements', 0.7, deleteDurationInSeconds, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 100 whole lists'() {
@@ -116,7 +116,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Delete 100 whole lists', 6, deleteDurationInSeconds, 20, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Delete 100 whole lists', 4, deleteDurationInSeconds, 20, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 whole lists'() {
@@ -130,7 +130,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Batch delete 100 whole lists', 5, deleteDurationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Batch delete 100 whole lists', 3, deleteDurationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Delete 1 large data node'() {
@@ -160,7 +160,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Delete data nodes for anchor', 2, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Delete data nodes for anchor', 1.9, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Batch delete 100 non-existing nodes'() {
@@ -174,7 +174,7 @@ class DeletePerfTest extends CpsPerfTestBase {
             resourceMeter.stop()
             def deleteDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'delete duration is within expected time and memory used is within limit'
-            recordAndAssertResourceUsage('Batch delete 100 non-existing', 7, deleteDurationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage('Batch delete 100 non-existing', 1, deleteDurationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Clean up test data'() {
index 8a228a3..cb7680d 100644 (file)
@@ -44,9 +44,9 @@ class GetPerfTest extends CpsPerfTestBase {
             recordAndAssertResourceUsage("Read datatrees with ${scenario}", durationLimit, durationInSeconds, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
             scenario             | fetchDescendantsOption  || durationLimit | memoryLimit  | expectedNumberOfDataNodes
-            'no descendants'     | OMIT_DESCENDANTS        || 0.02          | 1            | 1
-            'direct descendants' | DIRECT_CHILDREN_ONLY    || 0.06          | 5            | 1 + OPENROADM_DEVICES_PER_ANCHOR
-            'all descendants'    | INCLUDE_ALL_DESCENDANTS || 2.5           | 250          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'no descendants'     | OMIT_DESCENDANTS        || 0.01          | 1            | 1
+            'direct descendants' | DIRECT_CHILDREN_ONLY    || 0.05          | 5            | 1 + OPENROADM_DEVICES_PER_ANCHOR
+            'all descendants'    | INCLUDE_ALL_DESCENDANTS || 1.2           | 250          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
     def 'Read data trees for multiple xpaths'() {
@@ -60,7 +60,7 @@ class GetPerfTest extends CpsPerfTestBase {
         then: 'requested nodes and their descendants are returned'
             assert countDataNodesInTree(result) == OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
         and: 'all data is read within expected time and memory used is within limit'
-            recordAndAssertResourceUsage("Read datatrees for multiple xpaths", 4 , durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage("Read datatrees for multiple xpaths", 1.8 , durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Read for multiple xpaths to non-existing datanodes'() {
@@ -74,7 +74,7 @@ class GetPerfTest extends CpsPerfTestBase {
         then: 'no data is returned'
             assert result.isEmpty()
         and: 'the operation completes within within expected time'
-            recordAndAssertResourceUsage("Read non-existing xpaths", 0.02, durationInSeconds, 2, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage("Read non-existing xpaths", 0.01, durationInSeconds, 2, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Read complete data trees using #scenario.'() {
@@ -88,9 +88,9 @@ class GetPerfTest extends CpsPerfTestBase {
             recordAndAssertResourceUsage("Read datatrees using ${scenario}", durationLimit, durationInSeconds, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following xpaths are used'
             scenario                | xpath                                  || durationLimit  | memoryLimit  | expectedNumberOfDataNodes
-            'openroadm root'        | '/'                                    || 2              | 250          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-            'openroadm top element' | '/openroadm-devices'                   || 2              | 250          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-            'openroadm whole list'  | '/openroadm-devices/openroadm-device'  || 3              | 250          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'openroadm root'        | '/'                                    || 1.0            | 250          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'openroadm top element' | '/openroadm-devices'                   || 1.0            | 250          | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'openroadm whole list'  | '/openroadm-devices/openroadm-device'  || 1.7            | 250          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
 }
index 0ae018d..7b9bf62 100644 (file)
@@ -45,11 +45,11 @@ class QueryPerfTest extends CpsPerfTestBase {
             recordAndAssertResourceUsage("Query 1 anchor ${scenario}", durationLimit, durationInSeconds, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
             scenario                     | cpsPath                                                             || durationLimit  | memoryLimit  | expectedNumberOfDataNodes
-            'top element'                | '/openroadm-devices'                                                || 2.5            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
-            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || 2.5            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
-            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || 2.5            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
-            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 2.5            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
-            'non-existing data'          | '/path/to/non-existing/node[@id="1"]'                               || 0.1            | 1            | 0
+            'top element'                | '/openroadm-devices'                                                || 1.1            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || 1.1            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || 1.1            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 1.1            | 400          | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+            'non-existing data'          | '/path/to/non-existing/node[@id="1"]'                               || 0.009          | 1            | 0
     }
 
     def 'Query complete data trees across all anchors with #scenario.'() {
@@ -64,10 +64,10 @@ class QueryPerfTest extends CpsPerfTestBase {
             recordAndAssertResourceUsage("Query across anchors ${scenario}", durationLimit, durationInSeconds, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
             scenario                     | cpspath                                                             || durationLimit  | memoryLimit   | expectedNumberOfDataNodes
-            'top element'                | '/openroadm-devices'                                                || 7              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
-            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || 7              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE)
-            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || 7              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
-            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 7              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+            'top element'                | '/openroadm-devices'                                                || 3              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+            'leaf condition'             | '//openroadm-device[@ne-state="inservice"]'                         || 3              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE)
+            'ancestors'                  | '//openroadm-device/ancestor::openroadm-devices'                    || 3              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+            'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 3              | 600           | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
     }
 
     def 'Query with leaf condition and #scenario.'() {
@@ -83,8 +83,8 @@ class QueryPerfTest extends CpsPerfTestBase {
         where: 'the following parameters are used'
             scenario             | fetchDescendantsOption  || durationLimit  | memoryLimit   | expectedNumberOfDataNodes
             'no descendants'     | OMIT_DESCENDANTS        || 0.1            | 6             | OPENROADM_DEVICES_PER_ANCHOR
-            'direct descendants' | DIRECT_CHILDREN_ONLY    || 0.2            | 12            | OPENROADM_DEVICES_PER_ANCHOR * 2
-            'all descendants'    | INCLUDE_ALL_DESCENDANTS || 2.5            | 200           | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'direct descendants' | DIRECT_CHILDREN_ONLY    || 0.1            | 12            | OPENROADM_DEVICES_PER_ANCHOR * 2
+            'all descendants'    | INCLUDE_ALL_DESCENDANTS || 1.1            | 200           | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
     def 'Query ancestors with #scenario.'() {
@@ -99,9 +99,9 @@ class QueryPerfTest extends CpsPerfTestBase {
             recordAndAssertResourceUsage("Query ancestors with ${scenario}", durationLimit, durationInSeconds, memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where: 'the following parameters are used'
             scenario             | fetchDescendantsOption  || durationLimit  | memoryLimit | expectedNumberOfDataNodes
-            'no descendants'     | OMIT_DESCENDANTS        || 0.           | 3           | 1
-            'direct descendants' | DIRECT_CHILDREN_ONLY    || 0.2            | 8           | 1 + OPENROADM_DEVICES_PER_ANCHOR
-            'all descendants'    | INCLUDE_ALL_DESCENDANTS || 2.5            | 400         | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+            'no descendants'     | OMIT_DESCENDANTS        || 0.08           | 3           | 1
+            'direct descendants' | DIRECT_CHILDREN_ONLY    || 0.1            | 8           | 1 + OPENROADM_DEVICES_PER_ANCHOR
+            'all descendants'    | INCLUDE_ALL_DESCENDANTS || 1.1            | 400         | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
     }
 
 }
index 69f6477..360feca 100644 (file)
@@ -78,13 +78,13 @@ class UpdatePerfTest extends CpsPerfTestBase {
                     timeLimit, resourceMeter.getTotalTimeInSeconds(),
                     memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where:
-            scenario                           | totalNodes | startId | changeLeaves || timeLimit | memoryLimit
-            'Replace 0 nodes with 100'         | 100        | 1       | false        ||       2.5 | 200
-            'Replace 100 using same data'      | 100        | 1       | false        ||       3.0 | 200
-            'Replace 100 with new leaf values' | 100        | 1       | true         ||       3.0 | 200
-            'Replace 100 with 100 new nodes'   | 100        | 101     | false        ||       6.0 | 200
-            'Replace 50 existing and 50 new'   | 100        | 151     | true         ||       4.5 | 200
-            'Replace 100 nodes with 0'         | 0          | 1       | false        ||       3.0 | 200
+            scenario                           | totalNodes | startId | changeLeaves || timeLimit  | memoryLimit
+            'Replace 0 nodes with 100'         | 100        | 1       | false        ||       3.2  | 200
+            'Replace 100 using same data'      | 100        | 1       | false        ||       5.6  | 200
+            'Replace 100 with new leaf values' | 100        | 1       | true         ||       5.5  | 200
+            'Replace 100 with 100 new nodes'   | 100        | 101     | false        ||       10.0 | 200
+            'Replace 50 existing and 50 new'   | 100        | 151     | true         ||       8.0  | 200
+            'Replace 100 nodes with 0'         | 0          | 1       | false        ||       7.0  | 200
     }
 
     def 'Replace list content: #scenario.'() {
@@ -105,12 +105,12 @@ class UpdatePerfTest extends CpsPerfTestBase {
                     memoryLimit, resourceMeter.getTotalMemoryUsageInMB())
         where:
             scenario                                   | totalNodes | startId | changeLeaves || timeLimit | memoryLimit
-            'Replace list of 0 with 100'               | 100        | 1       | false        ||       2.5 | 200
-            'Replace list of 100 using same data'      | 100        | 1       | false        ||       3.0 | 200
-            'Replace list of 100 with new leaf values' | 100        | 1       | true         ||       3.0 | 200
-            'Replace list with 100 new nodes'          | 100        | 101     | false        ||       6.0 | 200
-            'Replace list with 50 existing and 50 new' | 100        | 151     | true         ||       4.5 | 200
-            'Replace list of 100 nodes with 1'         | 1          | 1       | false        ||       3.0 | 200
+            'Replace list of 0 with 100'               | 100        | 1       | false        ||       3.0 | 200
+            'Replace list of 100 using same data'      | 100        | 1       | false        ||       5.4 | 200
+            'Replace list of 100 with new leaf values' | 100        | 1       | true         ||       5.6 | 200
+            'Replace list with 100 new nodes'          | 100        | 101     | false        ||       9.9 | 200
+            'Replace list with 50 existing and 50 new' | 100        | 151     | true         ||       8.0 | 200
+            'Replace list of 100 nodes with 1'         | 1          | 1       | false        ||       7.0 | 200
     }
 
     def 'Update leaves for 100 data nodes.'() {
@@ -127,7 +127,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
             assert 100 == countDataNodes('/openroadm-devices/openroadm-device[@status="fail"]')
         and: 'update completes within expected time and memory used is within limit'
             recordAndAssertResourceUsage('Update leaves for 100 data nodes',
-                    0.4, resourceMeter.getTotalTimeInSeconds(),
+                    0.3, resourceMeter.getTotalTimeInSeconds(),
                     120, resourceMeter.getTotalMemoryUsageInMB())
     }
 
index 96f85ff..c3dd2af 100644 (file)
@@ -44,10 +44,10 @@ class WritePerfTest extends CpsPerfTestBase {
             cpsAnchorService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, WRITE_TEST_ANCHOR)
         where:
             totalNodes || expectedDuration | memoryLimit
-            50         || 2                | 100
-            100        || 4                | 200
-            200        || 7                | 400
-            400        || 14               | 500
+            50         || 1.6              | 100
+            100        || 3.3              | 200
+            200        || 6.8              | 400
+            400        || 13.0             | 500
     }
 
     def 'Writing bookstore data has exponential time.'() {
@@ -69,10 +69,10 @@ class WritePerfTest extends CpsPerfTestBase {
             cpsAnchorService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, WRITE_TEST_ANCHOR)
         where:
             totalBooks || expectedDuration | memoryLimit
-            800        || 0.5              | 50
-            1600       || 1.5              | 100
-            3200       || 6.0              | 150
-            6400       || 18.0             | 200
+            800        || 0.3              | 50
+            1600       || 0.8              | 100
+            3200       || 2.6              | 150
+            6400       || 6.7              | 200
     }
 
     def 'Writing openroadm list data using saveListElements.'() {
@@ -97,10 +97,10 @@ class WritePerfTest extends CpsPerfTestBase {
             cpsAnchorService.deleteAnchor(CPS_PERFORMANCE_TEST_DATASPACE, WRITE_TEST_ANCHOR)
         where:
             totalNodes || expectedDuration | memoryLimit
-            50         || 2                | 100
-            100        || 4                | 200
-            200        || 7                | 400
-            400        || 14               | 500
+            50         || 1.5              | 100
+            100        || 3.0              | 200
+            200        || 6.3              | 400
+            400        || 14.0             | 500
     }
 
 }
index 579394b..53b2194 100644 (file)
@@ -95,7 +95,7 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
             def resultAfter = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
             assert resultAfter.collect {it.leaves.subscribers.size()}.sum() == totalNumberOfEntries * (1 + numberOfCmDataSubscribers)
         and: 'update matching subscription within 15 seconds'
-            recordAndAssertResourceUsage("Update matching subscription", 15, durationInSeconds, 1000, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage("Update matching subscription", 11, durationInSeconds, 1000, resourceMeter.getTotalMemoryUsageInMB())
     }
 
     def 'Worst case new subscription (200x10 new entries).'() {
index d95ac73..91b28f9 100644 (file)
 
 package org.onap.cps.integration.performance.ncmp
 
-import org.apache.commons.lang3.StringUtils
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncService
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter
-import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.spi.model.DataNode
-import org.springframework.beans.factory.annotation.Autowired
 
-import java.util.stream.Collectors
 import org.onap.cps.api.CpsQueryService
 import org.onap.cps.integration.ResourceMeter
 import org.onap.cps.integration.performance.base.NcmpPerfTestBase
 
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+import java.util.stream.Collectors
+
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 
 class CmHandleQueryPerfTest extends NcmpPerfTestBase {
 
@@ -74,7 +68,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase {
             resourceMeter.stop()
             def durationInSeconds = resourceMeter.getTotalTimeInSeconds()
         then: 'the required operations are performed within required time'
-            recordAndAssertResourceUsage("CpsPath Registry attributes Query", 2, durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
+            recordAndAssertResourceUsage("CpsPath Registry attributes Query", 3.4, durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
         and: 'all nodes are returned'
             result.size() == TOTAL_CM_HANDLES
         and: 'the tree contains all the expected descendants too'
@@ -98,7 +92,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase {
                     expectedAverageResponseTime, averageResponseTime,
                     15, resourceMeter.totalMemoryUsageInMB)
         where:
-            expectedAverageResponseTime = 1 * MILLISECONDS
+            expectedAverageResponseTime = 6 * MILLISECONDS
     }
 
     def 'CM-handle is looked up by alternate-id.'() {
@@ -118,7 +112,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase {
                     expectedAverageResponseTime, averageResponseTime,
                     15, resourceMeter.totalMemoryUsageInMB)
         where:
-            expectedAverageResponseTime = 10 * MILLISECONDS
+            expectedAverageResponseTime = 20 * MILLISECONDS
     }
 
     def 'A batch of CM-handles is looked up by alternate-id.'() {
@@ -157,7 +151,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase {
                     expectedAverageResponseTime, averageResponseTime,
                     500, resourceMeter.totalMemoryUsageInMB)
         where:
-            expectedAverageResponseTime = 100 * MILLISECONDS
+            expectedAverageResponseTime = 360 * MILLISECONDS
     }
 
 }
index 407210f..6fd3bca 100644 (file)
@@ -169,7 +169,6 @@ ncmp:
       maximumConnectionsPerRoute: 50
       maximumConnectionsTotal: 100
       idleConnectionEvictionThresholdInSeconds: 5
-      maximumInMemorySizeInMegabytes: 16
     auth:
       username: dmi
       password: dmi
index 9919e8c..585d45b 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.4.8-SNAPSHOT</version>
+        <version>3.4.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/pom.xml b/pom.xml
index df89d96..767c230 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
 \r
     <groupId>org.onap.cps</groupId>\r
     <artifactId>cps-aggregator</artifactId>\r
-    <version>3.4.8-SNAPSHOT</version>\r
+    <version>3.4.9-SNAPSHOT</version>\r
     <packaging>pom</packaging>\r
 \r
     <name>cps</name>\r
diff --git a/releases/3.4.8-container.yaml b/releases/3.4.8-container.yaml
new file mode 100644 (file)
index 0000000..c5cccb4
--- /dev/null
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.4.8
+project: cps
+log_dir: cps-maven-docker-stage-master/940/
+ref: ad46c250eebd2eec9a99991371f825c778336182
+containers:
+  - name: 'cps-and-ncmp'
+    version: '3.4.8-20240501T114419Z'
diff --git a/releases/3.4.8.yaml b/releases/3.4.8.yaml
new file mode 100644 (file)
index 0000000..a711ff7
--- /dev/null
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/948/
+project: cps
+version: 3.4.8
index 02c6079..7c93d55 100644 (file)
@@ -25,7 +25,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>spotbugs</artifactId>
-    <version>3.4.8-SNAPSHOT</version>
+    <version>3.4.9-SNAPSHOT</version>
 
     <properties>
         <nexusproxy>https://nexus.onap.org</nexusproxy>
index 767a534..edba7cf 100644 (file)
@@ -22,7 +22,7 @@
 
 major=3
 minor=4
-patch=8
+patch=9
 
 base_version=${major}.${minor}.${patch}