aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xINFO.yaml2
-rw-r--r--checkstyle/pom.xml2
-rw-r--r--cps-application/pom.xml2
-rw-r--r--cps-application/src/main/resources/application.yml16
-rw-r--r--cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java5
-rw-r--r--cps-bom/pom.xml2
-rw-r--r--cps-dependencies/pom.xml8
-rw-r--r--cps-events/pom.xml2
-rw-r--r--cps-events/src/main/resources/schemas/updatenode/cps-data-updated-event-schema-1.0.0.json2
-rw-r--r--cps-ncmp-events/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/pom.xml2
-rw-r--r--cps-ncmp-rest/pom.xml2
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java5
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy22
-rw-r--r--cps-ncmp-service/pom.xml6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java38
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java82
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java16
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java70
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java78
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java9
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java11
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java)26
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java)21
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java58
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java39
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java28
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java35
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java12
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy56
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy62
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy11
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy1
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy12
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy58
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy64
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy6
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy54
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy54
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy28
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy16
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy7
-rw-r--r--cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json2
-rw-r--r--cps-parent/pom.xml2
-rw-r--r--cps-path-parser/pom.xml2
-rw-r--r--cps-rest/pom.xml2
-rw-r--r--cps-rest/src/test/java/org/onap/cps/utils/DateTimeUtility.java6
-rw-r--r--cps-ri/pom.xml2
-rw-r--r--cps-service/pom.xml18
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java37
-rw-r--r--cps-service/src/main/java/org/onap/cps/events/CpsDataUpdateEventsService.java113
-rw-r--r--cps-service/src/main/java/org/onap/cps/events/CpsEvent.java66
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/DateTimeUtility.java (renamed from cps-service/src/test/java/org/onap/cps/utils/DateTimeUtility.java)9
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy38
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy6
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy121
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml2
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml2
-rw-r--r--dmi-plugin-demo-and-csit-stub/pom.xml2
-rw-r--r--docs/api/swagger/ncmp/openapi-inventory.yaml4
-rw-r--r--docs/api/swagger/ncmp/openapi.yaml56
-rw-r--r--docs/release-notes.rst60
-rw-r--r--integration-test/pom.xml41
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy55
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy105
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy70
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy38
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy60
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy23
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy31
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy16
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy24
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy14
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy28
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy30
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy24
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy6
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy53
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy22
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/moduleReferencesTemplate.json4
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/moduleResourcesTemplate.json5
-rw-r--r--integration-test/src/test/resources/data/ncmp-registry/innerCmHandleNode.json24
-rw-r--r--jacoco-report/pom.xml2
-rw-r--r--pom.xml2
-rw-r--r--releases/3.4.8-container.yaml8
-rw-r--r--releases/3.4.8.yaml4
-rw-r--r--releases/3.4.9-container.yaml8
-rw-r--r--releases/3.4.9.yaml4
-rw-r--r--spotbugs/pom.xml2
-rw-r--r--version.properties4
105 files changed, 1678 insertions, 702 deletions
diff --git a/INFO.yaml b/INFO.yaml
index fe96ba8f1..eee6540a5 100755
--- a/INFO.yaml
+++ b/INFO.yaml
@@ -19,7 +19,7 @@
---
project: 'cps'
project_creation_date: '2020-10-27'
-lifecycle_state: 'Incubation'
+lifecycle_state: 'Mature'
project_category: ''
project_lead: &onap_releng_ptl
name: 'Toine Siebelink'
diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml
index b1c4379ee..9ecfa2d32 100644
--- a/checkstyle/pom.xml
+++ b/checkstyle/pom.xml
@@ -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.5.0-SNAPSHOT</version>
<profiles>
<profile>
diff --git a/cps-application/pom.xml b/cps-application/pom.xml
index e6e2f9a2a..6804c7de6 100644
--- a/cps-application/pom.xml
+++ b/cps-application/pom.xml
@@ -28,7 +28,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml
index 27bc6c618..810068081 100644
--- a/cps-application/src/main/resources/application.yml
+++ b/cps-application/src/main/resources/application.yml
@@ -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,6 +114,11 @@ app:
topic: ${DMI_CM_EVENTS_TOPIC:dmi-cm-events}
device-heartbeat:
topic: ${DMI_DEVICE_HEARTBEAT_TOPIC:dmi-device-heartbeat}
+ cps:
+ data-updated:
+ change-event-notifications-enabled: ${CPS_CHANGE_EVENT_NOTIFICATIONS_ENABLED:true}
+ topic: ${CPS_CHANGE_EVENT_TOPIC:cps-data-updated-events}
+
notification:
@@ -138,14 +144,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:
@@ -175,8 +179,8 @@ ncmp:
maximumConnectionsTotal: 100
idleConnectionEvictionThresholdInSeconds: 5
auth:
- username: ${DMI_USERNAME}
- password: ${DMI_PASSWORD}
+ username: ${DMI_USERNAME:cpsuser}
+ password: ${DMI_PASSWORD:cpsr0cks!}
enabled: ${DMI_AUTH_ENABLED:true}
api:
base-path: dmi
diff --git a/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java b/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java
index ec16ceefe..c18a3ed10 100644
--- a/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java
+++ b/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nordix Foundation
+ * Copyright (C) 2021-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.
@@ -45,6 +45,7 @@ public class LayeredArchitectureTest {
private static final String CPS_UTILS_PACKAGE = "org.onap.cps.utils..";
private static final String NCMP_INIT_PACKAGE = "org.onap.cps.ncmp.init..";
private static final String CPS_CACHE_PACKAGE = "org.onap.cps.cache..";
+ private static final String CPS_EVENTS_PACKAGE = "org.onap.cps.events..";
@ArchTest
static final ArchRule restControllerShouldOnlyDependOnRestController =
@@ -57,7 +58,7 @@ public class LayeredArchitectureTest {
.or().resideInAPackage(SPI_SERVICE_PACKAGE).should().onlyHaveDependentClassesThat()
.resideInAnyPackage(REST_CONTROLLER_PACKAGE, API_SERVICE_PACKAGE, SPI_SERVICE_PACKAGE, NCMP_REST_PACKAGE,
NCMP_SERVICE_PACKAGE, YANG_SCHEMA_PACKAGE, NOTIFICATION_PACKAGE, CPS_UTILS_PACKAGE, NCMP_INIT_PACKAGE,
- CPS_CACHE_PACKAGE));
+ CPS_CACHE_PACKAGE, CPS_EVENTS_PACKAGE));
@ArchTest
diff --git a/cps-bom/pom.xml b/cps-bom/pom.xml
index 366d4c72f..4548eb21c 100644
--- a/cps-bom/pom.xml
+++ b/cps-bom/pom.xml
@@ -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.5.0-SNAPSHOT</version>
<packaging>pom</packaging>
<description>This artifact contains dependencyManagement declarations of all published CPS components.</description>
diff --git a/cps-dependencies/pom.xml b/cps-dependencies/pom.xml
index b7ec70b33..effaa06f6 100644
--- a/cps-dependencies/pom.xml
+++ b/cps-dependencies/pom.xml
@@ -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.5.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>${project.groupId}:${project.artifactId}</name>
@@ -143,6 +143,12 @@
<version>5.3.1</version>
</dependency>
<dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <version>4.12.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>1.2.0</version>
diff --git a/cps-events/pom.xml b/cps-events/pom.xml
index 680d0bbad..ec0c96bc2 100644
--- a/cps-events/pom.xml
+++ b/cps-events/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-events/src/main/resources/schemas/updatenode/cps-data-updated-event-schema-1.0.0.json b/cps-events/src/main/resources/schemas/updatenode/cps-data-updated-event-schema-1.0.0.json
index 18f83ccf8..a3eaf63fa 100644
--- a/cps-events/src/main/resources/schemas/updatenode/cps-data-updated-event-schema-1.0.0.json
+++ b/cps-events/src/main/resources/schemas/updatenode/cps-data-updated-event-schema-1.0.0.json
@@ -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": {
diff --git a/cps-ncmp-events/pom.xml b/cps-ncmp-events/pom.xml
index e12ab3bba..3804e5bd2 100644
--- a/cps-ncmp-events/pom.xml
+++ b/cps-ncmp-events/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
index ae755a314..7b277cdb3 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-ncmp-rest-stub</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
</parent>
<artifactId>cps-ncmp-rest-stub-app</artifactId>
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
index b6c461c6d..cb655320f 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-ncmp-rest-stub</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
</parent>
<artifactId>cps-ncmp-rest-stub-service</artifactId>
diff --git a/cps-ncmp-rest-stub/pom.xml b/cps-ncmp-rest-stub/pom.xml
index c2c789e5b..441ce43f4 100644
--- a/cps-ncmp-rest-stub/pom.xml
+++ b/cps-ncmp-rest-stub/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml
index 453da8fea..e33334479 100644
--- a/cps-ncmp-rest/pom.xml
+++ b/cps-ncmp-rest/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
index 453abcabb..5467eeffc 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
@@ -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(
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
index 1d03be107..7b850a7ff 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
@@ -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.'() {
diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml
index 04864c458..fc41da3ae 100644
--- a/cps-ncmp-service/pom.xml
+++ b/cps-ncmp-service/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-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>
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
index 6df0e4994..798a280c8 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
@@ -22,29 +22,28 @@
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
index 4f9e8800d..000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
+++ /dev/null
@@ -1,82 +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;
-
- @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))
- .build();
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
index 729930e65..d547e31c6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
@@ -1,4 +1,4 @@
-/*-
+/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023 Nordix Foundation.
* ================================================================================
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
index 32852b326..c6ff116a7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
@@ -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
index 000000000..50a5df537
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java
@@ -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
index 000000000..73f9563ec
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java
@@ -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);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java
index b2c0a5cfb..f7dd51e63 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java
@@ -20,14 +20,13 @@
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);
}
-
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java
index 34ffb5e19..b5370bf1e 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java
@@ -122,10 +122,13 @@ public class DmiCmNotificationSubscriptionCacheHandler {
* @param status String of status
*
*/
- public void updateDmiCmNotificationSubscriptionStatusPerDmi(
- final String subscriptionId, final String dmiServiceName, final CmNotificationSubscriptionStatus status) {
- cmNotificationSubscriptionCache.get(subscriptionId).get(dmiServiceName)
- .setCmNotificationSubscriptionStatus(status);
+ public void updateDmiCmNotificationSubscriptionStatusPerDmi(final String subscriptionId,
+ final String dmiServiceName, final CmNotificationSubscriptionStatus status) {
+ final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi =
+ cmNotificationSubscriptionCache.get(subscriptionId);
+ dmiCmNotificationSubscriptionDetailsPerDmi.get(dmiServiceName).setCmNotificationSubscriptionStatus(status);
+ cmNotificationSubscriptionCache.put(subscriptionId, dmiCmNotificationSubscriptionDetailsPerDmi);
+
}
/**
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java
index 82ae5467e..fb89aae3f 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java
@@ -18,16 +18,22 @@
* ============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;
import io.cloudevents.CloudEvent;
+import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
+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.model.CmNotificationSubscriptionStatus;
+import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent;
+import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
@@ -37,6 +43,8 @@ import org.springframework.stereotype.Component;
public class CmNotificationSubscriptionDmiOutEventConsumer {
private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
+ private final CmNotificationSubscriptionEventsHandler cmNotificationSubscriptionEventsHandler;
+ private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
/**
* Consume the Cm Notification Subscription event from the dmi-plugin.
@@ -65,10 +73,12 @@ public class CmNotificationSubscriptionDmiOutEventConsumer {
if ("ACCEPTED".equals(cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage())) {
handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmNotificationSubscriptionStatus.ACCEPTED);
dmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName);
+ handleEventsStatusPerDmi(subscriptionId);
}
if ("REJECTED".equals(cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage())) {
handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmNotificationSubscriptionStatus.REJECTED);
+ handleEventsStatusPerDmi(subscriptionId);
}
log.info("Cm Subscription with id : {} handled by the dmi-plugin : {} has the status : {}", subscriptionId,
@@ -76,8 +86,18 @@ public class CmNotificationSubscriptionDmiOutEventConsumer {
}
private void handleCacheStatusPerDmi(final String subscriptionId, final String dmiPluginName,
- final CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus) {
+ final CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus) {
dmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi(subscriptionId,
- dmiPluginName, cmNotificationSubscriptionStatus);
+ dmiPluginName, cmNotificationSubscriptionStatus);
+ }
+
+ private void handleEventsStatusPerDmi(final String subscriptionId) {
+ final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi =
+ dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId);
+ final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
+ cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+ dmiCmNotificationSubscriptionDetailsPerDmi);
+ cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+ "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java
index 377e15531..70135b307 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java
@@ -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;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java
index 5c192a953..9fbe26848 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java
@@ -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;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java
index e7af69e50..ac5de07f0 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java
@@ -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) {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java
index 8204f05c9..7872ba0a3 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java
@@ -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,33 +43,56 @@ 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);
+ scheduleCmNotificationSubscriptionNcmpOutEventResponse(subscriptionId);
} else {
- final Set<String> subscriptionTargetFilters = predicates.stream().flatMap(
- predicate -> predicate.getTargetFilter().stream()).collect(Collectors.toSet());
rejectAndPublishCmNotificationSubscriptionCreateRequest(subscriptionId,
- new ArrayList<>(subscriptionTargetFilters));
+ predicates);
}
}
+ private void scheduleCmNotificationSubscriptionNcmpOutEventResponse(final String subscriptionId) {
+ cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
+ "subscriptionCreateResponse", null, true);
+ }
+
private void rejectAndPublishCmNotificationSubscriptionCreateRequest(final String subscriptionId,
- final List<String> subscriptionTargetFilters) {
+ final List<Predicate> predicates) {
+ final Set<String> subscriptionTargetFilters =
+ predicates.stream().flatMap(predicate -> predicate.getTargetFilter().stream())
+ .collect(Collectors.toSet());
final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
- cmNotificationSubscriptionNcmpOutEventMapper
- .toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(subscriptionId,
- subscriptionTargetFilters);
- cmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false);
+ cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
+ subscriptionId, new ArrayList<>(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
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java
new file mode 100644
index 000000000..2e6cd3308
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java
@@ -0,0 +1,39 @@
+/*
+ * ============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.exception;
+
+import java.io.Serial;
+
+public class NoAlternateIdParentFoundException extends NcmpException {
+
+ @Serial
+ private static final long serialVersionUID = -2412915490233422945L;
+ private static final String ALTERNATE_ID_NOT_FOUND = "No matching (parent) cm handle found using alternate ids";
+
+ /**
+ * Constructor.
+ *
+ * @param cpsPath datanode cpsPath
+ */
+ public NoAlternateIdParentFoundException(final String cpsPath) {
+ super(ALTERNATE_ID_NOT_FOUND, String.format("cannot find a datanode with alternate id %s", cpsPath));
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
index e230b3fcb..184b12570 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
@@ -130,6 +130,16 @@ public interface InventoryPersistence extends NcmpPersistence {
DataNode getCmHandleDataNodeByAlternateId(String alternateId);
/**
+ * Get data node that matches longest alternate id by removing elements (as defined by the separator string)
+ * from right to left.
+ *
+ * @param alternateId alternate ID
+ * @param separator a string that separates each element from the next.
+ * @return data node
+ */
+ DataNode getCmHandleDataNodeByLongestMatchAlternateId(final String alternateId, final String separator);
+
+ /**
* Get collection of data nodes of given cm handles.
*
* @param cmHandleIds collection of cmHandle IDs
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
index 3ae3dd911..bf54fe5d9 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
@@ -33,9 +33,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsModuleService;
+import org.onap.cps.ncmp.api.impl.exception.NoAlternateIdParentFoundException;
import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.spi.FetchDescendantsOption;
@@ -169,17 +171,30 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
@Override
public DataNode getCmHandleDataNodeByAlternateId(final String alternateId) {
- final String xPathForCmHandleByAlternateId = getXPathForCmHandleByAlternateId(alternateId);
+ final String cpsPathForCmHandleByAlternateId = getCpsPathForCmHandleByAlternateId(alternateId);
final Collection<DataNode> dataNodes = cmHandleQueries
- .queryNcmpRegistryByCpsPath(xPathForCmHandleByAlternateId, OMIT_DESCENDANTS);
+ .queryNcmpRegistryByCpsPath(cpsPathForCmHandleByAlternateId, OMIT_DESCENDANTS);
if (dataNodes.isEmpty()) {
throw new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- xPathForCmHandleByAlternateId);
+ cpsPathForCmHandleByAlternateId);
}
return dataNodes.iterator().next();
}
@Override
+ public DataNode getCmHandleDataNodeByLongestMatchAlternateId(final String alternateId, final String separator) {
+ String bestMatch = alternateId;
+ while (StringUtils.isNotEmpty(bestMatch)) {
+ try {
+ return getCmHandleDataNodeByAlternateId(bestMatch);
+ } catch (final DataNodeNotFoundException ignored) {
+ bestMatch = getParentPath(bestMatch, separator);
+ }
+ }
+ throw new NoAlternateIdParentFoundException(alternateId);
+ }
+
+ @Override
public Collection<DataNode> getCmHandleDataNodes(final Collection<String> cmHandleIds) {
final Collection<String> xpaths = new ArrayList<>(cmHandleIds.size());
cmHandleIds.forEach(cmHandleId -> xpaths.add(getXPathForCmHandleById(cmHandleId)));
@@ -195,7 +210,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']";
}
- private static String getXPathForCmHandleByAlternateId(final String alternateId) {
+ private static String getCpsPathForCmHandleByAlternateId(final String alternateId) {
return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@alternate-id='" + alternateId + "']";
}
@@ -206,4 +221,9 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
private String createCmHandlesJsonData(final List<YangModelCmHandle> yangModelCmHandles) {
return "{\"cm-handles\":" + jsonObjectMapper.asJsonString(yangModelCmHandles) + "}";
}
+
+ private static String getParentPath(final String path, final String separator) {
+ final int lastSeparatorIndex = path.lastIndexOf(separator);
+ return lastSeparatorIndex < 0 ? "" : path.substring(0, lastSeparatorIndex);
+ }
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
index cac25c845..a9ec1241b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
@@ -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) -> {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
index c71da1cd1..798f6de81 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
@@ -24,7 +24,9 @@ package org.onap.cps.ncmp.api.impl.operations;
import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL;
import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -32,7 +34,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 +57,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 +73,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());
}
@@ -88,13 +90,13 @@ public class DmiModelOperations extends DmiOperations {
if (newModuleReferences.isEmpty()) {
return Collections.emptyMap();
}
- final String jsonWithDataAndDmiProperties = getRequestBodyToFetchYangResources(
- newModuleReferences, yangModelCmHandle.getDmiProperties());
+ final String jsonWithDataAndDmiProperties = getRequestBodyToFetchYangResources(newModuleReferences,
+ yangModelCmHandle.getDmiProperties(), yangModelCmHandle.getModuleSetTag());
final ResponseEntity<Object> responseEntity = getResourceFromDmiWithJsonData(
- yangModelCmHandle.resolveDmiServiceName(MODEL),
- jsonWithDataAndDmiProperties,
- yangModelCmHandle.getId(),
- "moduleResources");
+ yangModelCmHandle.resolveDmiServiceName(MODEL),
+ jsonWithDataAndDmiProperties,
+ yangModelCmHandle.getId(),
+ "moduleResources");
return asModuleNameToYangResourceMap(responseEntity);
}
@@ -112,16 +114,21 @@ 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 String moduleSetTag) {
final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(newModuleReferences);
final JsonObject data = new JsonObject();
data.add("modules", moduleReferencesAsJson);
final JsonObject jsonRequestObject = new JsonObject();
+ if (!moduleSetTag.isEmpty()) {
+ final JsonElement moduleSetTagAsJson = JsonParser.parseString(moduleSetTag);
+ jsonRequestObject.add("moduleSetTag", moduleSetTagAsJson);
+ }
jsonRequestObject.add("data", data);
jsonRequestObject.add("cmHandleProperties", toJsonObject(dmiProperties));
return jsonRequestObject.toString();
@@ -140,7 +147,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 +180,7 @@ public class DmiModelOperations extends DmiOperations {
final YangResource yangResource =
jsonObjectMapper.convertToValueType(yangResourceAsMap, YangResource.class);
yangResourcesModuleNameToContentMap.put(yangResource.getModuleName(),
- yangResource.getYangSource());
+ yangResource.getYangSource());
});
}
return yangResourcesModuleNameToContentMap;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
index 912c52ca9..c8d73eac6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
@@ -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;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
index e0c956803..04acaa5e9 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
@@ -20,14 +20,12 @@
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);
}
};
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
index 003dbf5b0..c8e34b1a5 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
@@ -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
index c9491cd02..000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
+++ /dev/null
@@ -1,62 +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"])
-class DmiWebClientConfigurationSpec extends Specification {
-
- @Autowired
- DmiWebClientConfiguration.DmiProperties dmiProperties
-
- def objectUnderTest = new DmiWebClientConfiguration()
-
- def setup() {
- objectUnderTest.connectionTimeoutInSeconds = 10
- }
-
- 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
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
index f588e2ed2..74e342405 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
@@ -31,10 +31,13 @@ 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
def mockRestTemplateBuilder = new RestTemplateBuilder()
@@ -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)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy
index cd9b8ddf4..cfb28a0ad 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy
@@ -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
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy
index 523ec767c..488879db7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy
@@ -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
@@ -48,10 +49,11 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe
@Autowired
ObjectMapper objectMapper
- @SpringBean
- DmiCmNotificationSubscriptionCacheHandler mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler)
+ def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler)
+ def mockCmNotificationSubscriptionEventsHandler = Mock(CmNotificationSubscriptionEventsHandler)
+ def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler)
- def objectUnderTest = new CmNotificationSubscriptionDmiOutEventConsumer(mockDmiCmNotificationSubscriptionCacheHandler)
+ def objectUnderTest = new CmNotificationSubscriptionDmiOutEventConsumer(mockDmiCmNotificationSubscriptionCacheHandler, mockCmNotificationSubscriptionEventsHandler, mockCmNotificationSubscriptionMappersHandler)
def logger = Spy(ListAppender<ILoggingEvent>)
void setup() {
@@ -101,6 +103,10 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe
expectedCacheCalls * mockDmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi('sub-1','test-dmi-plugin-name', subscriptionStatus)
and: 'correct number of calls to persist cache'
expectedPersistenceCalls * mockDmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi('sub-1','test-dmi-plugin-name')
+ and: 'correct number of calls to map the ncmp out event'
+ 1 * mockCmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent('sub-1', _)
+ and: 'correct number of calls to publish the ncmp out event to client'
+ 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent('sub-1', 'subscriptionCreateResponse', _, false)
where: 'the following parameters are used'
scenario | subscriptionStatus | statusCode || expectedCacheCalls | expectedPersistenceCalls
'Accepted Status' | CmNotificationSubscriptionStatus.ACCEPTED | '1' || 1 | 1
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
index 000000000..788a7a7da
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy
@@ -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
index 000000000..bdc54bd1e
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy
@@ -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)
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
index 8210cf32a..9c84c51b2 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
@@ -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(_)
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy
index 0f1bdc65b..77bbe7ebc 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy
@@ -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'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy
index 1020f55ea..98b4ee267 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy
@@ -21,10 +21,17 @@
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,58 @@ 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)
+ and: 'we schedule to send the response after configured time from the cache'
+ 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(
+ "test-id", "subscriptionCreateResponse", null, true)
}
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)
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
index cbc985f78..9907e9ab2 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -22,6 +22,14 @@
package org.onap.cps.ncmp.api.impl.inventory
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
@@ -29,6 +37,7 @@ import org.onap.cps.api.CpsModuleService
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.FetchDescendantsOption
+import org.onap.cps.ncmp.api.impl.exception.NoAlternateIdParentFoundException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.ModuleDefinition
@@ -37,19 +46,10 @@ import org.onap.cps.spi.utils.CpsValidator
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
import spock.lang.Specification
-
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-
class InventoryPersistenceImplSpec extends Specification {
def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
@@ -303,6 +303,41 @@ class InventoryPersistenceImplSpec extends Specification {
assert objectUnderTest.getCmHandleDataNodeByAlternateId('alternate id') == new DataNode()
}
+ def 'Find cm handle parent data node using alternate ids'() {
+ given: 'cm handle in the registry with alternateId /a/b'
+ def matchingCpsPath = "/dmi-registry/cm-handles[@alternate-id='/a/b']"
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath(matchingCpsPath, OMIT_DESCENDANTS) >> [new DataNode()]
+ and: 'no other cm handle'
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
+ expect: 'querying for alternate id a matching result found'
+ assert objectUnderTest.getCmHandleDataNodeByLongestMatchAlternateId(alternateId, '/') != null
+ where: 'the following parameters are used'
+ scenario | alternateId
+ 'exact match' | '/a/b'
+ 'exact match with trailing separator' | '/a/b/'
+ 'child match' | '/a/b/c'
+ }
+
+ def 'Find cm handle parent data node using alternate ids mismatches'() {
+ given: 'cm handle in the registry with alternateId'
+ def matchingCpsPath = "/dmi-registry/cm-handles[@alternate-id='${cpsPath}]"
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath(matchingCpsPath, OMIT_DESCENDANTS) >> [new DataNode()]
+ and: 'no other cm handle'
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
+ when: 'attempt to find alternateId'
+ objectUnderTest.getCmHandleDataNodeByLongestMatchAlternateId(alternateId, '/')
+ then: 'no alternate id found exception thrown'
+ def thrown = thrown(NoAlternateIdParentFoundException)
+ and: 'the exception has the relevant details from the error response'
+ assert thrown.message == 'No matching (parent) cm handle found using alternate ids'
+ assert thrown.details == 'cannot find a datanode with alternate id ' + alternateId
+ where: 'the following parameters are used'
+ scenario | alternateId | cpsPath
+ 'no match for parent only' | '/a' | '/a/b'
+ 'no match at all' | '/x/y/z' | '/a/b'
+ 'no match with trailing separator' | '/c/d/' | '/c/d'
+ }
+
def 'Attempt to get non existing cm handle data node by alternate id'() {
given: 'query service is invoked and returns empty collection of data nodes'
mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
@@ -340,5 +375,4 @@ class InventoryPersistenceImplSpec extends Specification {
then: 'the cps data service method to delete data nodes is invoked once with the same xPaths'
1 * mockCpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, ['xpath1', 'xpath2'], NO_TIMESTAMP);
}
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
index e2062bc80..eb6c7a0f4 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
@@ -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
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
index a2ec9d1f0..9aab46747 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
@@ -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
@@ -58,7 +58,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']]
def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules"
def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK)
- mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":"tag1"}', READ, NO_AUTH_HEADER)
+ mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER)
>> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
@@ -91,7 +91,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
and: 'a positive response from DMI service when it is called with tha expected parameters'
def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
- '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":"tag1"}', READ, NO_AUTH_HEADER) >> responseFromDmi
+ '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'a get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'the result is the response from DMI service'
@@ -139,7 +139,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
def 'Retrieving yang resources, DMI property handling #scenario.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval(dmiProperties)
- and: 'a positive response from DMI service when it is called with the expected parameters'
+ and: 'a positive response from DMI service when it is called with the expected moduleSetTag, modules and properties'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
'{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}',
@@ -154,6 +154,24 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
'without properties' | [] || '{}'
}
+ def 'Retrieving yang resources #scenario'() {
+ given: 'a cm handle'
+ mockYangModelCmHandleRetrieval([], moduleSetTag)
+ and: 'a positive response from DMI service when it is called with the expected moduleSetTag'
+ def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+ '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}',
+ READ, NO_AUTH_HEADER) >> responseFromDmi
+ when: 'get new yang resources from DMI service'
+ def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
+ then: 'the result is the response from DMI service'
+ assert result == [mod1:'some yang source']
+ where: 'the following Module Set Tags are used'
+ scenario | moduleSetTag || expectedModuleSetTagInRequest
+ 'Without module set tag' | '' || ''
+ 'With module set tag' | 'moduleSetTag1' || '"moduleSetTag":"moduleSetTag1",'
+ }
+
def 'Retrieving yang resources from DMI with no module references.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
index 061878e95..72a0f2f11 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
@@ -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'
@@ -59,22 +58,27 @@ abstract class DmiOperationsBaseSpec extends Specification {
def static resourceIdentifier = 'parent/child'
def mockYangModelCmHandleRetrieval(dmiProperties) {
- populateYangModelCmHandle(dmiProperties)
+ populateYangModelCmHandle(dmiProperties, '')
+ mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
+ }
+
+ def mockYangModelCmHandleRetrieval(dmiProperties, moduleSetTag) {
+ populateYangModelCmHandle(dmiProperties, moduleSetTag)
mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
}
def mockYangModelCmHandleCollectionRetrieval(dmiProperties) {
- populateYangModelCmHandle(dmiProperties)
+ populateYangModelCmHandle(dmiProperties, "")
mockInventoryPersistence.getYangModelCmHandles(_) >> [yangModelCmHandle]
}
- def populateYangModelCmHandle(dmiProperties) {
+ def populateYangModelCmHandle(dmiProperties, moduleSetTag) {
yangModelCmHandle.dmiDataServiceName = dmiServiceName
yangModelCmHandle.dmiServiceName = dmiServiceName
yangModelCmHandle.dmiProperties = dmiProperties
yangModelCmHandle.id = cmHandleId
yangModelCmHandle.compositeState = new CompositeState()
yangModelCmHandle.compositeState.cmHandleState = CmHandleState.READY
- yangModelCmHandle.moduleSetTag = 'tag1'
+ yangModelCmHandle.moduleSetTag = moduleSetTag
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
index 54e9f210d..fbf2c3d78 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
@@ -20,13 +20,12 @@
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.'() {
diff --git a/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json b/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
index 09796e2f4..6b665495c 100644
--- a/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
+++ b/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
@@ -1,6 +1,6 @@
{
"data": {
- "subscriptionId": "cm-subscription-001",
+ "subscriptionId": "test-id",
"predicates": [
{
"targetFilter": ["ch1","ch2"],
diff --git a/cps-parent/pom.xml b/cps-parent/pom.xml
index ca466d704..594aa1f0f 100644
--- a/cps-parent/pom.xml
+++ b/cps-parent/pom.xml
@@ -32,7 +32,7 @@
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
diff --git a/cps-path-parser/pom.xml b/cps-path-parser/pom.xml
index 93166ec9c..3176d9a47 100644
--- a/cps-path-parser/pom.xml
+++ b/cps-path-parser/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml
index 90422d737..ccfb77fb6 100644
--- a/cps-rest/pom.xml
+++ b/cps-rest/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-rest/src/test/java/org/onap/cps/utils/DateTimeUtility.java b/cps-rest/src/test/java/org/onap/cps/utils/DateTimeUtility.java
index f8d709647..af0efe2e2 100644
--- a/cps-rest/src/test/java/org/onap/cps/utils/DateTimeUtility.java
+++ b/cps-rest/src/test/java/org/onap/cps/utils/DateTimeUtility.java
@@ -30,11 +30,11 @@ public interface DateTimeUtility {
DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
static OffsetDateTime toOffsetDateTime(String datetTimestampAsString) {
- return ! StringUtils.hasLength(datetTimestampAsString)
- ? null : OffsetDateTime.parse(datetTimestampAsString, ISO_TIMESTAMP_FORMATTER);
+ return !StringUtils.hasLength(datetTimestampAsString) ? null
+ : OffsetDateTime.parse(datetTimestampAsString, ISO_TIMESTAMP_FORMATTER);
}
static String toString(OffsetDateTime offsetDateTime) {
return offsetDateTime != null ? ISO_TIMESTAMP_FORMATTER.format(offsetDateTime) : null;
}
-}
+} \ No newline at end of file
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml
index 583bad0ab..221e1a9bf 100644
--- a/cps-ri/pom.xml
+++ b/cps-ri/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-service/pom.xml b/cps-service/pom.xml
index adca61763..422496877 100644
--- a/cps-service/pom.xml
+++ b/cps-service/pom.xml
@@ -29,7 +29,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -37,6 +37,10 @@
<dependencies>
<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
@@ -75,6 +79,18 @@
<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>
</dependency>
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index b3f42279d..f556f4064 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -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
index 000000000..109783488
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/events/CpsDataUpdateEventsService.java
@@ -0,0 +1,113 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 TechMahindra Ltd.
+ * 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.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.onap.cps.utils.DateTimeUtility;
+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("${app.cps.data-updated.change-event-notifications-enabled:true}")
+ private boolean cpsChangeEventNotificationsEnabled;
+
+ @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 && cpsChangeEventNotificationsEnabled) {
+ 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("State of Overall Notifications : {} and Cps Change Event Notifications : {}",
+ notificationsEnabled, cpsChangeEventNotificationsEnabled);
+ }
+ }
+
+ 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(DateTimeUtility.toString(observedTimestamp));
+ 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
index 000000000..c19abc176
--- /dev/null
+++ b/cps-service/src/main/java/org/onap/cps/events/CpsEvent.java
@@ -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();
+ }
+}
diff --git a/cps-service/src/test/java/org/onap/cps/utils/DateTimeUtility.java b/cps-service/src/main/java/org/onap/cps/utils/DateTimeUtility.java
index f8d709647..c2310707a 100644
--- a/cps-service/src/test/java/org/onap/cps/utils/DateTimeUtility.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/DateTimeUtility.java
@@ -1,12 +1,13 @@
/*
* ============LICENSE_START=======================================================
* Copyright (c) 2021 Bell Canada.
+ * 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
+ * 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,
@@ -22,18 +23,12 @@ package org.onap.cps.utils;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
-import org.springframework.util.StringUtils;
public interface DateTimeUtility {
String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
- static OffsetDateTime toOffsetDateTime(String datetTimestampAsString) {
- return ! StringUtils.hasLength(datetTimestampAsString)
- ? null : OffsetDateTime.parse(datetTimestampAsString, ISO_TIMESTAMP_FORMATTER);
- }
-
static String toString(OffsetDateTime offsetDateTime) {
return offsetDateTime != null ? ISO_TIMESTAMP_FORMATTER.format(offsetDateTime) : null;
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index b2b2d7d44..fcbfd0561 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -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.
@@ -23,9 +23,13 @@
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
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
index 140dfaac9..57f2f8ea7 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
@@ -3,7 +3,7 @@
* Copyright (C) 2021-2024 Nordix Foundation.
* Modifications Copyright (C) 2021-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2022-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.
@@ -26,6 +26,7 @@ package org.onap.cps.api.impl
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.CpsModulePersistenceService
import org.onap.cps.spi.model.Anchor
@@ -50,7 +51,8 @@ class E2ENetworkSliceSpec extends Specification {
def cpsModuleServiceImpl = new CpsModuleServiceImpl(mockModuleStoreService,
mockYangTextSchemaSourceSetCache, mockCpsAnchorService, mockCpsValidator,timedYangTextSchemaSourceSetBuilder)
- def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)
+ def mockDataUpdateEventsService = Mock(CpsDataUpdateEventsService)
+ def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockDataUpdateEventsService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)
def dataspaceName = 'someDataspace'
def anchorName = 'someAnchor'
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
index 000000000..11842645c
--- /dev/null
+++ b/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy
@@ -0,0 +1,121 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 TechMahindra Ltd.
+ * 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.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.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 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
+ and: 'cpsChangeEventNotificationsEnabled is also true'
+ objectUnderTest.cpsChangeEventNotificationsEnabled = 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 #scenario'() {
+ given: 'an anchor, operation and observed timestamp'
+ def anchor = new Anchor('anchor01', 'dataspace01', 'schema01');
+ def operation = CREATE
+ def observedTimestamp = OffsetDateTime.now()
+ and: 'notificationsEnabled is #notificationsEnabled'
+ objectUnderTest.notificationsEnabled = notificationsEnabled
+ and: 'cpsChangeEventNotificationsEnabled is #cpsChangeEventNotificationsEnabled'
+ objectUnderTest.cpsChangeEventNotificationsEnabled = cpsChangeEventNotificationsEnabled
+ 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'
+ expectedCallToPublisher * mockEventsPublisher.publishCloudEvent('cps-core-event', 'dataspace01:anchor01', _)
+ where: 'below scenarios are present'
+ scenario | notificationsEnabled | cpsChangeEventNotificationsEnabled || expectedCallToPublisher
+ 'both notifications enabled' | true | true || 1
+ 'both notifications disabled' | false | false || 0
+ 'only CPS change event notification enabled' | false | true || 0
+ 'only overall notification enabled' | true | false || 0
+
+ }
+
+ def 'publish cps update event when no timestamp provided'() {
+ given: 'an anchor, operation and null timestamp'
+ def anchor = new Anchor('anchor01', 'dataspace01', 'schema01');
+ def operation = CREATE
+ def observedTimestamp = null
+ and: 'notificationsEnabled is true'
+ objectUnderTest.notificationsEnabled = true
+ and: 'cpsChangeEventNotificationsEnabled is true'
+ objectUnderTest.cpsChangeEventNotificationsEnabled = true
+ when: 'service is called to publish data update event'
+ objectUnderTest.topicName = "cps-core-event"
+ objectUnderTest.publishCpsDataUpdateEvent(anchor, '/', operation, observedTimestamp)
+ then: 'the event is published'
+ 1 * mockEventsPublisher.publishCloudEvent('cps-core-event', 'dataspace01:anchor01', _)
+ }
+}
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
index bb7d3e56f..e62c01d6c 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
@@ -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.5.0-SNAPSHOT</version>
</parent>
<artifactId>dmi-plugin-demo-and-csit-stub-app</artifactId>
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
index 288159cf6..c0b4eadb1 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
@@ -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.5.0-SNAPSHOT</version>
</parent>
<artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId>
diff --git a/dmi-plugin-demo-and-csit-stub/pom.xml b/dmi-plugin-demo-and-csit-stub/pom.xml
index d8576459b..071927252 100644
--- a/dmi-plugin-demo-and-csit-stub/pom.xml
+++ b/dmi-plugin-demo-and-csit-stub/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml
index 8a6c13ebe..4f5180d51 100644
--- a/docs/api/swagger/ncmp/openapi-inventory.yaml
+++ b/docs/api/swagger/ncmp/openapi-inventory.yaml
@@ -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:
diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml
index da0b0b3f9..9f6a1b2b6 100644
--- a/docs/api/swagger/ncmp/openapi.yaml
+++ b/docs/api/swagger/ncmp/openapi.yaml
@@ -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
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index f04f977c4..82a890d79 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -16,6 +16,61 @@ CPS Release Notes
.. * * * NEW DELHI * * *
.. =========================
+Version: 3.4.10
+===============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project** | |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images** | onap/cps-and-ncmp:3.4.10 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation** | 3.4.10 New Delhi |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release date** | Not yet released |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.4.10
+
+Features
+--------
+
+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** | 2024 May 14 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.4.9
+ - `CPS-2211 <https://jira.onap.org/browse/CPS-2211>`_ Toggle switch to disable CPS Core change events if not used by application. Set CPS_CHANGE_EVENT_NOTIFICATIONS_ENABLED environment variable for the same.
+
+Features
+--------
+
Version: 3.4.8
==============
@@ -32,7 +87,7 @@ Release Data
| **Release designation** | 3.4.8 New Delhi |
| | |
+--------------------------------------+--------------------------------------------------------+
-| **Release date** | Not yet released |
+| **Release date** | 2024 May 1 |
| | |
+--------------------------------------+--------------------------------------------------------+
@@ -40,6 +95,9 @@ 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
+ - `CPS-2204 <https://jira.onap.org/browse/CPS-2204>`_ Added error handling for yang module upgrade operation
Features
--------
diff --git a/integration-test/pom.xml b/integration-test/pom.xml
index d4ee0cc68..f228e0119 100644
--- a/integration-test/pom.xml
+++ b/integration-test/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -33,15 +33,6 @@
<dependencies>
<!-- T E S T D E P E N D E N C I E S -->
<dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter</artifactId>
- </dependency>
- <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>cps-rest</artifactId>
<scope>test</scope>
@@ -67,6 +58,26 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>kafka</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>postgresql</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<scope>test</scope>
@@ -93,19 +104,9 @@
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
- <artifactId>postgresql</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.testcontainers</groupId>
<artifactId>spock</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.testcontainers</groupId>
- <artifactId>kafka</artifactId>
- <scope>test</scope>
- </dependency>
</dependencies>
<profiles>
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
index 51b02387e..6952b2ad3 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
@@ -20,8 +20,14 @@
package org.onap.cps.integration.base
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
+import okhttp3.mockwebserver.MockWebServer
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsDataspaceService
@@ -48,23 +54,12 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import org.springframework.test.web.client.ExpectedCount
-import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.servlet.MockMvc
-import org.springframework.web.client.RestTemplate
import org.testcontainers.spock.Testcontainers
import spock.lang.Shared
import spock.lang.Specification
import spock.util.concurrent.PollingConditions
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
@Testcontainers
@EnableAutoConfiguration
@@ -111,17 +106,19 @@ abstract class CpsIntegrationSpecBase extends Specification {
NetworkCmProxyQueryService networkCmProxyQueryService
@Autowired
- RestTemplate restTemplate
-
- @Autowired
ModuleSyncWatchdog moduleSyncWatchdog
@Autowired
JsonObjectMapper jsonObjectMapper
- MockRestServiceServer mockDmiServer = null
+ @Autowired
+ InventoryPersistence inventoryPersistence
+
+ MockWebServer mockDmiServer = null
+ DmiDispatcher dmiDispatcher = new DmiDispatcher()
+
+ def DMI_URL = null
- static DMI_URL = 'http://mock-dmi-server'
static NO_MODULE_SET_TAG = ''
static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
@@ -135,7 +132,14 @@ abstract class CpsIntegrationSpecBase extends Specification {
createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
initialized = true
}
- mockDmiServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
+ mockDmiServer = new MockWebServer()
+ mockDmiServer.setDispatcher(dmiDispatcher)
+ mockDmiServer.start()
+ DMI_URL = String.format("http://%s:%s", mockDmiServer.getHostName(), mockDmiServer.getPort())
+ }
+
+ def cleanup() {
+ mockDmiServer.shutdown()
}
def static readResourceDataFile(filename) {
@@ -217,23 +221,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
}
- def mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
- mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
- mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
- }
-
- def mockDmiIsNotAvailableForModuleSync(dmiPlugin, cmHandleId) {
- mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
- .andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
- }
-
- def mockDmiWillRespondToHealthChecks(dmiPlugin) {
- mockDmiServer.expect(ExpectedCount.between(0, Integer.MAX_VALUE), requestTo("${dmiPlugin}/actuator/health"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body('{"status":"UP"}'))
- }
-
def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
new file mode 100644
index 000000000..6676cb74c
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
@@ -0,0 +1,105 @@
+/*
+ * ============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.integration.base
+
+import static org.onap.cps.integration.base.CpsIntegrationSpecBase.readResourceDataFile
+
+import org.springframework.http.HttpHeaders
+import java.util.regex.Matcher
+import okhttp3.mockwebserver.Dispatcher
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.RecordedRequest
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+
+/**
+ * This class simulates responses from the DMI server in NCMP integration tests.
+ *
+ * It is to be used with a MockWebServer, using mockWebServer.setDispatcher(new DmiDispatcher()).
+ *
+ * It currently implements the following endpoints:
+ * - /actuator/health: healthcheck endpoint that responds with 200 OK / {"status":"UP"}
+ * - /dmi/v1/ch/{cmHandleId}/modules: returns module references for a CM handle
+ * - /dmi/v1/ch/{cmHandleId}/moduleResources: returns modules resources for a CM handle
+ *
+ * The module resource/reference responses are generated based on the module names in the map moduleNamesPerCmHandleId.
+ * To configure the DMI so that CM handle 'ch-1' will have modules 'M1' and 'M2', you may use:
+ * dmiDispatcher.moduleNamesPerCmHandleId.put('ch-1', ['M1', 'M2']);
+ *
+ * To simulate the DMI not being available, the boolean isAvailable may be set to false, in which case the mock server
+ * will always respond with 503 Service Unavailable.
+ */
+class DmiDispatcher extends Dispatcher {
+
+ static final MODULE_REFERENCES_RESPONSE_TEMPLATE = readResourceDataFile('mock-dmi-responses/moduleReferencesTemplate.json')
+ static final MODULE_RESOURCES_RESPONSE_TEMPLATE = readResourceDataFile('mock-dmi-responses/moduleResourcesTemplate.json')
+
+ def isAvailable = true
+
+ Map<String, List<String>> moduleNamesPerCmHandleId = [:]
+
+ @Override
+ MockResponse dispatch(RecordedRequest request) {
+ if (!isAvailable) {
+ return new MockResponse().setResponseCode(HttpStatus.SERVICE_UNAVAILABLE.value())
+ }
+ switch (request.path) {
+ case ~/^\/dmi\/v1\/ch\/(.*)\/modules$/:
+ def cmHandleId = Matcher.lastMatcher[0][1]
+ return getModuleReferencesResponse(cmHandleId)
+
+ case ~/^\/dmi\/v1\/ch\/(.*)\/moduleResources$/:
+ def cmHandleId = Matcher.lastMatcher[0][1]
+ return getModuleResourcesResponse(cmHandleId)
+
+ default:
+ throw new IllegalArgumentException('Mock DMI does not handle path ' + request.path)
+ }
+ }
+
+ private getModuleReferencesResponse(cmHandleId) {
+ def moduleReferences = '{"schemas":[' + getModuleNamesForCmHandle(cmHandleId).collect {
+ MODULE_REFERENCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it)
+ }.join(',') + ']}'
+ return mockOkResponseWithBody(moduleReferences)
+ }
+
+ private getModuleResourcesResponse(cmHandleId) {
+ def moduleResources = '[' + getModuleNamesForCmHandle(cmHandleId).collect {
+ MODULE_RESOURCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it)
+ }.join(',') + ']'
+ return mockOkResponseWithBody(moduleResources)
+ }
+
+ private getModuleNamesForCmHandle(cmHandleId) {
+ if (!moduleNamesPerCmHandleId.containsKey(cmHandleId)) {
+ throw new IllegalArgumentException('Mock DMI has no modules configured for ' + cmHandleId)
+ }
+ return moduleNamesPerCmHandleId.get(cmHandleId)
+ }
+
+ private static mockOkResponseWithBody(responseBody) {
+ return new MockResponse()
+ .setResponseCode(HttpStatus.OK.value())
+ .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+ .setBody(responseBody)
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
index d8585fb97..4ffe586a9 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
@@ -20,38 +20,45 @@
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
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import org.springframework.test.web.client.match.MockRestRequestMatchers
-
import static org.springframework.http.HttpMethod.GET
import static org.springframework.http.HttpMethod.DELETE
import static org.springframework.http.HttpMethod.PATCH
import static org.springframework.http.HttpMethod.POST
import static org.springframework.http.HttpMethod.PUT
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.method
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
-@Ignore
+import okhttp3.mockwebserver.Dispatcher
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.RecordedRequest
+import org.jetbrains.annotations.NotNull
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import spock.util.concurrent.PollingConditions
+
class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
- static final MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
+ def lastAuthHeaderReceived = null
def setup() {
- mockDmiWillRespondToHealthChecks(DMI_URL)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE, MODULE_RESOURCES_RESPONSE)
+ dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG)
- mockDmiServer.reset()
- mockDmiWillRespondToHealthChecks(DMI_URL)
+
+ mockDmiServer.setDispatcher(new Dispatcher() {
+ @Override
+ MockResponse dispatch(@NotNull RecordedRequest request) throws InterruptedException {
+ if (request.path == '/actuator/health') {
+ return new MockResponse()
+ .addHeader("Content-Type", MediaType.APPLICATION_JSON).setBody('{"status":"UP"}')
+ .setResponseCode(HttpStatus.OK.value())
+ } else {
+ lastAuthHeaderReceived = request.getHeader('Authorization')
+ return new MockResponse().setResponseCode(HttpStatus.OK.value())
+ }
+ }
+ })
}
def cleanup() {
@@ -59,12 +66,6 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
}
def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() {
- given: 'DMI will expect to receive a request with a bearer token'
- def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id"
- mockDmiServer.expect(requestTo(targetDmiUrl))
- .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token'))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON))
-
when: 'a pass-through data request is sent to NCMP with a bearer token'
mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
.queryParam('resourceIdentifier', 'my-resource-id')
@@ -74,19 +75,13 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI has received request with bearer token'
- mockDmiServer.verify()
+ lastAuthHeaderReceived == 'Bearer some-bearer-token'
where: 'all HTTP operations are applied'
httpMethod << [GET, POST, PUT, PATCH, DELETE]
}
def 'Basic auth header is NOT passed from NCMP to DMI in pass-through data operations.'() {
- given: 'DMI will expect to receive a request with no authorization header'
- def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id"
- mockDmiServer.expect(requestTo(targetDmiUrl))
- .andExpect(MockRestRequestMatchers.headerDoesNotExist(HttpHeaders.AUTHORIZATION))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON))
-
when: 'a pass-through data request is sent to NCMP with basic authentication'
mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
.queryParam('resourceIdentifier', 'my-resource-id')
@@ -96,18 +91,13 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI has received request with no authorization header'
- mockDmiServer.verify()
+ lastAuthHeaderReceived == null
where: 'all HTTP operations are applied'
httpMethod << [GET, POST, PUT, PATCH, DELETE]
}
def 'Bearer token is passed from NCMP to DMI in async batch pass-through data operation.'() {
- given: 'DMI will expect to receive a request with a bearer token'
- mockDmiServer.expect(method(POST))
- .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token'))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON))
-
when: 'a pass-through async data request is sent to NCMP with a bearer token'
def requestBody = """{"operations": [{
"operation": "read",
@@ -124,7 +114,9 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI will receive the async request with bearer token'
- mockDmiServer.verify(Duration.ofSeconds(1))
+ new PollingConditions().within(3, () -> {
+ assert lastAuthHeaderReceived == 'Bearer some-bearer-token'
+ })
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
index 4e291490d..5c337f179 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
@@ -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,26 +35,19 @@ 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
def kafkaConsumer = KafkaTestContainer.getConsumer('ncmp-group', StringDeserializer.class)
- static final MODULE_REFERENCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final MODULE_RESOURCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
- static final MODULE_REFERENCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
- static final MODULE_RESOURCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
-
def setup() {
objectUnderTest = networkCmProxyDataService
- mockDmiWillRespondToHealthChecks(DMI_URL)
}
def 'CM Handle registration is successful.'() {
given: 'DMI will return modules when requested'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
+ dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
and: 'consumer subscribed to topic'
kafkaConsumer.subscribe(['ncmp-events'])
@@ -91,16 +82,13 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
and: 'the CM-handle has expected modules'
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
- and: 'DMI received expected requests'
- mockDmiServer.verify()
-
cleanup: 'deregister CM handle'
deregisterCmHandle(DMI_URL, 'ch-1')
}
def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
given: 'DMI is not available to handle requests'
- mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-1')
+ dmiDispatcher.isAvailable = false
when: 'a CM-handle is registered for creation'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
@@ -125,13 +113,11 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
}
def 'Create a CM-handle with existing moduleSetTag.'() {
- given: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ given: 'DMI will return modules when requested'
+ dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
+ and: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
registerCmHandle(DMI_URL, 'ch-1', 'A')
registerCmHandle(DMI_URL, 'ch-2', 'B')
- assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
- assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-2').moduleName.sort()
when: 'a CM-handle is registered for creation with moduleSetTag "B"'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-3', moduleSetTag: 'B')
@@ -155,11 +141,7 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
def 'CM Handle retry after failed module sync.'() {
given: 'DMI is not initially available to handle requests'
- mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-1')
- mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-2')
- and: 'DMI will be available for retry'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ dmiDispatcher.isAvailable = false
when: 'CM-handles are registered for creation'
def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'ch-1'), new NcmpServiceCmHandle(cmHandleId: 'ch-2')]
@@ -182,7 +164,11 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.ADVISED
assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.ADVISED
- when: 'module sync runs'
+ when: 'DMI is available for retry'
+ dmiDispatcher.isAvailable = true
+ and: 'DMI will return expected modules'
+ dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
+ and: 'module sync runs'
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handles go to READY state'
new PollingConditions().within(3, () -> {
@@ -195,8 +181,6 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
and: 'CM-handles have expected module set tags (blank)'
assert objectUnderTest.getNcmpServiceCmHandle('ch-1').moduleSetTag == ''
assert objectUnderTest.getNcmpServiceCmHandle('ch-2').moduleSetTag == ''
- and: 'DMI received expected requests'
- mockDmiServer.verify()
cleanup: 'deregister CM handle'
deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2'])
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
index 68c354e02..4d1d77e69 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
@@ -27,40 +27,26 @@ import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
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
- static final INITIAL_MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final INITIAL_MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
- static final UPDATED_MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
- static final UPDATED_MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
static final CM_HANDLE_ID = 'ch-1'
static final CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG = 'ch-2'
def setup() {
objectUnderTest = networkCmProxyDataService
- mockDmiWillRespondToHealthChecks(DMI_URL)
}
def 'Upgrade CM-handle with new moduleSetTag or no moduleSetTag.'() {
- given: 'DMI will return modules for initial registration'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
- and: 'DMI returns different modules for upgrade'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
-
- when: 'a CM-handle is created with expected initial modules: M1 and M2'
+ given: 'a CM-handle is created with expected initial modules: M1 and M2'
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag)
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
- and: "the CM-handle is upgraded with given moduleSetTag '${updatedModuleSetTag}'"
+
+ when: "the CM-handle is upgraded with given moduleSetTag '${updatedModuleSetTag}'"
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
@@ -74,14 +60,16 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE
assert cmHandleCompositeState.lockReason.details == "Upgrade to ModuleSetTag: ${updatedModuleSetTag}"
- when: 'module sync runs'
+ when: 'DMI will return different modules for upgrade: M1 and M3'
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M3']
+ and: 'module sync runs'
moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
+ new PollingConditions().eventually {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
- })
+ }
and: 'the CM-handle has expected moduleSetTag'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
@@ -89,9 +77,6 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
and: 'CM-handle has expected updated modules: M1 and M3'
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
- and: 'DMI received expected requests'
- mockDmiServer.verify()
-
cleanup: 'deregister CM-handle'
deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
@@ -105,8 +90,8 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
def 'Upgrade CM-handle with existing moduleSetTag.'() {
given: 'DMI will return modules for registration'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG] = ['M1', 'M3']
and: "an existing CM-handle handle with moduleSetTag '${updatedModuleSetTag}'"
registerCmHandle(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, updatedModuleSetTag)
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG).moduleName.sort()
@@ -127,9 +112,9 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
+ new PollingConditions().eventually {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
- })
+ }
and: 'the CM-handle has expected moduleSetTag'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
@@ -148,7 +133,7 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
def 'Skip upgrade of CM-handle with same moduleSetTag as before.'() {
given: 'an existing CM-handle with expected initial modules: M1 and M2'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
registerCmHandle(DMI_URL, CM_HANDLE_ID, 'same')
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
@@ -171,14 +156,13 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
}
def 'Upgrade of CM-handle fails due to DMI error.'() {
- given: 'DMI will return modules for initial registration'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
- and: 'DMI returns error code for upgrade'
- mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
-
- when: 'a CM-handle is created'
+ given: 'a CM-handle exists'
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
registerCmHandle(DMI_URL, CM_HANDLE_ID, 'oldTag')
- and: 'the CM-handle is upgraded'
+ and: 'DMI is not available for upgrade'
+ dmiDispatcher.isAvailable = false
+
+ when: 'the CM-handle is upgraded'
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'newTag')
networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
@@ -188,11 +172,11 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED'
- new PollingConditions().within(3, () -> {
+ new PollingConditions(timeout: 3).eventually {
def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED
- })
+ }
and: 'the CM-handle has same moduleSetTag as before'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == 'oldTag'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
index 14b9f6560..302c7e512 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
@@ -1,13 +1,30 @@
-package org.onap.cps.integration.functional
+/*
+ * ============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=========================================================
+ */
-import spock.lang.Ignore
+package org.onap.cps.integration.functional
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
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
index 5e250b0e5..950cd65e7 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
@@ -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,23 +30,15 @@ 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')
- static final MODULE_RESOURCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
- static final MODULE_REFERENCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
- static final MODULE_RESOURCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
-
- def setup() {
- mockDmiWillRespondToHealthChecks(DMI_URL)
- }
-
def 'Register CM Handles using REST API.'() {
given: 'DMI will return modules'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-3', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ dmiDispatcher.moduleNamesPerCmHandleId = [
+ 'ch-1': ['M1', 'M2'],
+ 'ch-2': ['M1', 'M2'],
+ 'ch-3': ['M1', 'M3']
+ ]
and: 'a POST request is made to register the CM Handles'
def requestBody = '{"dmiPlugin":"'+DMI_URL+'","createdCmHandles":[{"cmHandle":"ch-1"},{"cmHandle":"ch-2"},{"cmHandle":"ch-3"}]}'
mvc.perform(post('/ncmpInventory/v1/ch').contentType(MediaType.APPLICATION_JSON).content(requestBody))
@@ -55,10 +46,12 @@ class NcmpRestApiSpec extends CpsIntegrationSpecBase {
when: 'module sync runs'
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handles go to READY state'
- new PollingConditions(timeout: 3, delay: 0.5).eventually {
- mvc.perform(get('/ncmp/v1/ch/ch-1'))
- .andExpect(status().isOk())
- .andExpect(jsonPath('$.state.cmHandleState').value('READY'))
+ new PollingConditions().eventually {
+ (1..3).each {
+ mvc.perform(get('/ncmp/v1/ch/ch-'+it))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath('$.state.cmHandleState').value('READY'))
+ }
}
}
@@ -73,7 +66,7 @@ class NcmpRestApiSpec extends CpsIntegrationSpecBase {
]
}""".formatted(moduleName)
expect: "a search for module ${moduleName} returns expected CM handles"
- mvc.perform(post(DMI_URL+'/ncmp/v1/ch/id-searches').contentType(MediaType.APPLICATION_JSON).content(requestBodyWithModuleCondition))
+ mvc.perform(post('/ncmp/v1/ch/id-searches').contentType(MediaType.APPLICATION_JSON).content(requestBodyWithModuleCondition))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath('$[*]', containsInAnyOrder(expectedCmHandles.toArray())))
.andExpect(jsonPath('$', hasSize(expectedCmHandles.size())));
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
index 4b39e5327..cbbf1d9be 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
@@ -20,6 +20,9 @@
package org.onap.cps.integration.performance.base
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+
import org.onap.cps.integration.ResourceMeter
import org.onap.cps.spi.FetchDescendantsOption
@@ -60,6 +63,7 @@ class NcmpPerfTestBase extends PerfTestBase {
def createInitialData() {
addRegistryData()
+ addRegistryDataWithAlternateIdAsPath()
addCmSubscriptionData()
}
@@ -79,6 +83,18 @@ class NcmpPerfTestBase extends PerfTestBase {
}
}
+ def addRegistryDataWithAlternateIdAsPath() {
+ def innerNodeJsonTemplate = readResourceDataFile('ncmp-registry/innerCmHandleNode.json')
+ def batchSize = 10
+ for (def i = 0; i < TOTAL_CM_HANDLES; i += batchSize) {
+ def data = '{ "cm-handles": [' + (1..batchSize).collect {
+ innerNodeJsonTemplate.replace('CM_HANDLE_ID_HERE', (it + i).toString())
+ .replace('ALTERNATE_ID_AS_PATH', (it + i).toString())
+ }.join(',') + ']}'
+ cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry', data, now)
+ }
+ }
+
def createCmDataSubscriptionsSchemaSet() {
def modelAsString = readResourceDataFile('cm-data-subscriptions/cm-data-subscriptions@2023-09-21.yang')
cpsModuleService.createSchemaSet(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_SCHEMA_SET, [registry: modelAsString])
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy
index 0c1e1f5d8..135586936 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimitsPerfTest.groovy
@@ -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", 18.891, 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.141, durationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
}
def countDataNodes() {
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy
index 2efbf7d3f..1b449b8da 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/DeletePerfTest.groovy
@@ -40,7 +40,7 @@ class DeletePerfTest extends CpsPerfTestBase {
resourceMeter.stop()
def setupDurationInSeconds = resourceMeter.getTotalTimeInSeconds()
then: 'setup duration is within expected time and memory used is within limit'
- recordAndAssertResourceUsage('Delete test setup', 100, setupDurationInSeconds, 800, resourceMeter.getTotalMemoryUsageInMB())
+ recordAndAssertResourceUsage('Delete test setup', 103, setupDurationInSeconds, 800, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Delete 100 container nodes'() {
@@ -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', 3.9, 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.87, 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', 4.22, 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.87, 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', 5.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', 1.98, deleteDurationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Delete 1 large data node'() {
@@ -140,7 +140,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 one large node', 2, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
+ recordAndAssertResourceUsage('Delete one large node', 2.35, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Delete root node with many descendants'() {
@@ -150,7 +150,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 root node', 2, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
+ recordAndAssertResourceUsage('Delete root node', 2.23, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Delete data nodes for an anchor'() {
@@ -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', 2.25, 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', 0.74, deleteDurationInSeconds, 3, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Clean up test data'() {
@@ -186,7 +186,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 test cleanup', 10, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
+ recordAndAssertResourceUsage('Delete test cleanup', 11.09, deleteDurationInSeconds, 1, resourceMeter.getTotalMemoryUsageInMB())
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
index 8a228a353..060c9cb6d 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
@@ -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
+ 'no descendants' | OMIT_DESCENDANTS || 0.01 | 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
+ 'all descendants' | INCLUDE_ALL_DESCENDANTS || 1.47 | 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", 2.2, 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.28 | 250 | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+ 'openroadm top element' | '/openroadm-devices' || 1.3 | 250 | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+ 'openroadm whole list' | '/openroadm-devices/openroadm-device' || 1.51 | 250 | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy
index 0ae018d46..f31c6a988 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy
@@ -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.27 | 400 | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+ 'leaf condition' | '//openroadm-device[@ne-state="inservice"]' || 1.3 | 400 | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
+ 'ancestors' | '//openroadm-device/ancestor::openroadm-devices' || 1.46 | 400 | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+ 'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 1.32 | 400 | OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1
+ 'non-existing data' | '/path/to/non-existing/node[@id="1"]' || 0.01 | 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.76 | 600 | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+ 'leaf condition' | '//openroadm-device[@ne-state="inservice"]' || 3.3 | 600 | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE)
+ 'ancestors' | '//openroadm-device/ancestor::openroadm-devices' || 3.96 | 600 | OPENROADM_ANCHORS * (OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE + 1)
+ 'leaf condition + ancestors' | '//openroadm-device[@status="success"]/ancestor::openroadm-devices' || 3.76 | 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.16 | 12 | OPENROADM_DEVICES_PER_ANCHOR * 2
+ 'all descendants' | INCLUDE_ALL_DESCENDANTS || 1.4 | 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.1 | 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.09 | 3 | 1
+ 'direct descendants' | DIRECT_CHILDREN_ONLY || 0.11 | 8 | 1 + OPENROADM_DEVICES_PER_ANCHOR
+ 'all descendants' | INCLUDE_ALL_DESCENDANTS || 1.34 | 400 | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
index 69f64773f..1d3943f36 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
@@ -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.99 | 200
+ 'Replace 100 using same data' | 100 | 1 | false || 7.46 | 200
+ 'Replace 100 with new leaf values' | 100 | 1 | true || 7.87 | 200
+ 'Replace 100 with 100 new nodes' | 100 | 101 | false || 13.85 | 200
+ 'Replace 50 existing and 50 new' | 100 | 151 | true || 10.82 | 200
+ 'Replace 100 nodes with 0' | 0 | 1 | false || 8.91 | 200
}
def 'Replace list content: #scenario.'() {
@@ -104,13 +104,13 @@ class UpdatePerfTest extends CpsPerfTestBase {
timeLimit, resourceMeter.getTotalTimeInSeconds(),
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
+ scenario | totalNodes | startId | changeLeaves || timeLimit | memoryLimit
+ 'Replace list of 0 with 100' | 100 | 1 | false || 4.01 | 200
+ 'Replace list of 100 using same data' | 100 | 1 | false || 5.53 | 200
+ 'Replace list of 100 with new leaf values' | 100 | 1 | true || 6.96 | 200
+ 'Replace list with 100 new nodes' | 100 | 101 | false || 12.82 | 200
+ 'Replace list with 50 existing and 50 new' | 100 | 151 | true || 10.42 | 200
+ 'Replace list of 100 nodes with 1' | 1 | 1 | false || 9.26 | 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.35, resourceMeter.getTotalTimeInSeconds(),
120, resourceMeter.getTotalMemoryUsageInMB())
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
index 96f85ffd7..019561174 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
@@ -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.98 | 100
+ 100 || 3.84 | 200
+ 200 || 8.6 | 400
+ 400 || 16.37 | 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.38 | 50
+ 1600 || 0.95 | 100
+ 3200 || 2.71 | 150
+ 6400 || 8.08 | 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.8 | 100
+ 100 || 3.93 | 200
+ 200 || 7.77 | 400
+ 400 || 16.59 | 500
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
index 579394be8..fc2f8cf00 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
@@ -52,7 +52,7 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
matches.size() == numberOfFiltersPerCmHandle * numberOfCmHandlesPerCmDataSubscription
and: 'query all subscribers within 1 second'
def durationInSeconds = resourceMeter.getTotalTimeInSeconds()
- recordAndAssertResourceUsage("Query all subscribers", 1.2, durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
+ recordAndAssertResourceUsage("Query all subscribers", 2.56, durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Worst case subscription update (200x10 matching entries).'() {
@@ -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", 13.86, durationInSeconds, 1000, resourceMeter.getTotalMemoryUsageInMB())
}
def 'Worst case new subscription (200x10 new entries).'() {
@@ -109,7 +109,7 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
resourceMeter.stop()
def durationInSeconds = resourceMeter.getTotalTimeInSeconds()
then: 'insert new subscription with 1 second'
- recordAndAssertResourceUsage("Insert new subscription", 2, durationInSeconds, 100, resourceMeter.getTotalMemoryUsageInMB())
+ recordAndAssertResourceUsage("Insert new subscription", 1.28, durationInSeconds, 100, resourceMeter.getTotalMemoryUsageInMB())
}
def querySubscriptionsByIteration(Collection<DataNode> allSubscriptionsAsDataNodes, targetSubscriptionSequenceNumber) {
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy
new file mode 100644
index 000000000..bbff5a83f
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy
@@ -0,0 +1,53 @@
+/*
+ * ============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.integration.performance.ncmp
+
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
+import org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
+import org.onap.cps.integration.ResourceMeter
+import org.onap.cps.integration.performance.base.NcmpPerfTestBase
+import java.util.stream.Collectors
+
+class CmHandleQueryByAlternateIdPerfTest extends NcmpPerfTestBase {
+
+ InventoryPersistence objectUnderTest
+ ResourceMeter resourceMeter = new ResourceMeter()
+
+ def setup() { objectUnderTest = inventoryPersistence }
+
+ def 'Query cm handle by longest match alternate id'() {
+ when: 'an alternate id as cps path query'
+ resourceMeter.start()
+ def cpsPath = "/a/b/c/d-5/e/f/g/h/i"
+ def dataNodes = objectUnderTest.getCmHandleDataNodeByLongestMatchAlternateId(cpsPath, '/')
+ and: 'the ids of the result are extracted and converted to xpath'
+ def cpsXpaths = dataNodes.stream().map(dataNode -> "/dmi-registry/cm-handles[@id='${dataNode.leaves.id}']".toString() ).collect(Collectors.toSet())
+ and: 'a single get is executed to get all the parent objects and their descendants'
+ cpsDataService.getDataNodesForMultipleXpaths(NcmpPersistence.NCMP_DATASPACE_NAME, NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR, cpsXpaths, OMIT_DESCENDANTS)
+ resourceMeter.stop()
+ def durationInSeconds = resourceMeter.getTotalTimeInSeconds()
+ print 'Total time in seconds to query ch handle by alternate id: ' + durationInSeconds
+ then: 'the required operations are performed within required time and memory limit'
+ recordAndAssertResourceUsage('CpsPath Registry attributes Query', 1, durationInSeconds, 300, resourceMeter.getTotalMemoryUsageInMB())
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy
index d95ac7319..d518234f5 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy
@@ -20,21 +20,15 @@
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.96, 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 = 8 * 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.'() {
@@ -136,7 +130,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase {
expectedAverageResponseTime, averageResponseTime,
15, resourceMeter.totalMemoryUsageInMB)
where:
- expectedAverageResponseTime = 1 * MILLISECONDS
+ expectedAverageResponseTime = 4 * MILLISECONDS
}
def 'Find any CM-handle given moduleSetTag when there are 20K READY handles with same moduleSetTag.'() {
@@ -157,7 +151,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase {
expectedAverageResponseTime, averageResponseTime,
500, resourceMeter.totalMemoryUsageInMB)
where:
- expectedAverageResponseTime = 100 * MILLISECONDS
+ expectedAverageResponseTime = 438 * MILLISECONDS
}
}
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json
deleted file mode 100644
index 5d713914d..000000000
--- a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "moduleName": "M1",
- "revision": "2024-01-01",
- "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "M2",
- "revision": "2024-01-02",
- "yangSource": "module M2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-02 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json
deleted file mode 100644
index 9f20564f0..000000000
--- a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "M1",
- "revision": "2024-01-01"
- },
- {
- "moduleName": "M2",
- "revision": "2024-01-02"
- }
- ]
-} \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json
deleted file mode 100644
index ef9b85f92..000000000
--- a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "moduleName": "M1",
- "revision": "2024-01-01",
- "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "M3",
- "revision": "2024-01-03",
- "yangSource": "module M3 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M3\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-03 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json
deleted file mode 100644
index 513c749a2..000000000
--- a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "M1",
- "revision": "2024-01-01"
- },
- {
- "moduleName": "M3",
- "revision": "2024-01-03"
- }
- ]
-} \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/moduleReferencesTemplate.json b/integration-test/src/test/resources/data/mock-dmi-responses/moduleReferencesTemplate.json
new file mode 100644
index 000000000..2551ad4e3
--- /dev/null
+++ b/integration-test/src/test/resources/data/mock-dmi-responses/moduleReferencesTemplate.json
@@ -0,0 +1,4 @@
+{
+ "moduleName": "<MODULE_NAME>",
+ "revision": "2024-01-01"
+}
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/moduleResourcesTemplate.json b/integration-test/src/test/resources/data/mock-dmi-responses/moduleResourcesTemplate.json
new file mode 100644
index 000000000..1e189f188
--- /dev/null
+++ b/integration-test/src/test/resources/data/mock-dmi-responses/moduleResourcesTemplate.json
@@ -0,0 +1,5 @@
+{
+ "moduleName": "<MODULE_NAME>",
+ "revision": "2024-01-01",
+ "yangSource": "module <MODULE_NAME> {\n\n namespace \"urn:ietf:params:xml:ns:yang:<MODULE_NAME>\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+}
diff --git a/integration-test/src/test/resources/data/ncmp-registry/innerCmHandleNode.json b/integration-test/src/test/resources/data/ncmp-registry/innerCmHandleNode.json
new file mode 100644
index 000000000..88446c4a0
--- /dev/null
+++ b/integration-test/src/test/resources/data/ncmp-registry/innerCmHandleNode.json
@@ -0,0 +1,24 @@
+{
+ "id": "cm-handle-CM_HANDLE_ID_HERE",
+ "alternate-id": "/a/b/c/d-ALTERNATE_ID_AS_PATH",
+ "module-set-tag": "my-module-set-tag",
+ "dmi-service-name": "http://ncmp-dmi-plugin-stub:8080",
+ "dmi-data-service-name": "",
+ "dmi-model-service-name": "",
+ "additional-properties": [
+ {
+ "name": "neType",
+ "value": "RadioNode"
+ }
+ ],
+ "state": {
+ "cm-handle-state": "READY",
+ "last-update-time": "2023-03-01T19:18:33.571+0000",
+ "data-sync-enabled": false,
+ "datastores": {
+ "operational": {
+ "sync-state": "NONE_REQUESTED"
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/jacoco-report/pom.xml b/jacoco-report/pom.xml
index 9919e8ccc..447614f39 100644
--- a/jacoco-report/pom.xml
+++ b/jacoco-report/pom.xml
@@ -5,7 +5,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/pom.xml b/pom.xml
index df89d965a..4d0460237 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
<groupId>org.onap.cps</groupId>
<artifactId>cps-aggregator</artifactId>
- <version>3.4.8-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>cps</name>
diff --git a/releases/3.4.8-container.yaml b/releases/3.4.8-container.yaml
new file mode 100644
index 000000000..c5cccb463
--- /dev/null
+++ b/releases/3.4.8-container.yaml
@@ -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
index 000000000..a711ff7cf
--- /dev/null
+++ b/releases/3.4.8.yaml
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/948/
+project: cps
+version: 3.4.8
diff --git a/releases/3.4.9-container.yaml b/releases/3.4.9-container.yaml
new file mode 100644
index 000000000..ab557665e
--- /dev/null
+++ b/releases/3.4.9-container.yaml
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.4.9
+project: cps
+log_dir: cps-maven-docker-stage-master/941/
+ref: 85de6a351eadb3b3a48aabc776c892926333db60
+containers:
+ - name: 'cps-and-ncmp'
+ version: '3.4.9-20240513T163732Z' \ No newline at end of file
diff --git a/releases/3.4.9.yaml b/releases/3.4.9.yaml
new file mode 100644
index 000000000..81217f4bd
--- /dev/null
+++ b/releases/3.4.9.yaml
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/949/
+project: cps
+version: 3.4.9 \ No newline at end of file
diff --git a/spotbugs/pom.xml b/spotbugs/pom.xml
index 02c60793c..bab955190 100644
--- a/spotbugs/pom.xml
+++ b/spotbugs/pom.xml
@@ -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.5.0-SNAPSHOT</version>
<properties>
<nexusproxy>https://nexus.onap.org</nexusproxy>
diff --git a/version.properties b/version.properties
index 767a534df..5fdc4e357 100644
--- a/version.properties
+++ b/version.properties
@@ -21,8 +21,8 @@
# because they are used in Jenkins, whose plug-in doesn't support this
major=3
-minor=4
-patch=8
+minor=5
+patch=0
base_version=${major}.${minor}.${patch}