diff options
189 files changed, 2714 insertions, 2987 deletions
diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-in-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-in-event-schema-1.0.0.json index 461bf152ed..93ec216e3d 100644 --- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-in-event-schema-1.0.0.json +++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-in-event-schema-1.0.0.json @@ -1,12 +1,12 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-dmi-in-event-schema:1.0.0", - "$ref": "#/definitions/CmNotificationSubscriptionDmiInEvent", + "$ref": "#/definitions/DmiInEvent", "definitions": { - "CmNotificationSubscriptionDmiInEvent": { + "DmiInEvent": { "description": "The payload for cm notification subscription event incoming message from NCMP.", "type": "object", - "javaType": "org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent", + "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent", "additionalProperties": false, "properties": { "data": { diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-out-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-out-event-schema-1.0.0.json index 538716ab55..0910de1529 100644 --- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-out-event-schema-1.0.0.json +++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-out-event-schema-1.0.0.json @@ -1,13 +1,13 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-dmi-out-event-schema:1.0.0", - "$ref": "#/definitions/CmNotificationSubscriptionDmiOutEvent", + "$ref": "#/definitions/DmiOutEvent", "definitions": { - "CmNotificationSubscriptionDmiOutEvent": { + "DmiOutEvent": { "description": "The payload for cm notification subscription merge event coming out from DMI Plugin.", "type": "object", "additionalProperties": false, - "javaType": "org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent", + "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent", "properties": { "data": { "$ref": "#/definitions/Data" @@ -16,7 +16,7 @@ "required": [ "data" ], - "title": "CmNotificationSubscriptionDmiOutEvent" + "title": "DmiOutEvent" }, "Data": { "type": "object", diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-in-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-in-event-schema-1.0.0.json index e39d7d9a57..f8b6c2e680 100644 --- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-in-event-schema-1.0.0.json +++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-in-event-schema-1.0.0.json @@ -1,11 +1,11 @@ { "$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-ncmp-in-event:1.0.0", - "$ref": "#/definitions/CmNotificationSubscriptionNcmpInEvent", + "$ref": "#/definitions/NcmpInEvent", "$schema": "https://json-schema.org/draft/2019-09/schema", "definitions": { - "CmNotificationSubscriptionNcmpInEvent": { + "NcmpInEvent": { "description": "The payload for subscription merge event.", - "javaType": "org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent", + "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent", "properties": { "data": { "properties": { diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-out-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-out-event-schema-1.0.0.json index d75e53cdfc..0c8d02a613 100644 --- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-out-event-schema-1.0.0.json +++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-out-event-schema-1.0.0.json @@ -1,12 +1,12 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-ncmp-out-event-schema:1.0.0", - "$ref": "#/definitions/CmNotificationSubscriptionNcmpOutEvent", + "$ref": "#/definitions/NcmpOutEvent", "definitions": { - "CmNotificationSubscriptionNcmpOutEvent": { + "NcmpOutEvent": { "type": "object", "description": "The payload applied cm subscription merge event coming out from NCMP.", - "javaType": "org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent", + "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent", "additionalProperties": false, "properties": { "data": { @@ -16,7 +16,7 @@ "required": [ "data" ], - "title": "CmNotificationSubscriptionNcmpOutEvent" + "title": "NcmpOutEvent" }, "Data": { "type": "object", diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java index 08a492e0f7..11adc84a1f 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java @@ -35,7 +35,7 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; +import org.onap.cps.ncmp.api.data.models.DatastoreType; import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi; import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters; import org.onap.cps.ncmp.rest.model.DataOperationRequest; diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy index b36e25ada0..177febd8ae 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy @@ -19,24 +19,18 @@ */ package org.onap.cps.ncmp.rest.stub -import org.onap.cps.ncmp.api.impl.operations.DatastoreType +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.JsonMappingException +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.data.models.DatastoreType import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootContextLoader import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate import org.springframework.boot.test.web.server.LocalServerPort import org.springframework.http.HttpStatus import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.ContextConfiguration - -import com.fasterxml.jackson.core.JsonProcessingException -import com.fasterxml.jackson.core.type.TypeReference -import com.fasterxml.jackson.databind.JsonMappingException -import com.fasterxml.jackson.databind.ObjectMapper - -import spock.lang.Shared import spock.lang.Specification @SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java index 11252b7504..bb2332d615 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java @@ -23,12 +23,12 @@ package org.onap.cps.ncmp.rest.controller; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE; +import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL; +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING; +import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE; +import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE; +import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH; +import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE; import io.micrometer.core.annotation.Timed; import java.util.ArrayList; @@ -37,17 +37,15 @@ import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.NetworkCmProxyFacade; -import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; +import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException; +import org.onap.cps.ncmp.api.data.models.CmResourceAddress; +import org.onap.cps.ncmp.api.data.models.DatastoreType; import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade; import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters; import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; -import org.onap.cps.ncmp.api.models.CmResourceAddress; +import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade; import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi; -import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper; -import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper; import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties; import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters; import org.onap.cps.ncmp.rest.model.DataOperationRequest; @@ -56,7 +54,10 @@ import org.onap.cps.ncmp.rest.model.RestModuleReference; import org.onap.cps.ncmp.rest.model.RestOutputCmHandle; import org.onap.cps.ncmp.rest.model.RestOutputCmHandleCompositeState; import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties; +import org.onap.cps.ncmp.rest.util.CmHandleStateMapper; +import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper; import org.onap.cps.ncmp.rest.util.DeprecationHelper; +import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.utils.JsonObjectMapper; 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 113ee02aa1..8aa86ade36 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 @@ -37,6 +37,7 @@ import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters; import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse; import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse; import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration; +import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandler.java index ba39178c7b..d8c4af53bb 100755..100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandler.java @@ -18,22 +18,20 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.exceptions; +package org.onap.cps.ncmp.rest.controller; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException; +import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException; +import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException; import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; import org.onap.cps.ncmp.api.impl.exception.DmiRequestException; -import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; -import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException; import org.onap.cps.ncmp.api.impl.exception.NcmpException; import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException; import org.onap.cps.ncmp.exceptions.InvalidTopicException; -import org.onap.cps.ncmp.exceptions.OperationNotSupportedException; import org.onap.cps.ncmp.exceptions.PayloadTooLargeException; -import org.onap.cps.ncmp.rest.controller.NetworkCmProxyController; -import org.onap.cps.ncmp.rest.controller.NetworkCmProxyInventoryController; import org.onap.cps.ncmp.rest.model.DmiErrorMessage; import org.onap.cps.ncmp.rest.model.DmiErrorMessageDmiResponse; import org.onap.cps.ncmp.rest.model.ErrorMessage; @@ -79,9 +77,9 @@ public class NetworkCmProxyRestExceptionHandler { return wrapDmiErrorResponse(dmiClientRequestException); } - @ExceptionHandler({DmiRequestException.class, DataValidationException.class, OperationNotSupportedException.class, - HttpMessageNotReadableException.class, InvalidTopicException.class, InvalidDatastoreException.class, - InvalidDmiResourceUrlException.class}) + @ExceptionHandler({DmiRequestException.class, DataValidationException.class, InvalidOperationException.class, + OperationNotSupportedException.class, HttpMessageNotReadableException.class, InvalidTopicException.class, + InvalidDatastoreException.class}) public static ResponseEntity<Object> handleDmiRequestExceptions(final Exception exception) { return buildErrorResponse(HttpStatus.BAD_REQUEST, exception); } diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleStateMapper.java index 3f44ee8528..4abcb72308 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleStateMapper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.mapper; +package org.onap.cps.ncmp.rest.util; import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.LOCKED_MISBEHAVING; diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/DataOperationRequestMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java index 51ee8ca174..42622a2ca2 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/DataOperationRequestMapper.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java @@ -18,14 +18,14 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.mapper; +package org.onap.cps.ncmp.rest.util; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.NullValuePropertyMappingStrategy; -import org.onap.cps.ncmp.api.models.DataOperationDefinition; -import org.onap.cps.ncmp.api.models.DataOperationRequest; +import org.onap.cps.ncmp.api.data.models.DataOperationDefinition; +import org.onap.cps.ncmp.api.data.models.DataOperationRequest; @Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT) diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/NcmpRestInputMapper.java index 7f46c92ec7..b9a814dce4 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/NcmpRestInputMapper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.controller; +package org.onap.cps.ncmp.rest.util; import org.mapstruct.InheritConfiguration; import org.mapstruct.Mapper; diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy index 65d6d8ca76..f7d80ad747 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy @@ -32,20 +32,21 @@ import groovy.json.JsonSlurper import org.mapstruct.factory.Mappers import org.onap.cps.TestUtils import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.NetworkCmProxyFacade +import org.onap.cps.ncmp.api.data.models.CmResourceAddress import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.api.inventory.models.TrustLevel -import org.onap.cps.ncmp.api.models.CmResourceAddress +import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory -import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper -import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper import org.onap.cps.ncmp.rest.model.DataOperationDefinition import org.onap.cps.ncmp.rest.model.DataOperationRequest +import org.onap.cps.ncmp.rest.util.CmHandleStateMapper +import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper import org.onap.cps.ncmp.rest.util.DeprecationHelper +import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper import org.onap.cps.spi.model.ModuleDefinition import org.onap.cps.spi.model.ModuleReference import org.onap.cps.utils.JsonObjectMapper @@ -66,12 +67,12 @@ import java.time.OffsetDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING -import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE -import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE -import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH -import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE +import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE +import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH +import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE import static org.onap.cps.ncmp.api.inventory.models.CompositeState.DataStores import static org.onap.cps.ncmp.api.inventory.models.CompositeState.Operational import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete 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 244ecfaea7..97c68f08f3 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 @@ -32,6 +32,7 @@ import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration +import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy index 10452b8469..b0dca6cc0e 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy @@ -19,23 +19,25 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.exceptions +package org.onap.cps.ncmp.rest.controller import groovy.json.JsonSlurper import org.mapstruct.factory.Mappers import org.onap.cps.TestUtils -import org.onap.cps.ncmp.api.impl.NcmpCachedResourceRequestHandler -import org.onap.cps.ncmp.api.impl.NcmpPassthroughResourceRequestHandler -import org.onap.cps.ncmp.api.impl.NetworkCmProxyFacade +import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException +import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException import org.onap.cps.ncmp.api.impl.exception.DmiRequestException import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade import org.onap.cps.ncmp.exceptions.PayloadTooLargeException -import org.onap.cps.ncmp.rest.controller.NcmpRestInputMapper -import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper -import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper +import org.onap.cps.ncmp.impl.data.NcmpCachedResourceRequestHandler +import org.onap.cps.ncmp.impl.data.NcmpPassthroughResourceRequestHandler +import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade +import org.onap.cps.ncmp.rest.util.CmHandleStateMapper +import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper import org.onap.cps.ncmp.rest.util.DeprecationHelper +import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.CpsException import org.onap.cps.spi.exceptions.DataNodeNotFoundException @@ -51,8 +53,8 @@ import spock.lang.Shared import spock.lang.Specification import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA -import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMP -import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMPINVENTORY +import static org.onap.cps.ncmp.rest.controller.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMP +import static org.onap.cps.ncmp.rest.controller.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMPINVENTORY import static org.springframework.http.HttpStatus.BAD_GATEWAY import static org.springframework.http.HttpStatus.BAD_REQUEST import static org.springframework.http.HttpStatus.CONFLICT @@ -121,16 +123,18 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { then: 'an HTTP response is returned with correct message and details' assertTestResponse(response, expectedErrorCode, expectedErrorMessage, expectedErrorDetails) where: - scenario | exception || expectedErrorCode | expectedErrorMessage | expectedErrorDetails - 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | sampleErrorDetails - 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null - 'NCMP-client' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || BAD_REQUEST | sampleErrorMessage | null - 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | null - 'other' | new IllegalStateException(sampleErrorMessage) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null - 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | 'DataNode not found' - 'Existing entry' | new AlreadyDefinedException('name',null) || CONFLICT | 'Already defined exception' | 'name already exists' - 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || CONFLICT | 'Already defined exception' | '2 data node(s) already exist' - 'Operation too large' | new PayloadTooLargeException(sampleErrorMessage) || PAYLOAD_TOO_LARGE | sampleErrorMessage | 'Check logs' + scenario | exception || expectedErrorCode | expectedErrorMessage | expectedErrorDetails + 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | sampleErrorDetails + 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null + 'DMI Request' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || BAD_REQUEST | sampleErrorMessage | null + 'Invalid Operation' | new InvalidOperationException('some reason') || BAD_REQUEST | 'some reason' | null + 'Unsupported Operation' | new OperationNotSupportedException('not yet') || BAD_REQUEST | 'not yet' | null + 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | null + 'other' | new IllegalStateException(sampleErrorMessage) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null + 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | 'DataNode not found' + 'Existing entry' | new AlreadyDefinedException('name',null) || CONFLICT | 'Already defined exception' | 'name already exists' + 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || CONFLICT | 'Already defined exception' | '2 data node(s) already exist' + 'Operation too large' | new PayloadTooLargeException(sampleErrorMessage) || PAYLOAD_TOO_LARGE | sampleErrorMessage | 'Check logs' } def 'Post request with exception returns correct HTTP Status.'() { diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleStateMapperSpec.groovy index 8d5e91147f..24f45ad8a1 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleStateMapperSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.mapper +package org.onap.cps.ncmp.rest.util import org.mapstruct.factory.Mappers import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/NcmpRestInputMapperSpec.groovy index 41521f6398..3fd7e40345 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/NcmpRestInputMapperSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.rest.controller +package org.onap.cps.ncmp.rest.util import org.mapstruct.factory.Mappers import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDatastoreException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidDatastoreException.java index 6cfa159b20..740785e3be 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDatastoreException.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidDatastoreException.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.exception; +package org.onap.cps.ncmp.api.data.exceptions; public class InvalidDatastoreException extends RuntimeException { /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidOperationException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidOperationException.java index 17069098cb..7669dd05f6 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidOperationException.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidOperationException.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.exception; +package org.onap.cps.ncmp.api.data.exceptions; public class InvalidOperationException extends RuntimeException { /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/OperationNotSupportedException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/OperationNotSupportedException.java index d75c0bd47a..eea846a0f6 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/OperationNotSupportedException.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/OperationNotSupportedException.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.exceptions; +package org.onap.cps.ncmp.api.data.exceptions; public class OperationNotSupportedException extends RuntimeException { /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmResourceAddress.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java index 21d82fcf56..e93aa4c603 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmResourceAddress.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.models; +package org.onap.cps.ncmp.api.data.models; public record CmResourceAddress(String datastoreName, String cmHandleId, String resourceIdentifier) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationDefinition.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java index 366d845832..d1ff1a5815 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationDefinition.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.models; +package org.onap.cps.ncmp.api.data.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationRequest.java index a4d070c38d..b104f587fb 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationRequest.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationRequest.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.models; +package org.onap.cps.ncmp.api.data.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DatastoreType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DatastoreType.java index 6520c05c08..a483341b65 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DatastoreType.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DatastoreType.java @@ -18,14 +18,14 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.api.data.models; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import lombok.Getter; -import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; +import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException; @Getter public enum DatastoreType { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/OperationType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/OperationType.java index e863228ed5..870e24fac4 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/OperationType.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/OperationType.java @@ -18,12 +18,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.api.data.models; import com.fasterxml.jackson.annotation.JsonValue; import java.util.Locale; import lombok.Getter; -import org.onap.cps.ncmp.api.impl.exception.InvalidOperationException; +import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException; @Getter public enum OperationType { 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 d4c5d16a4c..ac7728da92 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 @@ -24,21 +24,18 @@ package org.onap.cps.ncmp.api.impl.client; import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING; import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA; import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR; -import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.REQUEST_TIMEOUT; 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.data.models.OperationType; import org.onap.cps.ncmp.api.impl.config.DmiProperties; import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; -import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException; -import org.onap.cps.ncmp.api.impl.operations.OperationType; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpHeaders; @@ -57,7 +54,6 @@ import reactor.core.publisher.Mono; @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; @@ -74,7 +70,7 @@ public class DmiRestClient { * Sends a synchronous (blocking) POST operation to the DMI with a JSON body containing module references. * * @param requiredDmiService Determines if the required service is for a data or model operation. - * @param dmiUrl The DMI resource URL. + * @param urlTemplateParameters The DMI resource URL template with variables. * @param requestBodyAsJsonString JSON data body. * @param operationType The type of operation being executed (for error reporting only). * @param authorization Contents of the Authorization header, or null if not present. @@ -82,13 +78,14 @@ public class DmiRestClient { * @throws DmiClientRequestException If there is an error during the DMI request. */ public ResponseEntity<Object> synchronousPostOperationWithJsonData(final RequiredDmiService requiredDmiService, - final String dmiUrl, + final UrlTemplateParameters + urlTemplateParameters, final String requestBodyAsJsonString, final OperationType operationType, final String authorization) { final Mono<ResponseEntity<Object>> responseEntityMono = asynchronousPostOperationWithJsonData(requiredDmiService, - dmiUrl, + urlTemplateParameters, requestBodyAsJsonString, operationType, authorization); @@ -99,22 +96,23 @@ public class DmiRestClient { * Asynchronously performs an HTTP POST operation with the given JSON data. * * @param requiredDmiService The service object required for retrieving or configuring the WebClient. - * @param dmiUrl The URL to which the POST request is sent. + * @param urlTemplateParameters The URL template with variables for the POST request. * @param requestBodyAsJsonString The JSON string that will be sent as the request body. * @param operationType An enumeration or object that holds information about the type of operation * being performed. * @param authorization The authorization token to be added to the request headers. * @return A Mono emitting the response entity containing the server's response. */ - public Mono<ResponseEntity<Object>> asynchronousPostOperationWithJsonData( - final RequiredDmiService requiredDmiService, - final String dmiUrl, - final String requestBodyAsJsonString, - final OperationType operationType, - final String authorization) { + public Mono<ResponseEntity<Object>> asynchronousPostOperationWithJsonData(final RequiredDmiService + requiredDmiService, + final UrlTemplateParameters + urlTemplateParameters, + final String requestBodyAsJsonString, + final OperationType operationType, + final String authorization) { final WebClient webClient = getWebClient(requiredDmiService); return webClient.post() - .uri(toUri(dmiUrl)) + .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization)) .body(BodyInserters.fromValue(requestBodyAsJsonString)) .retrieve() @@ -123,25 +121,29 @@ public class DmiRestClient { } /** - * Get DMI plugin health status. + * Retrieves the health status of the DMI plugin. + * This method performs an HTTP GET request to the DMI health check endpoint specified by the URL template + * parameters. If the response status code indicates a client error (4xx) or a server error (5xx), it logs a warning + * and returns an empty Mono. In case of an error during the request, it logs the exception and returns a default + * value of "NOT_SPECIFIED". If the response body contains a JSON node with a "status" field, the value of this + * field is returned. * - * @param dmiUrl the base URL of the dmi-plugin - * @return plugin health status ("UP" is all OK, "" (not-specified) in case of any exception) + * @param urlTemplateParameters the URL template parameters for the DMI health check endpoint + * @return a Mono emitting the health status as a String, or "NOT_SPECIFIED" if an error occurs */ - public String getDmiHealthStatus(final String dmiUrl) { - try { - final URI dmiHealthCheckUri = toUri(dmiUrl + HEALTH_CHECK_URL_EXTENSION); - final JsonNode responseHealthStatus = healthChecksWebClient.get() - .uri(dmiHealthCheckUri) - .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION)) - .retrieve() - .bodyToMono(JsonNode.class).block(); - return responseHealthStatus == null ? NOT_SPECIFIED : - responseHealthStatus.path("status").asText(); - } catch (final Exception e) { - log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiUrl, e.getMessage()); - return NOT_SPECIFIED; - } + public Mono<String> getDmiHealthStatus(final UrlTemplateParameters urlTemplateParameters) { + return healthChecksWebClient.get() + .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) + .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION)) + .retrieve() + .bodyToMono(JsonNode.class) + .map(responseHealthStatus -> responseHealthStatus.path("status").asText()) + .onErrorResume(Exception.class, ex -> { + log.warn("Failed to retrieve health status from {}. Status: {}", + urlTemplateParameters.urlTemplate(), ex.getMessage()); + return Mono.empty(); + }) + .defaultIfEmpty(NOT_SPECIFIED); } private WebClient getWebClient(final RequiredDmiService requiredDmiService) { @@ -156,14 +158,6 @@ public class DmiRestClient { } } - private static URI toUri(final String dmiResourceUrl) { - try { - return new URI(dmiResourceUrl); - } catch (final URISyntaxException e) { - throw new InvalidDmiResourceUrlException(dmiResourceUrl, BAD_REQUEST.value()); - } - } - private DmiClientRequestException handleDmiClientException(final Throwable throwable, final String operationType) { if (throwable instanceof WebClientResponseException webClientResponseException) { if (webClientResponseException.getStatusCode().isSameCodeAs(REQUEST_TIMEOUT)) { 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 index 3a861a68b4..be46105d13 100644 --- 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 @@ -47,68 +47,46 @@ import reactor.netty.resources.ConnectionProvider; public class DmiWebClientConfiguration { private final HttpClientConfiguration httpClientConfiguration; - private static final Duration DEFAULT_RESPONSE_TIMEOUT = Duration.ofSeconds(30); /** - * Configures and creates a WebClient bean for DMI data services. + * Configures and creates a web client bean for DMI data services. * + * @param webClientBuilder The builder instance to create the WebClient. * @return a WebClient instance configured for data services. */ @Bean - public WebClient dataServicesWebClient() { - final HttpClientConfiguration.DataServices dataServiceConfig = httpClientConfiguration.getDataServices(); - final ConnectionProvider dataServicesConnectionProvider - = getConnectionProvider(dataServiceConfig.getConnectionProviderName(), - dataServiceConfig.getMaximumConnectionsTotal(), dataServiceConfig.getPendingAcquireMaxCount()); - final HttpClient dataServicesHttpClient = createHttpClient(dataServiceConfig, dataServicesConnectionProvider); - return buildAndGetWebClient(dataServicesHttpClient, dataServiceConfig.getMaximumInMemorySizeInMegabytes()); + public WebClient dataServicesWebClient(final WebClient.Builder webClientBuilder) { + return configureWebClient(webClientBuilder, httpClientConfiguration.getDataServices()); } /** - * Configures and creates a WebClient bean for DMI model services. + * Configures and creates a web client bean for DMI model services. * + * @param webClientBuilder The builder instance to create the WebClient. * @return a WebClient instance configured for model services. */ @Bean - public WebClient modelServicesWebClient() { - final HttpClientConfiguration.ModelServices modelServiceConfig = httpClientConfiguration.getModelServices(); - final ConnectionProvider modelServicesConnectionProvider - = getConnectionProvider(modelServiceConfig.getConnectionProviderName(), - modelServiceConfig.getMaximumConnectionsTotal(), - modelServiceConfig.getPendingAcquireMaxCount()); - final HttpClient modelServicesHttpClient - = createHttpClient(modelServiceConfig, modelServicesConnectionProvider); - return buildAndGetWebClient(modelServicesHttpClient, modelServiceConfig.getMaximumInMemorySizeInMegabytes()); + public WebClient modelServicesWebClient(final WebClient.Builder webClientBuilder) { + return configureWebClient(webClientBuilder, httpClientConfiguration.getModelServices()); } /** - * Configures and creates a WebClient bean for DMI health check services. + * Configures and creates a web client bean for DMI health check services. * + * @param webClientBuilder The builder instance to create the WebClient. * @return a WebClient instance configured for health check services. */ @Bean - public WebClient healthChecksWebClient() { - final HttpClientConfiguration.HealthCheckServices healthCheckServiceConfig - = httpClientConfiguration.getHealthCheckServices(); - final ConnectionProvider healthChecksConnectionProvider - = getConnectionProvider(healthCheckServiceConfig.getConnectionProviderName(), - healthCheckServiceConfig.getMaximumConnectionsTotal(), - healthCheckServiceConfig.getPendingAcquireMaxCount()); - final HttpClient healthChecksHttpClient - = createHttpClient(healthCheckServiceConfig, healthChecksConnectionProvider); - return buildAndGetWebClient(healthChecksHttpClient, - healthCheckServiceConfig.getMaximumInMemorySizeInMegabytes()); + public WebClient healthChecksWebClient(final WebClient.Builder webClientBuilder) { + return configureWebClient(webClientBuilder, httpClientConfiguration.getHealthCheckServices()); } - /** - * Provides a WebClient.Builder bean for creating WebClient instances. - * - * @return a WebClient.Builder instance. - */ - @Bean - public WebClient.Builder webClientBuilder() { - return WebClient.builder(); + private WebClient configureWebClient(final WebClient.Builder webClientBuilder, + final HttpClientConfiguration.ServiceConfig serviceConfig) { + final ConnectionProvider connectionProvider = getConnectionProvider(serviceConfig); + final HttpClient httpClient = createHttpClient(serviceConfig, connectionProvider); + return buildAndGetWebClient(webClientBuilder, httpClient, serviceConfig.getMaximumInMemorySizeInMegabytes()); } private static HttpClient createHttpClient(final HttpClientConfiguration.ServiceConfig serviceConfig, @@ -124,18 +102,16 @@ public class DmiWebClientConfiguration { } @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE") - private static ConnectionProvider getConnectionProvider(final String connectionProviderName, - final int maximumConnectionsTotal, - final int pendingAcquireMaxCount) { - return ConnectionProvider.builder(connectionProviderName) - .maxConnections(maximumConnectionsTotal) - .pendingAcquireMaxCount(pendingAcquireMaxCount) + private static ConnectionProvider getConnectionProvider(final HttpClientConfiguration.ServiceConfig serviceConfig) { + return ConnectionProvider.builder(serviceConfig.getConnectionProviderName()) + .maxConnections(serviceConfig.getMaximumConnectionsTotal()) + .pendingAcquireMaxCount(serviceConfig.getPendingAcquireMaxCount()) .build(); } - private WebClient buildAndGetWebClient(final HttpClient httpClient, - final int maximumInMemorySizeInMegabytes) { - return webClientBuilder() + private WebClient buildAndGetWebClient(final WebClient.Builder webClientBuilder, final HttpClient httpClient, + final int maximumInMemorySizeInMegabytes) { + return webClientBuilder .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)) diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.java deleted file mode 100644 index 4e2062fed6..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.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.events.cmsubscription; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate; -import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class CmNotificationSubscriptionDelta { - - private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService; - - /** - * Get the delta for a given predicates list. - * - * @param dmiCmNotificationSubscriptionPredicates list of DmiCmNotificationSubscriptionPredicates - * @return delta list of DmiCmNotificationSubscriptionPredicates - */ - public List<DmiCmNotificationSubscriptionPredicate> getDelta( - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) { - final List<DmiCmNotificationSubscriptionPredicate> delta = new ArrayList<>(); - - for (final DmiCmNotificationSubscriptionPredicate cmNotificationSubscriptionPredicate: - dmiCmNotificationSubscriptionPredicates) { - - final Set<String> targetCmHandleIds = new HashSet<>(); - final Set<String> xpaths = new HashSet<>(); - final DatastoreType datastoreType = cmNotificationSubscriptionPredicate.getDatastoreType(); - - for (final String cmHandleId : cmNotificationSubscriptionPredicate.getTargetCmHandleIds()) { - for (final String xpath : cmNotificationSubscriptionPredicate.getXpaths()) { - if (!cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType, - cmHandleId, xpath)) { - xpaths.add(xpath); - targetCmHandleIds.add(cmHandleId); - - } - } - } - - populateValidDmiCmNotificationSubscriptionPredicateDelta(targetCmHandleIds, xpaths, datastoreType, delta); - } - return delta; - } - - private void populateValidDmiCmNotificationSubscriptionPredicateDelta(final Set<String> targetCmHandleIds, - final Set<String> xpaths, final DatastoreType datastoreType, - final List<DmiCmNotificationSubscriptionPredicate> delta) { - if (!(targetCmHandleIds.isEmpty() || xpaths.isEmpty())) { - final DmiCmNotificationSubscriptionPredicate predicateDelta = - new DmiCmNotificationSubscriptionPredicate(targetCmHandleIds, datastoreType, xpaths); - delta.add(predicateDelta); - } - } - -} 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 deleted file mode 100644 index 50a5df537d..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java +++ /dev/null @@ -1,70 +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.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 deleted file mode 100644 index 73f9563ecf..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java +++ /dev/null @@ -1,78 +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.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 deleted file mode 100644 index f7dd51e637..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java +++ /dev/null @@ -1,63 +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.events.cmsubscription; - -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.model.DmiCmNotificationSubscriptionDetails; -import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent; -import org.onap.cps.utils.JsonObjectMapper; - -@Slf4j -@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 CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler; - private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler; - - /** - * Delegating the responsibility of publishing CmNotificationSubscriptionNcmpOutEvent as a separate task which will - * be called after a specified delay. - */ - @Override - public void run() { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap = - dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId); - final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent = - cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId, - dmiCmNotificationSubscriptionDetailsMap); - eventsPublisher.publishCloudEvent(topicName, subscriptionId, - buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, - cmNotificationSubscriptionNcmpOutEvent)); - dmiCmNotificationSubscriptionCacheHandler - .removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java deleted file mode 100644 index 051949c5e8..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java +++ /dev/null @@ -1,123 +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.events.cmsubscription.consumer; - -import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_ACCEPTED; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_REJECTED; -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.NcmpResponseStatus; -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.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.Data; -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; - -@Component -@Slf4j -@RequiredArgsConstructor -public class CmNotificationSubscriptionDmiOutEventConsumer { - - private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler; - private final CmNotificationSubscriptionEventsHandler cmNotificationSubscriptionEventsHandler; - private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler; - - private static final String CM_DATA_SUBSCRIPTION_CORRELATION_ID_SEPARATOR = "#"; - - /** - * Consume the Cm Notification Subscription event from the dmi-plugin. - * - * @param cmNotificationSubscriptionDmiOutEventConsumerRecord the event to be consumed - */ - @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-dmi-out}", - containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeCmNotificationSubscriptionDmiOutEvent( - final ConsumerRecord<String, CloudEvent> cmNotificationSubscriptionDmiOutEventConsumerRecord) { - final CloudEvent cloudEvent = cmNotificationSubscriptionDmiOutEventConsumerRecord.value(); - final CmNotificationSubscriptionDmiOutEvent cmNotificationSubscriptionDmiOutEvent = - toTargetEvent(cloudEvent, CmNotificationSubscriptionDmiOutEvent.class); - final String correlationId = String.valueOf(cloudEvent.getExtension("correlationid")); - if (cmNotificationSubscriptionDmiOutEvent != null && correlationId != null) { - final String eventType = cloudEvent.getType(); - handleCmSubscriptionDmiOutEvent(correlationId, eventType, cmNotificationSubscriptionDmiOutEvent); - } - } - - private void handleCmSubscriptionDmiOutEvent(final String correlationId, - final String eventType, - final CmNotificationSubscriptionDmiOutEvent - cmNotificationSubscriptionDmiOutEvent) { - final String subscriptionId = correlationId.split(CM_DATA_SUBSCRIPTION_CORRELATION_ID_SEPARATOR)[0]; - final String dmiPluginName = correlationId.split(CM_DATA_SUBSCRIPTION_CORRELATION_ID_SEPARATOR)[1]; - - if (checkStatusCodeAndMessage(CM_DATA_SUBSCRIPTION_ACCEPTED, cmNotificationSubscriptionDmiOutEvent.getData())) { - handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmNotificationSubscriptionStatus.ACCEPTED); - if (eventType.equals("subscriptionCreateResponse")) { - dmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName); - } - if (eventType.equals("subscriptionDeleteResponse")) { - dmiCmNotificationSubscriptionCacheHandler.removeFromDatabasePerDmi(subscriptionId, dmiPluginName); - } - handleEventsStatusPerDmi(subscriptionId, eventType); - } - - if (checkStatusCodeAndMessage(CM_DATA_SUBSCRIPTION_REJECTED, cmNotificationSubscriptionDmiOutEvent.getData())) { - handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmNotificationSubscriptionStatus.REJECTED); - handleEventsStatusPerDmi(subscriptionId, eventType); - } - - log.info("Cm Subscription with id : {} handled by the dmi-plugin : {} has the status : {}", subscriptionId, - dmiPluginName, cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage()); - } - - private void handleCacheStatusPerDmi(final String subscriptionId, final String dmiPluginName, - final CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus) { - dmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi(subscriptionId, - dmiPluginName, cmNotificationSubscriptionStatus); - } - - private void handleEventsStatusPerDmi(final String subscriptionId, final String eventType) { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi = - dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId); - final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent = - cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId, - dmiCmNotificationSubscriptionDetailsPerDmi); - cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, - eventType, cmNotificationSubscriptionNcmpOutEvent, false); - } - - private boolean checkStatusCodeAndMessage(final NcmpResponseStatus ncmpResponseStatus, - final Data cmNotificationSubscriptionDmiOutData) { - return ncmpResponseStatus.getCode().equals(cmNotificationSubscriptionDmiOutData.getStatusCode()) - && ncmpResponseStatus.getMessage() - .equals(cmNotificationSubscriptionDmiOutData.getStatusMessage()); - } -}
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java deleted file mode 100644 index ea21751691..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java +++ /dev/null @@ -1,114 +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.events.cmsubscription.mapper; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import lombok.RequiredArgsConstructor; -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.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate; -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; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class CmNotificationSubscriptionNcmpOutEventMapper { - - /** - * 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) { - - final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent = - new CmNotificationSubscriptionNcmpOutEvent(); - final Data cmSubscriptionData = new Data(); - cmSubscriptionData.setSubscriptionId(subscriptionId); - populateCmNotificationSubscriptionNcmpOutEventWithCmHandleIds(dmiCmNotificationSubscriptionDetailsMap, - cmSubscriptionData); - cmNotificationSubscriptionNcmpOutEvent.setData(cmSubscriptionData); - - return cmNotificationSubscriptionNcmpOutEvent; - } - - /** - * 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) { - final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent = - new CmNotificationSubscriptionNcmpOutEvent(); - final Data cmSubscriptionData = new Data(); - cmSubscriptionData.setSubscriptionId(subscriptionId); - cmSubscriptionData.setRejectedTargets(rejectedTargetFilters); - cmNotificationSubscriptionNcmpOutEvent.setData(cmSubscriptionData); - return cmNotificationSubscriptionNcmpOutEvent; - } - - private void populateCmNotificationSubscriptionNcmpOutEventWithCmHandleIds( - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap, - final Data cmSubscriptionData) { - - final List<String> acceptedCmHandleIds = new ArrayList<>(); - final List<String> pendingCmHandleIds = new ArrayList<>(); - final List<String> rejectedCmHandleIds = new ArrayList<>(); - - dmiCmNotificationSubscriptionDetailsMap.forEach((dmiPluginName, dmiCmNotificationSubscriptionDetails) -> { - final CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus = - dmiCmNotificationSubscriptionDetails.getCmNotificationSubscriptionStatus(); - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates = - dmiCmNotificationSubscriptionDetails.getDmiCmNotificationSubscriptionPredicates(); - - switch (cmNotificationSubscriptionStatus) { - case ACCEPTED -> acceptedCmHandleIds.addAll( - extractCmHandleIds(dmiCmNotificationSubscriptionPredicates)); - case PENDING -> pendingCmHandleIds.addAll(extractCmHandleIds(dmiCmNotificationSubscriptionPredicates)); - default -> rejectedCmHandleIds.addAll(extractCmHandleIds(dmiCmNotificationSubscriptionPredicates)); - } - }); - - cmSubscriptionData.setAcceptedTargets(acceptedCmHandleIds); - cmSubscriptionData.setPendingTargets(pendingCmHandleIds); - cmSubscriptionData.setRejectedTargets(rejectedCmHandleIds); - - } - - private List<String> extractCmHandleIds( - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) { - final List<String> cmHandleIds = new ArrayList<>(); - dmiCmNotificationSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> cmHandleIds.addAll( - dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds())); - - return cmHandleIds; - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java deleted file mode 100644 index ed7ed2a0ba..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java +++ /dev/null @@ -1,146 +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.events.cmsubscription.producer; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; -import java.net.URI; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -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.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; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) -public class CmNotificationSubscriptionNcmpOutEventProducer { - - @Value("${app.ncmp.avc.cm-subscription-ncmp-out}") - private String cmNotificationSubscriptionNcmpOutEventTopic; - - @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms}") - private Integer cmNotificationSubscriptionDmiOutEventTimeoutInMs; - - private final EventsPublisher<CloudEvent> eventsPublisher; - private final JsonObjectMapper jsonObjectMapper; - private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler; - private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler; - private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); - private static final Map<String, ScheduledFuture<?>> scheduledTasksPerSubscriptionId = new ConcurrentHashMap<>(); - - /** - * 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) { - - if (isScheduledEvent && !scheduledTasksPerSubscriptionId.containsKey(subscriptionId)) { - final ScheduledFuture<?> scheduledFuture = - scheduleAndPublishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType); - scheduledTasksPerSubscriptionId.putIfAbsent(subscriptionId, scheduledFuture); - log.debug("Scheduled the CmNotificationSubscriptionEvent for subscriptionId : {}", subscriptionId); - } else { - cancelScheduledTaskForSubscriptionId(subscriptionId); - publishCmNotificationSubscriptionNcmpOutEventNow(subscriptionId, eventType, - cmNotificationSubscriptionNcmpOutEvent); - log.info("Published CmNotificationSubscriptionEvent on demand for subscriptionId : {}", subscriptionId); - } - } - - private ScheduledFuture<?> scheduleAndPublishCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId, - final String eventType) { - final CmNotificationSubscriptionNcmpOutEventPublishingTask - cmNotificationSubscriptionNcmpOutEventPublishingTask = - new CmNotificationSubscriptionNcmpOutEventPublishingTask(cmNotificationSubscriptionNcmpOutEventTopic, - subscriptionId, eventType, eventsPublisher, jsonObjectMapper, - cmNotificationSubscriptionMappersHandler, dmiCmNotificationSubscriptionCacheHandler); - return scheduledExecutorService.schedule(cmNotificationSubscriptionNcmpOutEventPublishingTask, - cmNotificationSubscriptionDmiOutEventTimeoutInMs, TimeUnit.MILLISECONDS); - } - - private void cancelScheduledTaskForSubscriptionId(final String subscriptionId) { - - final ScheduledFuture<?> scheduledFuture = scheduledTasksPerSubscriptionId.get(subscriptionId); - if (scheduledFuture != null) { - scheduledFuture.cancel(true); - scheduledTasksPerSubscriptionId.remove(subscriptionId); - } - - } - - - private void publishCmNotificationSubscriptionNcmpOutEventNow(final String subscriptionId, final String eventType, - final CmNotificationSubscriptionNcmpOutEvent - cmNotificationSubscriptionNcmpOutEvent) { - final CloudEvent cmNotificationSubscriptionNcmpOutEventAsCloudEvent = - buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, - cmNotificationSubscriptionNcmpOutEvent); - eventsPublisher.publishCloudEvent(cmNotificationSubscriptionNcmpOutEventTopic, subscriptionId, - cmNotificationSubscriptionNcmpOutEventAsCloudEvent); - dmiCmNotificationSubscriptionCacheHandler - .removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId); - } - - /** - * 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) { - - return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType) - .withSource(URI.create("NCMP")).withDataSchema(URI.create("org.onap.ncmp.cm.subscription:1.0.0")) - .withExtension("correlationid", subscriptionId) - .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionNcmpOutEvent)).build(); - } - -} 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 deleted file mode 100644 index 08e3c95529..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java +++ /dev/null @@ -1,134 +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.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.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.model.CmNotificationSubscriptionStatus; -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.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; - -@Service -@RequiredArgsConstructor -public class CmNotificationSubscriptionHandlerServiceImpl implements CmNotificationSubscriptionHandlerService { - - private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService; - private final CmNotificationSubscriptionDelta cmNotificationSubscriptionDelta; - private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler; - private final CmNotificationSubscriptionEventsHandler cmNotificationSubscriptionEventsHandler; - private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler; - - @Override - public void processSubscriptionCreateRequest(final String subscriptionId, final List<Predicate> predicates) { - if (cmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId(subscriptionId)) { - dmiCmNotificationSubscriptionCacheHandler.add(subscriptionId, predicates); - handleCmNotificationSubscriptionDelta(subscriptionId); - scheduleCmNotificationSubscriptionNcmpOutEventResponse(subscriptionId, - "subscriptionCreateResponse"); - } else { - rejectAndPublishCmNotificationSubscriptionCreateRequest(subscriptionId, predicates); - } - } - - @Override - public void processSubscriptionDeleteRequest(final String subscriptionId, final List<Predicate> predicates) { - dmiCmNotificationSubscriptionCacheHandler.add(subscriptionId, predicates); - sendSubscriptionDeleteRequestToDmi(subscriptionId); - scheduleCmNotificationSubscriptionNcmpOutEventResponse(subscriptionId, "subscriptionDeleteResponse"); - } - - private void scheduleCmNotificationSubscriptionNcmpOutEventResponse(final String subscriptionId, - final String eventType) { - cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, - eventType, null, true); - } - - private void rejectAndPublishCmNotificationSubscriptionCreateRequest(final String subscriptionId, - final List<Predicate> predicates) { - final Set<String> subscriptionTargetFilters = - predicates.stream().flatMap(predicate -> predicate.getTargetFilter().stream()) - .collect(Collectors.toSet()); - final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent = - cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest( - subscriptionId, new ArrayList<>(subscriptionTargetFilters)); - cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, - "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false); - } - - private void handleCmNotificationSubscriptionDelta(final String subscriptionId) { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap = - dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId); - dmiCmNotificationSubscriptionDetailsMap.forEach((dmiPluginName, dmiCmNotificationSubscriptionDetails) -> { - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates = - cmNotificationSubscriptionDelta.getDelta( - dmiCmNotificationSubscriptionDetails.getDmiCmNotificationSubscriptionPredicates()); - - if (dmiCmNotificationSubscriptionPredicates.isEmpty()) { - acceptAndPublishCmNotificationSubscriptionNcmpOutEventPerDmi(subscriptionId, dmiPluginName); - } else { - publishCmNotificationSubscriptionDmiInEventPerDmi(subscriptionId, dmiPluginName, - dmiCmNotificationSubscriptionPredicates); - } - }); - } - - private void publishCmNotificationSubscriptionDmiInEventPerDmi(final String subscriptionId, - final String dmiPluginName, - final List<DmiCmNotificationSubscriptionPredicate> - dmiCmNotificationSubscriptionPredicates) { - final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent = - cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionDmiInEvent( - dmiCmNotificationSubscriptionPredicates); - cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(subscriptionId, - dmiPluginName, "subscriptionCreateRequest", cmNotificationSubscriptionDmiInEvent); - } - - private void acceptAndPublishCmNotificationSubscriptionNcmpOutEventPerDmi(final String subscriptionId, - final String dmiPluginName) { - dmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi(subscriptionId, - dmiPluginName, CmNotificationSubscriptionStatus.ACCEPTED); - dmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName); - } - - private void sendSubscriptionDeleteRequestToDmi(final String subscriptionId) { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap = - dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId); - dmiCmNotificationSubscriptionDetailsMap.forEach((dmiPluginName, dmiCmNotificationSubscriptionDetails) -> { - final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent = - cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionDmiInEvent( - dmiCmNotificationSubscriptionDetails.getDmiCmNotificationSubscriptionPredicates()); - cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(subscriptionId, - dmiPluginName, "subscriptionDeleteRequest", cmNotificationSubscriptionDmiInEvent); - }); - } -}
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java deleted file mode 100644 index 3bb40c3b7e..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java +++ /dev/null @@ -1,84 +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.events.cmsubscription.service; - -import java.util.Collection; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; - -public interface CmNotificationSubscriptionPersistenceService { - - String NCMP_DATASPACE_NAME = "NCMP-Admin"; - String CM_SUBSCRIPTIONS_ANCHOR_NAME = "cm-data-subscriptions"; - - /** - * Check if we have an ongoing cm subscription based on the parameters. - * - * @param datastoreType the susbcription target datastore type - * @param cmHandleId the id of the cm handle for the susbcription - * @param xpath the target xpath - * @return true for ongoing cmsubscription , otherwise false - */ - boolean isOngoingCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId, - final String xpath); - - /** - * Check if the subscription ID is unique against ongoing subscriptions. - * - * @param subscriptionId subscription ID - * @return true if subscriptionId is not used in active subscriptions, otherwise false - */ - boolean isUniqueSubscriptionId(final String subscriptionId); - - /** - * Get all ongoing cm notification subscription based on the parameters. - * - * @param datastoreType the susbcription target datastore type - * @param cmHandleId the id of the cm handle for the susbcription - * @param xpath the target xpath - * @return collection of subscription ids of ongoing cm notification subscription - */ - Collection<String> getOngoingCmNotificationSubscriptionIds(final DatastoreType datastoreType, - final String cmHandleId, final String xpath); - - /** - * Add cm notification subscription. - * - * @param datastoreType the susbcription target datastore type - * @param cmHandleId the id of the cm handle for the susbcription - * @param xpath the target xpath - * @param newSubscriptionId subscription id to be added - */ - void addCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId, - final String xpath, final String newSubscriptionId); - - /** - * Remove cm notification Subscription. - * - * @param datastoreType the susbcription target datastore type - * @param cmHandleId the id of the cm handle for the susbcription - * @param xpath the target xpath - * @param subscriptionId subscription id to remove - */ - void removeCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId, - final String xpath, final String subscriptionId); - -} - diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java deleted file mode 100644 index 270988b63b..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java +++ /dev/null @@ -1,37 +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.exception; - -import lombok.Getter; - -@Getter -public class InvalidDmiResourceUrlException extends RuntimeException { - - private static final long serialVersionUID = 2928476384584894968L; - - private static final String INVALID_DMI_URL = "Invalid dmi resource url"; - final Integer httpStatus; - - public InvalidDmiResourceUrlException(final String details, final Integer httpStatus) { - super(String.format(INVALID_DMI_URL + ": %s", details)); - this.httpStatus = httpStatus; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java index 533e15b918..67880648bc 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java @@ -27,8 +27,8 @@ import java.util.Map; import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class DmiServiceNameOrganizer { 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 deleted file mode 100644 index aeeeb6430f..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-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.utils; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import lombok.NoArgsConstructor; -import org.apache.logging.log4j.util.Strings; -import org.springframework.web.util.UriComponentsBuilder; - -@NoArgsConstructor -public class DmiServiceUrlBuilder { - - private static final String FIXED_PATH_SEGMENT = null; - - final UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); - final Map<String, Object> pathSegments = new LinkedHashMap<>(); - - public static DmiServiceUrlBuilder newInstance() { - return new DmiServiceUrlBuilder(); - } - - /** - * Add a fixed pathSegment to the URI. - * - * @param pathSegment the path segment - * @return this builder - */ - public DmiServiceUrlBuilder pathSegment(final String pathSegment) { - pathSegments.put(pathSegment, FIXED_PATH_SEGMENT); - return this; - } - - /** - * Add a variable pathSegment to the URI. - * Do NOT add { } braces. the builder will take care of that - * - * @param pathSegment the name of the variable path segment (with { and } - * @param value the value to be insert in teh URI for the given variable path segment - * @return this builder - */ - public DmiServiceUrlBuilder variablePathSegment(final String pathSegment, final Object value) { - pathSegments.put(pathSegment, value); - return this; - } - - /** - * Add a query parameter to the URI. - * Do NOT encode as the builder wil take care of encoding - * - * @param name the name of the variable - * @param value the value of the variable (only Strings are supported). - * - * @return this builder - */ - public DmiServiceUrlBuilder queryParameter(final String name, final String value) { - if (Strings.isNotBlank(value)) { - uriComponentsBuilder.queryParam(name, value); - } - return this; - } - - /** - * Build the URI as a correctly percentage-encoded String. - * - * @param dmiServiceName the name of the dmi service - * @param dmiBasePath the base path of the dmi service - * - * @return URI as a string - */ - public String build(final String dmiServiceName, final String dmiBasePath) { - uriComponentsBuilder - .path("{dmiServiceName}") - .pathSegment("{dmiBasePath}") - .pathSegment("v1"); - - final Map<String, Object> uriVariables = new HashMap<>(); - uriVariables.put("dmiServiceName", dmiServiceName); - uriVariables.put("dmiBasePath", dmiBasePath); - - pathSegments.forEach((pathSegment, variablePathValue) -> { - if (variablePathValue == FIXED_PATH_SEGMENT) { - uriComponentsBuilder.pathSegment(pathSegment); - } else { - uriComponentsBuilder.pathSegment("{" + pathSegment + "}"); - uriVariables.put(pathSegment, variablePathValue); - } - }); - return uriComponentsBuilder.buildAndExpand(uriVariables).encode().toUriString(); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java new file mode 100644 index 0000000000..b89b7b3221 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java @@ -0,0 +1,137 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-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.utils.url.builder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; +import org.springframework.web.util.UriComponentsBuilder; + +@NoArgsConstructor +public class DmiServiceUrlTemplateBuilder { + + private final UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); + private static final String FIXED_PATH_SEGMENT = null; + private static final String VERSION_SEGMENT = "v1"; + private final Map<String, String> pathSegments = new LinkedHashMap<>(); + private final Map<String, String> queryParameters = new LinkedHashMap<>(); + + /** + * Static factory method to create a new instance of DmiServiceUrlTemplateBuilder. + * + * @return a new instance of DmiServiceUrlTemplateBuilder + */ + public static DmiServiceUrlTemplateBuilder newInstance() { + return new DmiServiceUrlTemplateBuilder(); + } + + /** + * Add a fixed pathSegment to the URL. + * + * @param pathSegment the path segment + * @return this builder instance + */ + public DmiServiceUrlTemplateBuilder fixedPathSegment(final String pathSegment) { + pathSegments.put(pathSegment, FIXED_PATH_SEGMENT); + return this; + } + + /** + * Add a variable pathSegment to the URL. + * Do NOT add { } braces. the builder will take care of that + * + * @param pathSegment the name of the variable path segment (with { and } + * @param value the value to be insert in teh URL for the given variable path segment + * @return this builder instance + */ + public DmiServiceUrlTemplateBuilder variablePathSegment(final String pathSegment, final String value) { + pathSegments.put(pathSegment, value); + return this; + } + + /** + * Add a query parameter to the URL. + * Do NOT encode as the builder wil take care of encoding + * + * @param queryParameterName the name of the variable + * @param queryParameterValue the value of the variable (only Strings are supported). + * + * @return this builder instance + */ + public DmiServiceUrlTemplateBuilder queryParameter(final String queryParameterName, + final String queryParameterValue) { + if (Strings.isNotBlank(queryParameterValue)) { + queryParameters.put(queryParameterName, queryParameterValue); + } + return this; + } + + /** + * Constructs a URL template with variables based on the accumulated path segments and query parameters. + * + * @param dmiServiceBaseUrl the base URL of the DMI service, e.g., "http://dmi-service.com". + * @param dmiBasePath the base path of the DMI service + * @return a UrlTemplateParameters instance containing the complete URL template and URL variables + */ + public UrlTemplateParameters createUrlTemplateParameters(final String dmiServiceBaseUrl, final String dmiBasePath) { + this.uriComponentsBuilder.pathSegment(dmiBasePath) + .pathSegment(VERSION_SEGMENT); + + final Map<String, String> urlTemplateVariables = new HashMap<>(); + + pathSegments.forEach((pathSegmentName, variablePathValue) -> { + if (StringUtils.equals(variablePathValue, FIXED_PATH_SEGMENT)) { + this.uriComponentsBuilder.pathSegment(pathSegmentName); + } else { + this.uriComponentsBuilder.pathSegment("{" + pathSegmentName + "}"); + urlTemplateVariables.put(pathSegmentName, variablePathValue); + } + }); + + queryParameters.forEach((paramName, paramValue) -> { + this.uriComponentsBuilder.queryParam(paramName, "{" + paramName + "}"); + urlTemplateVariables.put(paramName, paramValue); + }); + + final String urlTemplate = dmiServiceBaseUrl + this.uriComponentsBuilder.build().toUriString(); + return new UrlTemplateParameters(urlTemplate, urlTemplateVariables); + } + + /** + * Constructs a URL for DMI health check based on the given base URL. + * + * @param dmiServiceBaseUrl the base URL of the DMI service, e.g., "http://dmi-service.com". + * @return a {@link UrlTemplateParameters} instance containing the complete URL template and empty URL variables, + * suitable for DMI health check. + */ + public UrlTemplateParameters createUrlTemplateParametersForHealthCheck(final String dmiServiceBaseUrl) { + this.uriComponentsBuilder.pathSegment("actuator") + .pathSegment("health"); + + final String urlTemplate = dmiServiceBaseUrl + this.uriComponentsBuilder.build().toUriString(); + return new UrlTemplateParameters(urlTemplate, Collections.emptyMap()); + } + +} diff --git a/k6-tests/ncmp/2-wait-for-cmhandles-to-be-ready.js b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/UrlTemplateParameters.java index cce85ab7cb..edf56197b5 100644 --- a/k6-tests/ncmp/2-wait-for-cmhandles-to-be-ready.js +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/UrlTemplateParameters.java @@ -18,25 +18,13 @@ * ============LICENSE_END========================================================= */ -import { makeCustomSummaryReport } from './common/utils.js'; -import { waitForCmHandlesToBeReady } from './common/cmhandle-crud.js'; +package org.onap.cps.ncmp.api.impl.utils.url.builder; -export const options = { - vus: 1, - iterations: 1, - thresholds: { - http_req_failed: ['rate == 0'], - iteration_duration: ['max <= 260000'], // 4m20s - }, -}; +import java.util.Map; -export default function () { - const timeOutInSeconds = 6 * 60; - waitForCmHandlesToBeReady(timeOutInSeconds); -} - -export function handleSummary(data) { - return { - stdout: makeCustomSummaryReport(data, options), - }; +/** + * Represents a URL template with associated variables for dynamic substitution. + * This record encapsulates a URL template string and a map of variables used for substitution within the template. + */ +public record UrlTemplateParameters(String urlTemplate, Map<String, String> urlVariables) { } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java deleted file mode 100644 index e527d99f2f..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java +++ /dev/null @@ -1,76 +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.yangmodels; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * Subscription event model to persist data into DB. - * Yang model subscription event - */ -@Getter -@Setter -@NoArgsConstructor -@JsonInclude(Include.NON_NULL) -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -public class YangModelCmDataSubscriptionEvent { - - @EqualsAndHashCode.Include - @JsonProperty("name") - private String name; - - private List<CmHandle> cmHandles; - - @AllArgsConstructor - @Data - @JsonInclude(JsonInclude.Include.NON_NULL) - public static class CmHandle { - - @JsonProperty() - private final String id; - - private final List<Filter> filters; - } - - @AllArgsConstructor - @Data - @JsonInclude(JsonInclude.Include.NON_NULL) - public static class Filter { - - @JsonProperty() - private final String id; - - @JsonProperty() - private final List<String> subscribers; - } -} - - diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfig.java index 1d6da90a9a..a4f9be357f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfig.java @@ -18,18 +18,18 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.config.embeddedcache; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache; import com.hazelcast.config.MapConfig; import com.hazelcast.map.IMap; import java.util.Map; import org.onap.cps.cache.HazelcastCacheConfig; -import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration -public class CmNotificationSubscriptionCacheConfig extends HazelcastCacheConfig { +public class CmSubscriptionConfig extends HazelcastCacheConfig { private static final MapConfig cmNotificationSubscriptionCacheMapConfig = createMapConfig("cmNotificationSubscriptionCacheMapConfig"); @@ -42,7 +42,7 @@ public class CmNotificationSubscriptionCacheConfig extends HazelcastCacheConfig * @return configured map of subscription events. */ @Bean - public IMap<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache() { + public IMap<String, Map<String, DmiCmSubscriptionDetails>> cmNotificationSubscriptionCache() { return createHazelcastInstance("hazelCastInstanceCmNotificationSubscription", cmNotificationSubscriptionCacheMapConfig).getMap("cmNotificationSubscriptionCache"); } 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/impl/cmnotificationsubscription/cache/DmiCacheHandler.java index 21c26228bc..c5052f1405 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/impl/cmnotificationsubscription/cache/DmiCacheHandler.java @@ -18,9 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache; -import static org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus.PENDING; +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING; import java.util.ArrayList; import java.util.Collection; @@ -31,22 +31,22 @@ 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.model.CmNotificationSubscriptionStatus; -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.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.Predicate; +import org.onap.cps.ncmp.api.data.models.DatastoreType; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class DmiCmNotificationSubscriptionCacheHandler { +public class DmiCacheHandler { - private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService; - private final Map<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache; + private final CmSubscriptionPersistenceService cmSubscriptionPersistenceService; + private final Map<String, Map<String, DmiCmSubscriptionDetails>> cmNotificationSubscriptionCache; private final InventoryPersistence inventoryPersistence; /** @@ -56,7 +56,7 @@ public class DmiCmNotificationSubscriptionCacheHandler { * @param predicates subscription request predicates */ public void add(final String subscriptionId, final List<Predicate> predicates) { - cmNotificationSubscriptionCache.put(subscriptionId, createDmiCmNotificationSubscriptionsPerDmi(predicates)); + cmNotificationSubscriptionCache.put(subscriptionId, createDmiSubscriptionsPerDmi(predicates)); } /** @@ -65,7 +65,7 @@ public class DmiCmNotificationSubscriptionCacheHandler { * @param subscriptionId subscription id * @return map of dmi cm notification subscriptions per dmi */ - public Map<String, DmiCmNotificationSubscriptionDetails> get(final String subscriptionId) { + public Map<String, DmiCmSubscriptionDetails> get(final String subscriptionId) { return cmNotificationSubscriptionCache.get(subscriptionId); } @@ -75,15 +75,15 @@ public class DmiCmNotificationSubscriptionCacheHandler { * * @param subscriptionId subscription id as key in CM notification Subscription cache. */ - public void removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(final String subscriptionId) { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionsPerDmi = + public void removeAcceptedAndRejectedDmiSubscriptionEntries(final String subscriptionId) { + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = cmNotificationSubscriptionCache.get(subscriptionId); - final Map<String, DmiCmNotificationSubscriptionDetails> updatedDmiCmNotificationSubscriptionsPerDmi = - dmiCmNotificationSubscriptionsPerDmi.entrySet().stream().filter( - dmiCmNotificationSubscription -> - !isAcceptedOrRejected(dmiCmNotificationSubscription.getValue())) + final Map<String, DmiCmSubscriptionDetails> updatedDmiSubscriptionsPerDmi = + dmiSubscriptionsPerDmi.entrySet().stream() + .filter(dmiCmNotificationSubscription -> !isAcceptedOrRejected( + dmiCmNotificationSubscription.getValue())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - cmNotificationSubscriptionCache.put(subscriptionId, updatedDmiCmNotificationSubscriptionsPerDmi); + cmNotificationSubscriptionCache.put(subscriptionId, updatedDmiSubscriptionsPerDmi); } /** @@ -92,9 +92,9 @@ public class DmiCmNotificationSubscriptionCacheHandler { * @param predicates CM Subscription Create Request Predicates * @return Map of DmiCmNotificationSubscription per DMI plugin */ - public Map<String, DmiCmNotificationSubscriptionDetails> createDmiCmNotificationSubscriptionsPerDmi( + public Map<String, DmiCmSubscriptionDetails> createDmiSubscriptionsPerDmi( final List<Predicate> predicates) { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi = + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = new HashMap<>(); for (final Predicate requestPredicate : predicates) { final List<String> targetFilter = requestPredicate.getTargetFilter(); @@ -103,15 +103,15 @@ public class DmiCmNotificationSubscriptionCacheHandler { final Set<String> xpaths = new HashSet<>(requestPredicate.getScopeFilter().getXpathFilter()); final Map<String, Set<String>> targetCmHandlesByDmiMap = groupTargetCmHandleIdsByDmi(targetFilter); for (final Map.Entry<String, Set<String>> targetCmHandlesByDmi: targetCmHandlesByDmiMap.entrySet()) { - final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate = - new DmiCmNotificationSubscriptionPredicate(targetCmHandlesByDmi.getValue(), + final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate = + new DmiCmSubscriptionPredicate(targetCmHandlesByDmi.getValue(), datastoreType, xpaths); - updateDmiCmNotificationSubscriptionDetailsPerDmi(targetCmHandlesByDmi.getKey(), - dmiCmNotificationSubscriptionPredicate, - dmiCmNotificationSubscriptionDetailsPerDmi); + updateDmiSubscriptionDetailsPerDmi(targetCmHandlesByDmi.getKey(), + dmiCmSubscriptionPredicate, + dmiSubscriptionsPerDmi); } } - return dmiCmNotificationSubscriptionDetailsPerDmi; + return dmiSubscriptionsPerDmi; } /** @@ -122,13 +122,12 @@ public class DmiCmNotificationSubscriptionCacheHandler { * @param status String of status * */ - public void updateDmiCmNotificationSubscriptionStatusPerDmi(final String subscriptionId, - final String dmiServiceName, - final CmNotificationSubscriptionStatus status) { - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi = + public void updateDmiSubscriptionStatusPerDmi(final String subscriptionId, final String dmiServiceName, + final CmSubscriptionStatus status) { + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = cmNotificationSubscriptionCache.get(subscriptionId); - dmiCmNotificationSubscriptionDetailsPerDmi.get(dmiServiceName).setCmNotificationSubscriptionStatus(status); - cmNotificationSubscriptionCache.put(subscriptionId, dmiCmNotificationSubscriptionDetailsPerDmi); + dmiSubscriptionsPerDmi.get(dmiServiceName).setCmSubscriptionStatus(status); + cmNotificationSubscriptionCache.put(subscriptionId, dmiSubscriptionsPerDmi); } /** @@ -139,18 +138,17 @@ public class DmiCmNotificationSubscriptionCacheHandler { * */ public void persistIntoDatabasePerDmi(final String subscriptionId, final String dmiServiceName) { - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicateList = + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates = cmNotificationSubscriptionCache.get(subscriptionId).get(dmiServiceName) - .getDmiCmNotificationSubscriptionPredicates(); - for (final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate: - dmiCmNotificationSubscriptionPredicateList) { - final DatastoreType datastoreType = dmiCmNotificationSubscriptionPredicate.getDatastoreType(); - final Set<String> cmHandles = dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds(); - final Set<String> xpaths = dmiCmNotificationSubscriptionPredicate.getXpaths(); + .getDmiCmSubscriptionPredicates(); + for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : dmiCmSubscriptionPredicates) { + final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType(); + final Set<String> cmHandles = dmiCmSubscriptionPredicate.getTargetCmHandleIds(); + final Set<String> xpaths = dmiCmSubscriptionPredicate.getXpaths(); for (final String cmHandle: cmHandles) { for (final String xpath: xpaths) { - cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType, cmHandle, + cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandle, xpath, subscriptionId); } } @@ -165,35 +163,34 @@ public class DmiCmNotificationSubscriptionCacheHandler { * */ public void removeFromDatabasePerDmi(final String subscriptionId, final String dmiServiceName) { - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicateList = + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates = cmNotificationSubscriptionCache.get(subscriptionId).get(dmiServiceName) - .getDmiCmNotificationSubscriptionPredicates(); - for (final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate: - dmiCmNotificationSubscriptionPredicateList) { - final DatastoreType datastoreType = dmiCmNotificationSubscriptionPredicate.getDatastoreType(); - final Set<String> cmHandles = dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds(); - final Set<String> xpaths = dmiCmNotificationSubscriptionPredicate.getXpaths(); + .getDmiCmSubscriptionPredicates(); + for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : dmiCmSubscriptionPredicates) { + final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType(); + final Set<String> cmHandles = dmiCmSubscriptionPredicate.getTargetCmHandleIds(); + final Set<String> xpaths = dmiCmSubscriptionPredicate.getXpaths(); for (final String cmHandle: cmHandles) { for (final String xpath: xpaths) { - cmNotificationSubscriptionPersistenceService.removeCmNotificationSubscription(datastoreType, + cmSubscriptionPersistenceService.removeCmSubscription(datastoreType, cmHandle, xpath, subscriptionId); } } } } - private void updateDmiCmNotificationSubscriptionDetailsPerDmi( + private void updateDmiSubscriptionDetailsPerDmi( final String dmiServiceName, - final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate, - final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi) { - if (dmiCmNotificationSubscriptionDetailsPerDmi.containsKey(dmiServiceName)) { - dmiCmNotificationSubscriptionDetailsPerDmi.get(dmiServiceName) - .getDmiCmNotificationSubscriptionPredicates().add(dmiCmNotificationSubscriptionPredicate); + final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate, + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi) { + if (dmiSubscriptionsPerDmi.containsKey(dmiServiceName)) { + dmiSubscriptionsPerDmi.get(dmiServiceName) + .getDmiCmSubscriptionPredicates().add(dmiCmSubscriptionPredicate); } else { - dmiCmNotificationSubscriptionDetailsPerDmi.put(dmiServiceName, - new DmiCmNotificationSubscriptionDetails( - new ArrayList<>(List.of(dmiCmNotificationSubscriptionPredicate)), + dmiSubscriptionsPerDmi.put(dmiServiceName, + new DmiCmSubscriptionDetails( + new ArrayList<>(List.of(dmiCmSubscriptionPredicate)), PENDING)); } } @@ -211,9 +208,8 @@ public class DmiCmNotificationSubscriptionCacheHandler { return targetCmHandlesByDmiServiceNames; } - private boolean isAcceptedOrRejected( - final DmiCmNotificationSubscriptionDetails dmiCmNotificationSubscription) { - return dmiCmNotificationSubscription.getCmNotificationSubscriptionStatus().toString().equals("ACCEPTED") - || dmiCmNotificationSubscription.getCmNotificationSubscriptionStatus().toString().equals("REJECTED"); + private boolean isAcceptedOrRejected(final DmiCmSubscriptionDetails dmiCmSubscription) { + return dmiCmSubscription.getCmSubscriptionStatus().toString().equals("ACCEPTED") + || dmiCmSubscription.getCmSubscriptionStatus().toString().equals("REJECTED"); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumer.java index f635f1a80b..0207fb90e3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumer.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.avc; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.cmavc; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; @@ -33,13 +33,13 @@ import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; /** - * Listener for AVC events. + * Listener for AVC events based on Cm Subscriptions. */ @Component @Slf4j @RequiredArgsConstructor @ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) -public class AvcEventConsumer { +public class CmAvcEventConsumer { @Value("${app.ncmp.avc.cm-events-topic}") @@ -50,15 +50,17 @@ public class AvcEventConsumer { /** * Incoming AvcEvent in the form of Consumer Record. * - * @param avcEventConsumerRecord Incoming raw consumer record + * @param cmAvcEventAsConsumerRecord Incoming raw consumer record */ @KafkaListener(topics = "${app.dmi.cm-events.topic}", containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeAndForward(final ConsumerRecord<String, CloudEvent> avcEventConsumerRecord) { - log.debug("Consuming AVC event {} ...", avcEventConsumerRecord.value()); + public void consumeAndForward( + final ConsumerRecord<String, CloudEvent> cmAvcEventAsConsumerRecord) { + log.debug("Consuming AVC event {} ...", cmAvcEventAsConsumerRecord.value()); final String newEventId = UUID.randomUUID().toString(); final CloudEvent outgoingAvcEvent = - CloudEventBuilder.from(avcEventConsumerRecord.value()).withId(newEventId).build(); + CloudEventBuilder.from(cmAvcEventAsConsumerRecord.value()).withId(newEventId) + .build(); eventsPublisher.publishCloudEvent(cmEventsTopicName, newEventId, outgoingAvcEvent); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapper.java index 7263891a21..4ce4ef36cf 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi; import java.util.ArrayList; import java.util.HashSet; @@ -27,46 +27,44 @@ import java.util.List; import java.util.Map; import java.util.Set; import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate; -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmHandle; -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.Data; -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Predicate; -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.ScopeFilter; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.CmHandle; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.Data; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.Predicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.ScopeFilter; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class CmNotificationSubscriptionDmiInEventMapper { +public class DmiInEventMapper { private final InventoryPersistence inventoryPersistence; /** * Mapper to form a request for the DMI Plugin for the Cm Notification Subscription. * - * @param dmiCmNotificationSubscriptionPredicates Collection of Cm Notification Subscription predicates - * @return CmNotificationSubscriptionDmiInEvent to be sent to DMI Plugin + * @param dmiCmSubscriptionPredicates Collection of Cm Notification Subscription predicates + * @return DmiInEvent to be sent to DMI Plugin */ - public CmNotificationSubscriptionDmiInEvent toCmNotificationSubscriptionDmiInEvent( - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) { - final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent = - new CmNotificationSubscriptionDmiInEvent(); + public DmiInEvent toDmiInEvent(final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) { + final DmiInEvent dmiInEvent = new DmiInEvent(); final Data cmSubscriptionData = new Data(); - cmSubscriptionData.setPredicates(mapToDmiInEventPredicates(dmiCmNotificationSubscriptionPredicates)); - cmSubscriptionData.setCmHandles(mapToCmSubscriptionCmhandleWithPrivateProperties( - extractUniqueCmHandleIds(dmiCmNotificationSubscriptionPredicates))); - cmNotificationSubscriptionDmiInEvent.setData(cmSubscriptionData); - return cmNotificationSubscriptionDmiInEvent; + cmSubscriptionData.setPredicates(mapToDmiInEventPredicates(dmiCmSubscriptionPredicates)); + cmSubscriptionData.setCmHandles(mapToCmSubscriptionCmHandleWithPrivateProperties( + extractUniqueCmHandleIds(dmiCmSubscriptionPredicates))); + dmiInEvent.setData(cmSubscriptionData); + return dmiInEvent; } private List<Predicate> mapToDmiInEventPredicates( - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) { + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) { final List<Predicate> predicates = new ArrayList<>(); - dmiCmNotificationSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> { + dmiCmSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> { final Predicate predicate = new Predicate(); final ScopeFilter scopeFilter = new ScopeFilter(); scopeFilter.setDatastore(ScopeFilter.Datastore.fromValue( @@ -81,7 +79,7 @@ public class CmNotificationSubscriptionDmiInEventMapper { } - private List<CmHandle> mapToCmSubscriptionCmhandleWithPrivateProperties(final Set<String> cmHandleIds) { + private List<CmHandle> mapToCmSubscriptionCmHandleWithPrivateProperties(final Set<String> cmHandleIds) { final List<CmHandle> cmSubscriptionCmHandles = new ArrayList<>(); @@ -99,11 +97,10 @@ public class CmNotificationSubscriptionDmiInEventMapper { } - private Set<String> extractUniqueCmHandleIds( - final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) { + private Set<String> extractUniqueCmHandleIds(final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) { final Set<String> cmHandleIds = new HashSet<>(); - dmiCmNotificationSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> cmHandleIds.addAll( + dmiCmSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> cmHandleIds.addAll( dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds())); return cmHandleIds; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducer.java index 3273c556c6..c62916f05c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducer.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.producer; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; @@ -26,7 +26,7 @@ import java.net.URI; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.onap.cps.events.EventsPublisher; -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -35,38 +35,36 @@ import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor @ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) -public class CmNotificationSubscriptionDmiInEventProducer { +public class DmiInEventProducer { private final EventsPublisher<CloudEvent> eventsPublisher; private final JsonObjectMapper jsonObjectMapper; @Value("${app.ncmp.avc.cm-subscription-dmi-in}") - private String cmNotificationSubscriptionDmiInEventTopic; + private String dmiInEventTopic; /** * 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 + * @param subscriptionId Cm Subscription Id + * @param dmiPluginName Dmi Plugin Name + * @param eventType Type of event + * @param dmiInEvent Cm Notification Subscription event for Dmi */ - public void publishCmNotificationSubscriptionDmiInEvent(final String subscriptionId, final String dmiPluginName, - final String eventType, final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) { - eventsPublisher.publishCloudEvent(cmNotificationSubscriptionDmiInEventTopic, subscriptionId, - buildAndGetCmNotificationDmiInEventAsCloudEvent(subscriptionId, dmiPluginName, eventType, - cmNotificationSubscriptionDmiInEvent)); + public void publishDmiInEvent(final String subscriptionId, final String dmiPluginName, + final String eventType, final DmiInEvent dmiInEvent) { + eventsPublisher.publishCloudEvent(dmiInEventTopic, subscriptionId, + buildAndGetDmiInEventAsCloudEvent(subscriptionId, dmiPluginName, eventType, dmiInEvent)); } - private CloudEvent buildAndGetCmNotificationDmiInEventAsCloudEvent(final String subscriptionId, - final String dmiPluginName, final String eventType, - final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) { + private CloudEvent buildAndGetDmiInEventAsCloudEvent(final String subscriptionId, + final String dmiPluginName, final String eventType, final DmiInEvent dmiInEvent) { return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType) .withSource(URI.create("NCMP")) .withDataSchema(URI.create("org.onap.ncmp.dmi.cm.subscription:1.0.0")) .withExtension("correlationid", subscriptionId.concat("#").concat(dmiPluginName)) - .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionDmiInEvent)).build(); + .withData(jsonObjectMapper.asJsonBytes(dmiInEvent)).build(); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java new file mode 100644 index 0000000000..20ccf528ed --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java @@ -0,0 +1,115 @@ +/* + * ============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.impl.cmnotificationsubscription.dmi; + +import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_ACCEPTED; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_REJECTED; +import static org.onap.cps.ncmp.utils.events.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.NcmpResponseStatus; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventMapper; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.Data; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class DmiOutEventConsumer { + + private final DmiCacheHandler dmiCacheHandler; + private final NcmpOutEventProducer ncmpOutEventProducer; + private final NcmpOutEventMapper ncmpOutEventMapper; + + private static final String CM_SUBSCRIPTION_CORRELATION_ID_SEPARATOR = "#"; + + /** + * Consume the Cm Notification Subscription event from the dmi-plugin. + * + * @param dmiOutEventAsConsumerRecord the event to be consumed + */ + @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-dmi-out}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void consumeDmiOutEvent(final ConsumerRecord<String, CloudEvent> dmiOutEventAsConsumerRecord) { + final CloudEvent cloudEvent = dmiOutEventAsConsumerRecord.value(); + final DmiOutEvent dmiOutEvent = toTargetEvent(cloudEvent, DmiOutEvent.class); + final String correlationId = String.valueOf(cloudEvent.getExtension("correlationid")); + if (dmiOutEvent != null && correlationId != null) { + final String eventType = cloudEvent.getType(); + handleDmiOutEvent(correlationId, eventType, dmiOutEvent); + } + } + + private void handleDmiOutEvent(final String correlationId, final String eventType, + final DmiOutEvent dmiOutEvent) { + final String subscriptionId = correlationId.split(CM_SUBSCRIPTION_CORRELATION_ID_SEPARATOR)[0]; + final String dmiPluginName = correlationId.split(CM_SUBSCRIPTION_CORRELATION_ID_SEPARATOR)[1]; + + if (checkStatusCodeAndMessage(CM_DATA_SUBSCRIPTION_ACCEPTED, dmiOutEvent.getData())) { + handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmSubscriptionStatus.ACCEPTED); + if (eventType.equals("subscriptionCreateResponse")) { + dmiCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName); + } + if (eventType.equals("subscriptionDeleteResponse")) { + dmiCacheHandler.removeFromDatabasePerDmi(subscriptionId, dmiPluginName); + } + handleEventsStatusPerDmi(subscriptionId, eventType); + } + + if (checkStatusCodeAndMessage(CM_DATA_SUBSCRIPTION_REJECTED, dmiOutEvent.getData())) { + handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmSubscriptionStatus.REJECTED); + handleEventsStatusPerDmi(subscriptionId, eventType); + } + + log.info("Cm Subscription with id : {} handled by the dmi-plugin : {} has the status : {}", subscriptionId, + dmiPluginName, dmiOutEvent.getData().getStatusMessage()); + } + + private void handleCacheStatusPerDmi(final String subscriptionId, final String dmiPluginName, + final CmSubscriptionStatus cmSubscriptionStatus) { + dmiCacheHandler.updateDmiSubscriptionStatusPerDmi(subscriptionId, dmiPluginName, + cmSubscriptionStatus); + } + + private void handleEventsStatusPerDmi(final String subscriptionId, final String eventType) { + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = dmiCacheHandler.get(subscriptionId); + final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEvent(subscriptionId, dmiSubscriptionsPerDmi); + ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, false); + } + + private boolean checkStatusCodeAndMessage(final NcmpResponseStatus ncmpResponseStatus, + final Data dmiOutData) { + return ncmpResponseStatus.getCode().equals(dmiOutData.getStatusCode()) + && ncmpResponseStatus.getMessage() + .equals(dmiOutData.getStatusMessage()); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/CmNotificationSubscriptionStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/CmSubscriptionStatus.java index 68d54fac95..5b7c46ed00 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/CmNotificationSubscriptionStatus.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/CmSubscriptionStatus.java @@ -18,15 +18,15 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.model; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.models; -public enum CmNotificationSubscriptionStatus { +public enum CmSubscriptionStatus { ACCEPTED("ACCEPTED"), REJECTED("REJECTED"), PENDING("PENDING"); private final String cmNotificationSubscriptionStatusValue; - CmNotificationSubscriptionStatus(final String cmNotificationSubscriptionStatusValue) { + CmSubscriptionStatus(final String cmNotificationSubscriptionStatusValue) { this.cmNotificationSubscriptionStatusValue = cmNotificationSubscriptionStatusValue; } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionDetails.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionDetails.java index 95757e7240..dbc607ad27 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionDetails.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionDetails.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.model; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.models; import java.util.List; import lombok.AllArgsConstructor; @@ -28,8 +28,8 @@ import lombok.Setter; @Getter @Setter @AllArgsConstructor -public class DmiCmNotificationSubscriptionDetails { +public class DmiCmSubscriptionDetails { - private List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates; - private CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus; + private List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates; + private CmSubscriptionStatus cmSubscriptionStatus; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionPredicate.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionPredicate.java index 9c4c3f64e3..84d3aead8c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionPredicate.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionPredicate.java @@ -18,18 +18,18 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.model; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.models; import java.util.Set; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; +import org.onap.cps.ncmp.api.data.models.DatastoreType; @Getter @Setter @AllArgsConstructor -public class DmiCmNotificationSubscriptionPredicate { +public class DmiCmSubscriptionPredicate { private Set<String> targetCmHandleIds; private DatastoreType datastoreType; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java new file mode 100644 index 0000000000..d7f15a2c72 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java @@ -0,0 +1,83 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.api.data.models.DatastoreType; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CmSubscriptionComparator { + + private final CmSubscriptionPersistenceService cmSubscriptionPersistenceService; + + /** + * Get the new Dmi Predicates for a given predicates list. + * + * @param existingDmiCmSubscriptionPredicates list of DmiCmNotificationSubscriptionPredicates + * @return new list of DmiCmNotificationSubscriptionPredicates + */ + public List<DmiCmSubscriptionPredicate> getNewDmiSubscriptionPredicates( + final List<DmiCmSubscriptionPredicate> existingDmiCmSubscriptionPredicates) { + final List<DmiCmSubscriptionPredicate> newDmiCmSubscriptionPredicates = + new ArrayList<>(); + + for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : existingDmiCmSubscriptionPredicates) { + + final Set<String> targetCmHandleIds = new HashSet<>(); + final Set<String> xpaths = new HashSet<>(); + final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType(); + + for (final String cmHandleId : dmiCmSubscriptionPredicate.getTargetCmHandleIds()) { + for (final String xpath : dmiCmSubscriptionPredicate.getXpaths()) { + if (!cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, + cmHandleId, xpath)) { + xpaths.add(xpath); + targetCmHandleIds.add(cmHandleId); + + } + } + } + + populateValidDmiSubscriptionPredicates(targetCmHandleIds, xpaths, datastoreType, + newDmiCmSubscriptionPredicates); + } + return newDmiCmSubscriptionPredicates; + } + + private void populateValidDmiSubscriptionPredicates(final Set<String> targetCmHandleIds, + final Set<String> xpaths, final DatastoreType datastoreType, + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) { + if (!(targetCmHandleIds.isEmpty() || xpaths.isEmpty())) { + final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate = + new DmiCmSubscriptionPredicate(targetCmHandleIds, datastoreType, xpaths); + dmiCmSubscriptionPredicates.add(dmiCmSubscriptionPredicate); + } + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandler.java index 1c52ffa798..3a9b2066b2 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandler.java @@ -18,12 +18,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.service; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp; import java.util.List; -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.Predicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate; -public interface CmNotificationSubscriptionHandlerService { +public interface CmSubscriptionHandler { /** * Process cm notification subscription create request. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java new file mode 100644 index 0000000000..9d33d25816 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java @@ -0,0 +1,123 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp; + +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.impl.cmnotificationsubscription.cache.DmiCacheHandler; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventMapper; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventProducer; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CmSubscriptionHandlerImpl implements CmSubscriptionHandler { + + private final CmSubscriptionPersistenceService cmSubscriptionPersistenceService; + private final CmSubscriptionComparator cmSubscriptionComparator; + private final NcmpOutEventMapper ncmpOutEventMapper; + private final DmiInEventMapper dmiInEventMapper; + private final NcmpOutEventProducer ncmpOutEventProducer; + private final DmiInEventProducer dmiInEventProducer; + private final DmiCacheHandler dmiCacheHandler; + + @Override + public void processSubscriptionCreateRequest(final String subscriptionId, final List<Predicate> predicates) { + if (cmSubscriptionPersistenceService.isUniqueSubscriptionId(subscriptionId)) { + dmiCacheHandler.add(subscriptionId, predicates); + handleNewCmSubscription(subscriptionId); + scheduleNcmpOutEventResponse(subscriptionId, "subscriptionCreateResponse"); + } else { + rejectAndPublishCreateRequest(subscriptionId, predicates); + } + } + + @Override + public void processSubscriptionDeleteRequest(final String subscriptionId, final List<Predicate> predicates) { + dmiCacheHandler.add(subscriptionId, predicates); + sendSubscriptionDeleteRequestToDmi(subscriptionId); + scheduleNcmpOutEventResponse(subscriptionId, "subscriptionDeleteResponse"); + } + + private void scheduleNcmpOutEventResponse(final String subscriptionId, final String eventType) { + ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, eventType, null, true); + } + + private void rejectAndPublishCreateRequest(final String subscriptionId, final List<Predicate> predicates) { + final Set<String> subscriptionTargetFilters = + predicates.stream().flatMap(predicate -> predicate.getTargetFilter().stream()) + .collect(Collectors.toSet()); + final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEventForRejectedRequest(subscriptionId, + new ArrayList<>(subscriptionTargetFilters)); + ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, "subscriptionCreateResponse", ncmpOutEvent, false); + } + + private void handleNewCmSubscription(final String subscriptionId) { + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = + dmiCacheHandler.get(subscriptionId); + dmiSubscriptionsPerDmi.forEach((dmiPluginName, dmiSubscriptionDetails) -> { + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates = + cmSubscriptionComparator.getNewDmiSubscriptionPredicates( + dmiSubscriptionDetails.getDmiCmSubscriptionPredicates()); + + if (dmiCmSubscriptionPredicates.isEmpty()) { + acceptAndPublishNcmpOutEventPerDmi(subscriptionId, dmiPluginName); + } else { + publishDmiInEventPerDmi(subscriptionId, dmiPluginName, dmiCmSubscriptionPredicates); + } + }); + } + + private void publishDmiInEventPerDmi(final String subscriptionId, final String dmiPluginName, + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) { + final DmiInEvent dmiInEvent = dmiInEventMapper.toDmiInEvent(dmiCmSubscriptionPredicates); + dmiInEventProducer.publishDmiInEvent(subscriptionId, dmiPluginName, + "subscriptionCreateRequest", dmiInEvent); + } + + private void acceptAndPublishNcmpOutEventPerDmi(final String subscriptionId, final String dmiPluginName) { + dmiCacheHandler.updateDmiSubscriptionStatusPerDmi(subscriptionId, dmiPluginName, + CmSubscriptionStatus.ACCEPTED); + dmiCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName); + } + + private void sendSubscriptionDeleteRequestToDmi(final String subscriptionId) { + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = + dmiCacheHandler.get(subscriptionId); + dmiSubscriptionsPerDmi.forEach((dmiPluginName, dmiSubscriptionDetails) -> { + final DmiInEvent dmiInEvent = dmiInEventMapper.toDmiInEvent( + dmiSubscriptionDetails.getDmiCmSubscriptionPredicates()); + dmiInEventProducer.publishDmiInEvent(subscriptionId, dmiPluginName, + "subscriptionDeleteRequest", dmiInEvent); + }); + } +}
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumer.java index fb3388c117..1e1359dd0d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumer.java @@ -18,53 +18,52 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp; -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent; +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent; import io.cloudevents.CloudEvent; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionHandlerService; -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.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; @Component @Slf4j @RequiredArgsConstructor -public class CmNotificationSubscriptionNcmpInEventConsumer { +public class NcmpInEventConsumer { - private final CmNotificationSubscriptionHandlerService cmNotificationSubscriptionHandlerService; + private final CmSubscriptionHandler cmSubscriptionHandler; /** * Consume the specified event. * - * @param subscriptionEventConsumerRecord the event to be consumed + * @param ncmpInEventAsConsumerRecord the event to be consumed */ @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-ncmp-in}", containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void consumeSubscriptionEvent(final ConsumerRecord<String, CloudEvent> subscriptionEventConsumerRecord) { - final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); - final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent = - toTargetEvent(cloudEvent, CmNotificationSubscriptionNcmpInEvent.class); + public void consumeSubscriptionEvent(final ConsumerRecord<String, CloudEvent> ncmpInEventAsConsumerRecord) { + final CloudEvent cloudEvent = ncmpInEventAsConsumerRecord.value(); + final NcmpInEvent ncmpInEvent = + toTargetEvent(cloudEvent, NcmpInEvent.class); log.info("Subscription with name {} to be mapped to hazelcast object...", - cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()); + ncmpInEvent.getData().getSubscriptionId()); - final String subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId(); - final List<Predicate> predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates(); + final String subscriptionId = ncmpInEvent.getData().getSubscriptionId(); + final List<Predicate> predicates = ncmpInEvent.getData().getPredicates(); if ("subscriptionCreateRequest".equals(cloudEvent.getType())) { log.info("Subscription create request for source {} with subscription id {} ...", cloudEvent.getSource(), subscriptionId); - cmNotificationSubscriptionHandlerService.processSubscriptionCreateRequest(subscriptionId, predicates); + cmSubscriptionHandler.processSubscriptionCreateRequest(subscriptionId, predicates); } if ("subscriptionDeleteRequest".equals(cloudEvent.getType())) { log.info("Subscription delete request for source {} with subscription id {} ...", cloudEvent.getSource(), subscriptionId); - cmNotificationSubscriptionHandlerService.processSubscriptionDeleteRequest(subscriptionId, predicates); + cmSubscriptionHandler.processSubscriptionDeleteRequest(subscriptionId, predicates); } } -}
\ No newline at end of file +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java new file mode 100644 index 0000000000..ffd4b014fb --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java @@ -0,0 +1,112 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.Data; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class NcmpOutEventMapper { + + /** + * Mapper to form a response for the client for the Cm Notification Subscription. + * + * @param subscriptionId Cm Notification Subscription Id + * @param dmiSubscriptionsPerDmi contains CmNotificationSubscriptionDetails per dmi plugin + * @return CmNotificationSubscriptionNcmpOutEvent to sent back to the client + */ + public NcmpOutEvent toNcmpOutEvent(final String subscriptionId, + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi) { + + final NcmpOutEvent ncmpOutEvent = new NcmpOutEvent(); + final Data cmSubscriptionData = new Data(); + cmSubscriptionData.setSubscriptionId(subscriptionId); + populateNcmpOutEventWithCmHandleIds(dmiSubscriptionsPerDmi, + cmSubscriptionData); + ncmpOutEvent.setData(cmSubscriptionData); + + return ncmpOutEvent; + } + + /** + * 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 NcmpOutEvent toNcmpOutEventForRejectedRequest(final String subscriptionId, + final List<String> rejectedTargetFilters) { + final NcmpOutEvent ncmpOutEvent = new NcmpOutEvent(); + final Data cmSubscriptionData = new Data(); + cmSubscriptionData.setSubscriptionId(subscriptionId); + cmSubscriptionData.setRejectedTargets(rejectedTargetFilters); + ncmpOutEvent.setData(cmSubscriptionData); + return ncmpOutEvent; + } + + private void populateNcmpOutEventWithCmHandleIds( + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi, + final Data cmSubscriptionData) { + + final List<String> acceptedCmHandleIds = new ArrayList<>(); + final List<String> pendingCmHandleIds = new ArrayList<>(); + final List<String> rejectedCmHandleIds = new ArrayList<>(); + + dmiSubscriptionsPerDmi.forEach((dmiPluginName, dmiSubscriptionDetails) -> { + final CmSubscriptionStatus cmSubscriptionStatus = + dmiSubscriptionDetails.getCmSubscriptionStatus(); + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates = + dmiSubscriptionDetails.getDmiCmSubscriptionPredicates(); + + switch (cmSubscriptionStatus) { + case ACCEPTED -> acceptedCmHandleIds.addAll( + extractCmHandleIds(dmiCmSubscriptionPredicates)); + case PENDING -> pendingCmHandleIds.addAll(extractCmHandleIds(dmiCmSubscriptionPredicates)); + default -> rejectedCmHandleIds.addAll(extractCmHandleIds(dmiCmSubscriptionPredicates)); + } + }); + + cmSubscriptionData.setAcceptedTargets(acceptedCmHandleIds); + cmSubscriptionData.setPendingTargets(pendingCmHandleIds); + cmSubscriptionData.setRejectedTargets(rejectedCmHandleIds); + + } + + private List<String> extractCmHandleIds( + final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) { + final List<String> cmHandleIds = new ArrayList<>(); + dmiCmSubscriptionPredicates.forEach(dmiSubscriptionPredicate -> cmHandleIds.addAll( + dmiSubscriptionPredicate.getTargetCmHandleIds())); + + return cmHandleIds; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java new file mode 100644 index 0000000000..01d720937f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java @@ -0,0 +1,134 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import java.net.URI; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.events.EventsPublisher; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent; +import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) +public class NcmpOutEventProducer { + + @Value("${app.ncmp.avc.cm-subscription-ncmp-out}") + private String ncmpOutEventTopic; + + @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms}") + private Integer dmiOutEventTimeoutInMs; + + private final EventsPublisher<CloudEvent> eventsPublisher; + private final JsonObjectMapper jsonObjectMapper; + private final NcmpOutEventMapper ncmpOutEventMapper; + private final DmiCacheHandler dmiCacheHandler; + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + private static final Map<String, ScheduledFuture<?>> scheduledTasksPerSubscriptionId = new ConcurrentHashMap<>(); + + /** + * 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 ncmpOutEvent Cm Notification Subscription Event for the + * client + * @param isScheduledEvent Determines if the event is to be scheduled + * or published now + */ + public void publishNcmpOutEvent(final String subscriptionId, final String eventType, + final NcmpOutEvent ncmpOutEvent, final boolean isScheduledEvent) { + + if (isScheduledEvent && !scheduledTasksPerSubscriptionId.containsKey(subscriptionId)) { + final ScheduledFuture<?> scheduledFuture = scheduleAndPublishNcmpOutEvent(subscriptionId, eventType); + scheduledTasksPerSubscriptionId.putIfAbsent(subscriptionId, scheduledFuture); + log.debug("Scheduled the CmNotificationSubscriptionEvent for subscriptionId : {}", subscriptionId); + } else { + cancelScheduledTaskForSubscriptionId(subscriptionId); + publishNcmpOutEventNow(subscriptionId, eventType, ncmpOutEvent); + log.info("Published CmNotificationSubscriptionEvent on demand for subscriptionId : {}", subscriptionId); + } + } + + private ScheduledFuture<?> scheduleAndPublishNcmpOutEvent(final String subscriptionId, final String eventType) { + final NcmpOutEventPublishingTask ncmpOutEventPublishingTask = + new NcmpOutEventPublishingTask(ncmpOutEventTopic, subscriptionId, eventType, eventsPublisher, + jsonObjectMapper, ncmpOutEventMapper, dmiCacheHandler); + return scheduledExecutorService.schedule(ncmpOutEventPublishingTask, dmiOutEventTimeoutInMs, + TimeUnit.MILLISECONDS); + } + + private void cancelScheduledTaskForSubscriptionId(final String subscriptionId) { + + final ScheduledFuture<?> scheduledFuture = scheduledTasksPerSubscriptionId.get(subscriptionId); + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + scheduledTasksPerSubscriptionId.remove(subscriptionId); + } + + } + + + private void publishNcmpOutEventNow(final String subscriptionId, final String eventType, + final NcmpOutEvent ncmpOutEvent) { + final CloudEvent ncmpOutEventAsCloudEvent = + buildAndGetNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, + ncmpOutEvent); + eventsPublisher.publishCloudEvent(ncmpOutEventTopic, subscriptionId, + ncmpOutEventAsCloudEvent); + dmiCacheHandler.removeAcceptedAndRejectedDmiSubscriptionEntries(subscriptionId); + } + + /** + * Get an NCMP out event as cloud event. + * + * @param jsonObjectMapper JSON object mapper + * @param subscriptionId subscription id + * @param eventType event type + * @param ncmpOutEvent cm notification subscription NCMP out event + * @return cm notification subscription NCMP out event as cloud event + */ + public static CloudEvent buildAndGetNcmpOutEventAsCloudEvent(final JsonObjectMapper jsonObjectMapper, + final String subscriptionId, final String eventType, final NcmpOutEvent ncmpOutEvent) { + + return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType) + .withSource(URI.create("NCMP")).withDataSchema(URI.create("org.onap.ncmp.cm.subscription:1.0.0")) + .withExtension("correlationid", subscriptionId) + .withData(jsonObjectMapper.asJsonBytes(ncmpOutEvent)).build(); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java new file mode 100644 index 0000000000..f8f253d275 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java @@ -0,0 +1,62 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp; + +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer.buildAndGetNcmpOutEventAsCloudEvent; + +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.impl.cmnotificationsubscription.cache.DmiCacheHandler; +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails; +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent; +import org.onap.cps.utils.JsonObjectMapper; + +@Slf4j +@RequiredArgsConstructor +public class NcmpOutEventPublishingTask 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 NcmpOutEventMapper ncmpOutEventMapper; + private final DmiCacheHandler dmiCacheHandler; + + /** + * Delegating the responsibility of publishing NcmpOutEvent as a separate task which will + * be called after a specified delay. + */ + @Override + public void run() { + final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = + dmiCacheHandler.get(subscriptionId); + final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEvent(subscriptionId, + dmiSubscriptionsPerDmi); + eventsPublisher.publishCloudEvent(topicName, subscriptionId, + buildAndGetNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, + ncmpOutEvent)); + dmiCacheHandler.removeAcceptedAndRejectedDmiSubscriptionEntries(subscriptionId); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceService.java index a9b1e26f54..c24507a1a7 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceService.java @@ -1,7 +1,6 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 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. @@ -19,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.service; +package org.onap.cps.ncmp.impl.cmnotificationsubscription.utils; import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY; import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS; @@ -34,7 +33,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsQueryService; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; +import org.onap.cps.ncmp.api.data.models.DatastoreType; import org.onap.cps.spi.model.DataNode; import org.onap.cps.utils.ContentType; import org.onap.cps.utils.JsonObjectMapper; @@ -43,7 +42,10 @@ import org.springframework.stereotype.Service; @Slf4j @Service @RequiredArgsConstructor -public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotificationSubscriptionPersistenceService { +public class CmSubscriptionPersistenceService { + + private static final String NCMP_DATASPACE_NAME = "NCMP-Admin"; + private static final String CM_SUBSCRIPTIONS_ANCHOR_NAME = "cm-data-subscriptions"; private static final String SUBSCRIPTION_ANCHOR_NAME = "cm-data-subscriptions"; private static final String CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_AND_CMHANDLE = """ @@ -64,22 +66,40 @@ public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotif private final CpsQueryService cpsQueryService; private final CpsDataService cpsDataService; - @Override - public boolean isOngoingCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId, - final String xpath) { - return !getOngoingCmNotificationSubscriptionIds(datastoreType, cmHandleId, xpath).isEmpty(); + /** + * Check if we have an ongoing cm subscription based on the parameters. + * + * @param datastoreType the susbcription target datastore type + * @param cmHandleId the id of the cm handle for the susbcription + * @param xpath the target xpath + * @return true for ongoing cmsubscription , otherwise false + */ + public boolean isOngoingCmSubscription(final DatastoreType datastoreType, final String cmHandleId, + final String xpath) { + return !getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).isEmpty(); } - @Override + /** + * Check if the subscription ID is unique against ongoing subscriptions. + * + * @param subscriptionId subscription ID + * @return true if subscriptionId is not used in active subscriptions, otherwise false + */ public boolean isUniqueSubscriptionId(final String subscriptionId) { return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID.formatted(subscriptionId), - OMIT_DESCENDANTS).isEmpty(); + CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID.formatted(subscriptionId), OMIT_DESCENDANTS).isEmpty(); } - @Override - public Collection<String> getOngoingCmNotificationSubscriptionIds(final DatastoreType datastoreType, - final String cmHandleId, final String xpath) { + /** + * Get all ongoing cm notification subscription based on the parameters. + * + * @param datastoreType the susbcription target datastore type + * @param cmHandleId the id of the cm handle for the susbcription + * @param xpath the target xpath + * @return collection of subscription ids of ongoing cm notification subscription + */ + public Collection<String> getOngoingCmSubscriptionIds(final DatastoreType datastoreType, + final String cmHandleId, final String xpath) { final String isOngoingCmSubscriptionCpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted( @@ -93,24 +113,38 @@ public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotif return (List<String>) existingNodes.iterator().next().getLeaves().get("subscriptionIds"); } - @Override - public void addCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId, - final String xpath, final String subscriptionId) { - final Collection<String> subscriptionIds = getOngoingCmNotificationSubscriptionIds(datastoreType, - cmHandleId, xpath); + /** + * Add cm notification subscription. + * + * @param datastoreType the susbcription target datastore type + * @param cmHandleId the id of the cm handle for the susbcription + * @param xpath the target xpath + * @param newSubscriptionId subscription id to be added + */ + public void addCmSubscription(final DatastoreType datastoreType, final String cmHandleId, + final String xpath, final String newSubscriptionId) { + final Collection<String> subscriptionIds = + getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath); if (subscriptionIds.isEmpty()) { - addFirstSubscriptionForDatastoreCmHandleAndXpath(datastoreType, cmHandleId, xpath, subscriptionId); - } else if (!subscriptionIds.contains(subscriptionId)) { - subscriptionIds.add(subscriptionId); + addFirstSubscriptionForDatastoreCmHandleAndXpath(datastoreType, cmHandleId, xpath, newSubscriptionId); + } else if (!subscriptionIds.contains(newSubscriptionId)) { + subscriptionIds.add(newSubscriptionId); saveSubscriptionDetails(datastoreType, cmHandleId, xpath, subscriptionIds); } } - @Override - public void removeCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId, - final String xpath, final String subscriptionId) { - final Collection<String> subscriptionIds = getOngoingCmNotificationSubscriptionIds(datastoreType, - cmHandleId, xpath); + /** + * Remove cm notification Subscription. + * + * @param datastoreType the susbcription target datastore type + * @param cmHandleId the id of the cm handle for the susbcription + * @param xpath the target xpath + * @param subscriptionId subscription id to remove + */ + public void removeCmSubscription(final DatastoreType datastoreType, final String cmHandleId, + final String xpath, final String subscriptionId) { + final Collection<String> subscriptionIds = + getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath); if (subscriptionIds.remove(subscriptionId)) { saveSubscriptionDetails(datastoreType, cmHandleId, xpath, subscriptionIds); log.info("There are subscribers left for the following cps path {} :", @@ -126,16 +160,17 @@ public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotif } private void deleteListOfSubscriptionsFor(final DatastoreType datastoreType, final String cmHandleId, - final String xpath) { + final String xpath) { cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted( datastoreType.getDatastoreName(), cmHandleId, escapeQuotesByDoublingThem(xpath)), OffsetDateTime.now()); final Collection<DataNode> existingFiltersForCmHandle = cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME, - CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted( - datastoreType.getDatastoreName(), cmHandleId), - DIRECT_CHILDREN_ONLY).iterator().next().getChildDataNodes(); + CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted( + datastoreType.getDatastoreName(), cmHandleId), + DIRECT_CHILDREN_ONLY).iterator().next() + .getChildDataNodes(); if (existingFiltersForCmHandle.isEmpty()) { removeCmHandleFromDatastore(datastoreType.getDatastoreName(), cmHandleId); } @@ -143,46 +178,43 @@ public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotif private void removeCmHandleFromDatastore(final String datastoreName, final String cmHandleId) { cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, - CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_AND_CMHANDLE.formatted( - datastoreName, cmHandleId), OffsetDateTime.now()); + CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_AND_CMHANDLE.formatted(datastoreName, cmHandleId), + OffsetDateTime.now()); } private boolean isFirstSubscriptionForCmHandle(final DatastoreType datastoreType, final String cmHandleId) { return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME, CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted( - datastoreType.getDatastoreName(), cmHandleId), - OMIT_DESCENDANTS).isEmpty(); + datastoreType.getDatastoreName(), cmHandleId), OMIT_DESCENDANTS).isEmpty(); } private void addFirstSubscriptionForDatastoreCmHandleAndXpath(final DatastoreType datastoreType, - final String cmHandleId, - final String xpath, - final String subscriptionId) { + final String cmHandleId, final String xpath, final String subscriptionId) { final Collection<String> newSubscriptionList = Collections.singletonList(subscriptionId); final String subscriptionDetailsAsJson = getSubscriptionDetailsAsJson(xpath, newSubscriptionList); if (isFirstSubscriptionForCmHandle(datastoreType, cmHandleId)) { - final String parentXpath = "/datastores/datastore[@name='%s']/cm-handles" - .formatted(datastoreType.getDatastoreName()); - final String subscriptionAsJson = String.format("{\"cm-handle\":[{\"id\":\"%s\",\"filters\":%s}]}", - cmHandleId, subscriptionDetailsAsJson); + final String parentXpath = + "/datastores/datastore[@name='%s']/cm-handles".formatted(datastoreType.getDatastoreName()); + final String subscriptionAsJson = + String.format("{\"cm-handle\":[{\"id\":\"%s\",\"filters\":%s}]}", cmHandleId, + subscriptionDetailsAsJson); cpsDataService.saveData(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, parentXpath, subscriptionAsJson, OffsetDateTime.now(), ContentType.JSON); } else { cpsDataService.saveListElements(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME, CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted( - datastoreType.getDatastoreName(), cmHandleId), - subscriptionDetailsAsJson, OffsetDateTime.now()); + datastoreType.getDatastoreName(), cmHandleId), subscriptionDetailsAsJson, + OffsetDateTime.now()); } } - private void saveSubscriptionDetails(final DatastoreType datastoreType, final String cmHandleId, - final String xpath, - final Collection<String> subscriptionIds) { + private void saveSubscriptionDetails(final DatastoreType datastoreType, final String cmHandleId, final String xpath, + final Collection<String> subscriptionIds) { final String subscriptionDetailsAsJson = getSubscriptionDetailsAsJson(xpath, subscriptionIds); cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME, CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted( - datastoreType.getDatastoreName(), cmHandleId), subscriptionDetailsAsJson, - OffsetDateTime.now(), ContentType.JSON); + datastoreType.getDatastoreName(), cmHandleId), subscriptionDetailsAsJson, OffsetDateTime.now(), + ContentType.JSON); } private String getSubscriptionDetailsAsJson(final String xpath, final Collection<String> subscriptionIds) { @@ -194,4 +226,6 @@ public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotif private static String escapeQuotesByDoublingThem(final String inputXpath) { return inputXpath.replace("'", "''"); } + } + 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/impl/data/DmiDataOperations.java index 32fc8a5dbb..efe0335e8c 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/impl/data/DmiDataOperations.java @@ -19,12 +19,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.data; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ; -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA; +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL; +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING; +import static org.onap.cps.ncmp.api.data.models.OperationType.READ; +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA; import io.micrometer.core.annotation.Timed; import java.util.Collection; @@ -34,16 +34,22 @@ import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.onap.cps.ncmp.api.NcmpResponseStatus; +import org.onap.cps.ncmp.api.data.models.CmResourceAddress; +import org.onap.cps.ncmp.api.data.models.DataOperationRequest; +import org.onap.cps.ncmp.api.data.models.OperationType; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; import org.onap.cps.ncmp.api.impl.config.DmiProperties; import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; -import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; -import org.onap.cps.ncmp.api.impl.utils.data.operation.ResourceDataOperationRequestUtils; -import org.onap.cps.ncmp.api.models.CmResourceAddress; -import org.onap.cps.ncmp.api.models.DataOperationRequest; +import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; +import org.onap.cps.ncmp.impl.data.models.DmiDataOperation; +import org.onap.cps.ncmp.impl.data.models.DmiDataOperationRequest; +import org.onap.cps.ncmp.impl.data.models.DmiOperationCmHandle; +import org.onap.cps.ncmp.impl.data.utils.DmiDataOperationsHelper; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.models.DmiRequestBody; import org.onap.cps.spi.exceptions.CpsException; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.http.ResponseEntity; @@ -89,9 +95,10 @@ public class DmiDataOperations { final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle); - final String dmiUrl = getDmiResourceDataUrl(cmResourceAddress.datastoreName(), yangModelCmHandle, - cmResourceAddress.resourceIdentifier(), options, topic); - return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, dmiUrl, jsonRequestBody, READ, authorization); + final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(cmResourceAddress + .datastoreName(), yangModelCmHandle, cmResourceAddress.resourceIdentifier(), options, topic); + return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ, + authorization); } /** @@ -109,9 +116,11 @@ public class DmiDataOperations { validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle); - final String dmiUrl = - getDmiResourceDataUrl(PASSTHROUGH_OPERATIONAL.getDatastoreName(), yangModelCmHandle, "/", null, null); - return dmiRestClient.synchronousPostOperationWithJsonData(DATA, dmiUrl, jsonRequestBody, READ, null); + final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters( + PASSTHROUGH_OPERATIONAL.getDatastoreName(), yangModelCmHandle, "/", null, + null); + return dmiRestClient.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ, + null); } /** @@ -129,16 +138,16 @@ public class DmiDataOperations { final String authorization) { final Set<String> cmHandlesIds - = getDistinctCmHandleIdsFromDataOperationRequest(dataOperationRequest); + = getDistinctCmHandleIds(dataOperationRequest); final Collection<YangModelCmHandle> yangModelCmHandles = inventoryPersistence.getYangModelCmHandles(cmHandlesIds); final Map<String, List<DmiDataOperation>> operationsOutPerDmiServiceName - = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(topicParamInQuery, + = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(topicParamInQuery, requestId, dataOperationRequest, yangModelCmHandles); - buildDataOperationRequestUrlAndSendToDmiService(requestId, topicParamInQuery, operationsOutPerDmiServiceName, + asyncSendMultipleRequest(requestId, topicParamInQuery, operationsOutPerDmiServiceName, authorization); } @@ -166,10 +175,11 @@ public class DmiDataOperations { final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType, yangModelCmHandle); - final String dmiUrl = getDmiResourceDataUrl(PASSTHROUGH_RUNNING.getDatastoreName(), - yangModelCmHandle, resourceId, null, null); - return dmiRestClient.synchronousPostOperationWithJsonData(DATA, dmiUrl, jsonRequestBody, - operationType, authorization); + final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters( + PASSTHROUGH_RUNNING.getDatastoreName(), yangModelCmHandle, resourceId, null, + null); + return dmiRestClient.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, + operationType, authorization); } private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) { @@ -192,22 +202,32 @@ public class DmiDataOperations { return jsonObjectMapper.asJsonString(dmiRequestBody); } - private String getDmiResourceDataUrl(final String datastoreName, - final YangModelCmHandle yangModelCmHandle, - final String resourceIdentifier, - final String optionsParamInQuery, - final String topicParamInQuery) { - final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA); - return DmiServiceUrlBuilder.newInstance() - .pathSegment("ch") - .variablePathSegment("cmHandleId", yangModelCmHandle.getId()) - .pathSegment("data") - .pathSegment("ds") - .variablePathSegment("datastore", datastoreName) - .queryParameter("resourceIdentifier", resourceIdentifier) - .queryParameter("options", optionsParamInQuery) - .queryParameter("topic", topicParamInQuery) - .build(dmiServiceName, dmiProperties.getDmiBasePath()); + private UrlTemplateParameters getUrlTemplateParameters(final String datastoreName, + final YangModelCmHandle yangModelCmHandle, + final String resourceIdentifier, + final String optionsParamInQuery, + final String topicParamInQuery) { + final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(DATA); + return DmiServiceUrlTemplateBuilder.newInstance() + .fixedPathSegment("ch") + .variablePathSegment("cmHandleId", yangModelCmHandle.getId()) + .fixedPathSegment("data") + .fixedPathSegment("ds") + .variablePathSegment("datastore", datastoreName) + .queryParameter("resourceIdentifier", resourceIdentifier) + .queryParameter("options", optionsParamInQuery) + .queryParameter("topic", topicParamInQuery) + .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath()); + } + + private UrlTemplateParameters getUrlTemplateParameters(final String dmiServiceName, + final String requestId, + final String topicParamInQuery) { + return DmiServiceUrlTemplateBuilder.newInstance() + .fixedPathSegment("data") + .queryParameter("requestId", requestId) + .queryParameter("topic", topicParamInQuery) + .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath()); } private void validateIfCmHandleStateReady(final YangModelCmHandle yangModelCmHandle, @@ -219,51 +239,37 @@ public class DmiDataOperations { } } - private static Set<String> getDistinctCmHandleIdsFromDataOperationRequest(final DataOperationRequest - dataOperationRequest) { + private static Set<String> getDistinctCmHandleIds(final DataOperationRequest dataOperationRequest) { return dataOperationRequest.getDataOperationDefinitions().stream() .flatMap(dataOperationDefinition -> dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet()); } - private void buildDataOperationRequestUrlAndSendToDmiService(final String requestId, - final String topicParamInQuery, - final Map<String, List<DmiDataOperation>> - groupsOutPerDmiServiceName, - final String authorization) { - - Flux.fromIterable(groupsOutPerDmiServiceName.entrySet()) - .flatMap(dmiDataOperationsByDmiServiceName -> { - final String dmiServiceName = dmiDataOperationsByDmiServiceName.getKey(); - final String dmiUrl = buildDmiServiceUrl(dmiServiceName, requestId, topicParamInQuery); - final List<DmiDataOperation> dmiDataOperationRequestBodies - = dmiDataOperationsByDmiServiceName.getValue(); - return sendDataOperationRequestToDmiService(dmiUrl, dmiDataOperationRequestBodies, authorization); - }) - .subscribe(); - } - - private String buildDmiServiceUrl(final String dmiServiceName, final String requestId, - final String topicParamInQuery) { - return DmiServiceUrlBuilder.newInstance() - .pathSegment("data") - .queryParameter("requestId", requestId) - .queryParameter("topic", topicParamInQuery) - .build(dmiServiceName, dmiProperties.getDmiBasePath()); - } + private void asyncSendMultipleRequest(final String requestId, final String topicParamInQuery, + final Map<String, List<DmiDataOperation>> dmiDataOperationsPerDmi, + final String authorization) { - private Mono<Void> sendDataOperationRequestToDmiService(final String dmiUrl, - final List<DmiDataOperation> dmiDataOperationRequestBodies, - final String authorization) { - final String dmiDataOperationRequestAsJsonString - = createDmiDataOperationRequestAsJsonString(dmiDataOperationRequestBodies); - return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, dmiUrl, dmiDataOperationRequestAsJsonString, - READ, authorization) - .then() - .onErrorResume(DmiClientRequestException.class, dmiClientRequestException -> { - handleTaskCompletionException(dmiClientRequestException, dmiUrl, dmiDataOperationRequestBodies); - return Mono.empty(); - }); + Flux.fromIterable(dmiDataOperationsPerDmi.entrySet()) + .flatMap(entry -> { + final String dmiServiceName = entry.getKey(); + final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(dmiServiceName, + requestId, topicParamInQuery); + final List<DmiDataOperation> dmiDataOperations = entry.getValue(); + final String dmiDataOperationRequestAsJsonString + = createDmiDataOperationRequestAsJsonString(dmiDataOperations); + return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters, + dmiDataOperationRequestAsJsonString, READ, authorization) + .then() + .onErrorResume(DmiClientRequestException.class, dmiClientRequestException -> { + final String dataOperationResourceUrl = UriComponentsBuilder + .fromUriString(urlTemplateParameters.urlTemplate()) + .buildAndExpand(urlTemplateParameters.urlVariables()) + .toUriString(); + handleTaskCompletionException(dmiClientRequestException, dataOperationResourceUrl, + dmiDataOperations); + return Mono.empty(); + }); + }).subscribe(); } private String createDmiDataOperationRequestAsJsonString( @@ -276,7 +282,7 @@ public class DmiDataOperations { private void handleTaskCompletionException(final DmiClientRequestException dmiClientRequestException, final String dataOperationResourceUrl, - final List<DmiDataOperation> dmiDataOperationRequestBodies) { + final List<DmiDataOperation> dmiDataOperations) { final MultiValueMap<String, String> dataOperationResourceUrlParameters = UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams(); final String topicName = dataOperationResourceUrlParameters.get("topic").get(0); @@ -285,13 +291,13 @@ public class DmiDataOperations { final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>> cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>(); - dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> { + dmiDataOperations.forEach(dmiDataOperationRequestBody -> { final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream() .map(DmiOperationCmHandle::getId).toList(); cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody, Map.of(dmiClientRequestException.getNcmpResponseStatus(), cmHandleIds)); }); - ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId, + DmiDataOperationsHelper.publishErrorMessageToClientTopic(topicName, requestId, cmHandleIdsPerResponseCodesPerOperation); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpCachedResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java index da230cf732..bff2f6390c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpCachedResourceRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java @@ -18,13 +18,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl; +package org.onap.cps.ncmp.impl.data; import java.util.Collection; import lombok.RequiredArgsConstructor; import org.onap.cps.api.CpsDataService; -import org.onap.cps.ncmp.api.NetworkCmProxyQueryService; -import org.onap.cps.ncmp.api.models.CmResourceAddress; +import org.onap.cps.ncmp.api.data.models.CmResourceAddress; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.springframework.stereotype.Service; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandler.java index 302ba449c7..f0a8c6c5d2 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandler.java @@ -18,13 +18,13 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl; +package org.onap.cps.ncmp.impl.data; import java.util.Map; import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.models.CmResourceAddress; -import org.onap.cps.ncmp.utils.TopicValidator; +import org.onap.cps.ncmp.api.data.models.CmResourceAddress; +import org.onap.cps.ncmp.utils.events.TopicValidator; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java index 0fd32501c3..be2dde2308 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java @@ -18,23 +18,22 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl; +package org.onap.cps.ncmp.impl.data; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ; +import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL; +import static org.onap.cps.ncmp.api.data.models.OperationType.READ; import java.util.Map; import java.util.UUID; import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; -import org.onap.cps.ncmp.api.impl.operations.OperationType; -import org.onap.cps.ncmp.api.models.CmResourceAddress; -import org.onap.cps.ncmp.api.models.DataOperationRequest; -import org.onap.cps.ncmp.exceptions.OperationNotSupportedException; +import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException; +import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException; +import org.onap.cps.ncmp.api.data.models.CmResourceAddress; +import org.onap.cps.ncmp.api.data.models.DataOperationRequest; +import org.onap.cps.ncmp.api.data.models.DatastoreType; +import org.onap.cps.ncmp.api.data.models.OperationType; import org.onap.cps.ncmp.exceptions.PayloadTooLargeException; -import org.onap.cps.ncmp.utils.TopicValidator; +import org.onap.cps.ncmp.utils.events.TopicValidator; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java index a24b18446e..503915716e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyFacade.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java @@ -22,18 +22,17 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl; +package org.onap.cps.ncmp.impl.data; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL; +import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL; import java.util.Collection; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; -import org.onap.cps.ncmp.api.impl.operations.OperationType; -import org.onap.cps.ncmp.api.models.CmResourceAddress; -import org.onap.cps.ncmp.api.models.DataOperationRequest; +import org.onap.cps.ncmp.api.data.models.CmResourceAddress; +import org.onap.cps.ncmp.api.data.models.DataOperationRequest; +import org.onap.cps.ncmp.api.data.models.DatastoreType; +import org.onap.cps.ncmp.api.data.models.OperationType; import org.onap.cps.spi.model.DataNode; import org.springframework.stereotype.Service; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryService.java index 39d497217f..39abdc56a0 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyQueryService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryService.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api; +package org.onap.cps.ncmp.impl.data; import java.util.Collection; import org.onap.cps.spi.FetchDescendantsOption; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImpl.java index 8507fb773f..021924a616 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImpl.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl; +package org.onap.cps.ncmp.impl.data; import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME; @@ -26,7 +26,6 @@ import java.util.Collection; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsQueryService; -import org.onap.cps.ncmp.api.NetworkCmProxyQueryService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.springframework.stereotype.Service; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/AsyncRestRequestResponseEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/AsyncRestRequestResponseEventConsumer.java index 993e3d63db..f14bb15842 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/AsyncRestRequestResponseEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/AsyncRestRequestResponseEventConsumer.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async; +package org.onap.cps.ncmp.impl.data.async; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumer.java index 9bb7fae4d9..6f368da2d0 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumer.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async; +package org.onap.cps.ncmp.impl.data.async; import io.cloudevents.CloudEvent; import io.cloudevents.kafka.impl.KafkaHeaders; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapper.java index 46a11b82a0..21d40339b2 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async; +package org.onap.cps.ncmp.impl.data.async; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategies.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategies.java index 0404790408..2615672374 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategies.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategies.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async; +package org.onap.cps.ncmp.impl.data.async; import io.cloudevents.CloudEvent; import io.cloudevents.kafka.impl.KafkaHeaders; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperation.java index 7baac34b1f..649d3ad374 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperation.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.data.models; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.List; import lombok.Builder; import lombok.Getter; -import org.onap.cps.ncmp.api.models.DataOperationDefinition; +import org.onap.cps.ncmp.api.data.models.DataOperationDefinition; +import org.onap.cps.ncmp.api.data.models.DatastoreType; +import org.onap.cps.ncmp.api.data.models.OperationType; @JsonInclude(JsonInclude.Include.NON_NULL) @Getter diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperationRequest.java index 8ee1d905bf..f342f04a1a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationRequest.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperationRequest.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.data.models; import com.fasterxml.jackson.annotation.JsonInclude; import java.util.List; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiOperationCmHandle.java index 1bf2b77dcc..6926b6890e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiOperationCmHandle.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.data.models; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DataOperationEventCreator.java index 42bad89f52..d74abb9935 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DataOperationEventCreator.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.utils.data.operation; +package org.onap.cps.ncmp.impl.data.utils; import io.cloudevents.CloudEvent; import java.util.ArrayList; @@ -29,11 +29,11 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NcmpResponseStatus; -import org.onap.cps.ncmp.api.impl.events.NcmpEvent; -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation; import org.onap.cps.ncmp.events.async1_0_0.Data; import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent; import org.onap.cps.ncmp.events.async1_0_0.Response; +import org.onap.cps.ncmp.impl.data.models.DmiDataOperation; +import org.onap.cps.ncmp.utils.events.NcmpEvent; import org.springframework.util.MultiValueMap; @Slf4j diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java index bb0c9a3150..ab2f106449 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.utils.data.operation; +package org.onap.cps.ncmp.impl.data.utils; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_READY; @@ -37,12 +37,12 @@ import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.events.EventsPublisher; import org.onap.cps.ncmp.api.NcmpResponseStatus; -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation; -import org.onap.cps.ncmp.api.impl.operations.DmiOperationCmHandle; +import org.onap.cps.ncmp.api.data.models.DataOperationDefinition; +import org.onap.cps.ncmp.api.data.models.DataOperationRequest; import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext; -import org.onap.cps.ncmp.api.models.DataOperationDefinition; -import org.onap.cps.ncmp.api.models.DataOperationRequest; +import org.onap.cps.ncmp.impl.data.models.DmiDataOperation; +import org.onap.cps.ncmp.impl.data.models.DmiOperationCmHandle; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.springframework.util.LinkedMultiValueMap; @@ -50,7 +50,7 @@ import org.springframework.util.MultiValueMap; @NoArgsConstructor(access = AccessLevel.PRIVATE) @Slf4j -public class ResourceDataOperationRequestUtils { +public class DmiDataOperationsHelper { private static final String UNKNOWN_SERVICE_NAME = null; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java index 8027e69d56..973a2a9b2d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.data.models.OperationType; import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata; import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation; import org.onap.cps.ncmp.api.datajobs.models.ProducerKey; @@ -32,9 +33,9 @@ import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteRequest; import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; import org.onap.cps.ncmp.api.impl.config.DmiProperties; -import org.onap.cps.ncmp.api.impl.operations.OperationType; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; -import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; +import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -64,10 +65,10 @@ public class DmiSubJobRequestHandler { final SubJobWriteRequest subJobWriteRequest = new SubJobWriteRequest(dataJobMetadata.dataAcceptType(), dataJobMetadata.dataContentType(), dataJobId, dmi3ggpWriteOperations); - final String dmiResourceUrl = getDmiResourceUrl(dataJobId, producerKey); + final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(dataJobId, producerKey); final ResponseEntity<Object> responseEntity = dmiRestClient.synchronousPostOperationWithJsonData( RequiredDmiService.DATA, - dmiResourceUrl, + urlTemplateParameters, jsonObjectMapper.asJsonString(subJobWriteRequest), OperationType.CREATE, NO_AUTH_HEADER); @@ -78,8 +79,10 @@ public class DmiSubJobRequestHandler { return subJobWriteResponses; } - private String getDmiResourceUrl(final String dataJobId, final ProducerKey producerKey) { - return DmiServiceUrlBuilder.newInstance().pathSegment("writeJob").variablePathSegment("requestId", dataJobId) - .build(producerKey.dmiServiceName(), dmiProperties.getDmiBasePath()); + private UrlTemplateParameters getUrlTemplateParameters(final String dataJobId, final ProducerKey producerKey) { + return DmiServiceUrlTemplateBuilder.newInstance() + .fixedPathSegment("writeJob") + .variablePathSegment("requestId", dataJobId) + .createUrlTemplateParameters(producerKey.dmiServiceName(), dmiProperties.getDmiBasePath()); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/AlternateIdChecker.java index 7ddde643aa..1096980e1d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/AlternateIdChecker.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.utils; +package org.onap.cps.ncmp.impl.inventory; import java.util.ArrayList; import java.util.Collection; @@ -28,7 +28,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; import org.springframework.stereotype.Service; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java index 1cbba7d6c7..d6ddd108ea 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java @@ -47,8 +47,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; -import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder; @@ -59,6 +57,7 @@ import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.ncmp.impl.inventory.sync.ModuleOperationsUtils; +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig; import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager; import org.onap.cps.spi.exceptions.AlreadyDefinedException; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java index fe47c0e2f2..c9981dba9a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java @@ -45,7 +45,6 @@ import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; -import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java index d96c9c7206..b10155c4a9 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java @@ -34,9 +34,9 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.commons.lang3.StringUtils; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; /** * Cm Handle which follows the Yang resource dmi registry model when persisting data to DMI or the DB. 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/impl/inventory/sync/DmiModelOperations.java index f1fdbea7f6..c1f89b3440 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/impl/inventory/sync/DmiModelOperations.java @@ -19,15 +19,13 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.inventory.sync; -import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ; -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL; +import static org.onap.cps.ncmp.api.data.models.OperationType.READ; +import static org.onap.cps.ncmp.impl.models.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; @@ -37,9 +35,11 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; import org.onap.cps.ncmp.api.impl.config.DmiProperties; -import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; +import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; import org.onap.cps.ncmp.api.inventory.models.YangResource; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.models.DmiRequestBody; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.http.ResponseEntity; @@ -107,12 +107,13 @@ public class DmiModelOperations { final String jsonRequestBody, final String cmHandle, final String resourceName) { - final String dmiUrl = DmiServiceUrlBuilder.newInstance() - .pathSegment("ch") + final UrlTemplateParameters urlTemplateParameters = DmiServiceUrlTemplateBuilder.newInstance() + .fixedPathSegment("ch") .variablePathSegment("cmHandleId", cmHandle) - .variablePathSegment("resourceName", resourceName) - .build(dmiServiceName, dmiProperties.getDmiBasePath()); - return dmiRestClient.synchronousPostOperationWithJsonData(MODEL, dmiUrl, jsonRequestBody, READ, null); + .fixedPathSegment(resourceName) + .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath()); + return dmiRestClient.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, jsonRequestBody, READ, + null); } private static String getRequestBodyToFetchYangResources(final Collection<ModuleReference> newModuleReferences, @@ -123,8 +124,7 @@ public class DmiModelOperations { data.add("modules", moduleReferencesAsJson); final JsonObject jsonRequestObject = new JsonObject(); if (!moduleSetTag.isEmpty()) { - final JsonElement moduleSetTagAsJson = JsonParser.parseString(moduleSetTag); - jsonRequestObject.add("moduleSetTag", moduleSetTagAsJson); + jsonRequestObject.addProperty("moduleSetTag", moduleSetTag); } jsonRequestObject.add("data", data); jsonRequestObject.add("cmHandleProperties", toJsonObject(dmiProperties)); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java index e344be8e1f..69fb7f59f5 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java @@ -36,8 +36,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; import org.onap.cps.ncmp.api.inventory.models.CompositeState; +import org.onap.cps.ncmp.impl.data.DmiDataOperations; import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java index 57d28aa743..d2bc3ada86 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java @@ -38,7 +38,6 @@ 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.operations.DmiModelOperations; import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java index 08db195ad6..39ea38aafc 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java @@ -29,12 +29,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.impl.utils.YangDataConverter; import org.onap.cps.spi.model.DataNode; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java index f7707d9f76..7395838306 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; import org.mapstruct.Mapper; import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java index a8d00f7e31..4bc2f10218 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; public enum LcmEventType { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java index 3a49957864..6cce153269 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; import java.util.Collection; import java.util.Map; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java index af745caa44..cf7921c350 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; import java.util.Collection; import lombok.RequiredArgsConstructor; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java index 4376014f36..b1b7b955f7 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java index 4231c99678..3ce6b91590 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; import java.util.UUID; import lombok.Getter; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java index 7c7a9722ce..348894d1b4 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java @@ -18,12 +18,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; -import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.CREATE; -import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.DELETE; -import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.UPDATE; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED; +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.CREATE; +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.DELETE; +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.UPDATE; import com.google.common.collect.MapDifference; import com.google.common.collect.Maps; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java index f51b58c3ef..10aebfa45d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm; +package org.onap.cps.ncmp.impl.inventory.sync.lcm; import io.micrometer.core.annotation.Timed; import java.util.Map; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java index 64ae800879..617fe7f01d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java @@ -24,9 +24,9 @@ import io.cloudevents.CloudEvent; import io.cloudevents.kafka.impl.KafkaHeaders; import lombok.RequiredArgsConstructor; import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel; +import org.onap.cps.ncmp.utils.events.CloudEventMapper; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java index 19597a205b..8be8ead44c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java @@ -25,6 +25,8 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; +import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; import org.springframework.beans.factory.annotation.Qualifier; @@ -50,10 +52,8 @@ public class DmiPluginTrustLevelWatchDog { */ @Scheduled(fixedDelayString = "${ncmp.timers.trust-level.dmi-availability-watchdog-ms:30000}") public void checkDmiAvailability() { - trustLevelPerDmiPlugin.entrySet().forEach(entry -> { + trustLevelPerDmiPlugin.forEach((dmiServiceName, oldDmiTrustLevel) -> { final TrustLevel newDmiTrustLevel; - final TrustLevel oldDmiTrustLevel = entry.getValue(); - final String dmiServiceName = entry.getKey(); final String dmiHealthStatus = getDmiHealthStatus(dmiServiceName); log.debug("The health status for dmi-plugin: {} is {}", dmiServiceName, dmiHealthStatus); @@ -72,7 +72,9 @@ public class DmiPluginTrustLevelWatchDog { }); } - private String getDmiHealthStatus(final String dmiServiceName) { - return dmiRestClient.getDmiHealthStatus(dmiServiceName); + private String getDmiHealthStatus(final String dmiServiceBaseUrl) { + final UrlTemplateParameters urlTemplateParameters = DmiServiceUrlTemplateBuilder.newInstance() + .createUrlTemplateParametersForHealthCheck(dmiServiceBaseUrl); + return dmiRestClient.getDmiHealthStatus(urlTemplateParameters).block(); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java index c7bfb1dbb9..44079c0bc9 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java @@ -24,11 +24,11 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; +import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -44,7 +44,7 @@ public class TrustLevelManager { private final Map<String, TrustLevel> trustLevelPerDmiPlugin; private final InventoryPersistence inventoryPersistence; - private final AvcEventPublisher avcEventPublisher; + private final CmAvcEventPublisher cmAvcEventPublisher; private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; private static final String AVC_NO_OLD_VALUE = null; @@ -65,7 +65,7 @@ public class TrustLevelManager { } trustLevelPerCmHandle.put(cmHandleId, initialTrustLevel); if (TrustLevel.NONE.equals(initialTrustLevel)) { - avcEventPublisher.publishAvcEvent(cmHandleId, + cmAvcEventPublisher.publishAvcEvent(cmHandleId, AVC_CHANGED_ATTRIBUTE_NAME, AVC_NO_OLD_VALUE, initialTrustLevel.name()); @@ -126,7 +126,7 @@ public class TrustLevelManager { } else { log.info("The trust level for Cm Handle: {} is now: {} ", notificationCandidateCmHandleId, newEffectiveTrustLevel); - avcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId, + cmAvcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId, AVC_CHANGED_ATTRIBUTE_NAME, oldEffectiveTrustLevel.name(), newEffectiveTrustLevel.name()); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/DmiRequestBody.java index f10b4f920f..6b05385693 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/DmiRequestBody.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.models; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import lombok.Builder; import lombok.Getter; +import org.onap.cps.ncmp.api.data.models.OperationType; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/RequiredDmiService.java index 7e39766f3f..c0c4f73f2a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/RequiredDmiService.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations; +package org.onap.cps.ncmp.impl.models; /** * Enmm to determine if the required service is for a data or model operation. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java index 130defb306..2592703449 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java @@ -29,8 +29,8 @@ import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; +import org.onap.cps.ncmp.api.data.models.DatastoreType; import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException; -import org.onap.cps.ncmp.api.impl.operations.DatastoreType; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.springframework.stereotype.Service; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java index 4120970e52..4462b169e2 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.mapper; +package org.onap.cps.ncmp.utils.events; import com.fasterxml.jackson.databind.ObjectMapper; import io.cloudevents.CloudEvent; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java index 7afe606f4f..06269d5177 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient; +package org.onap.cps.ncmp.utils.events; import io.cloudevents.CloudEvent; import java.util.Collections; @@ -26,16 +26,16 @@ import java.util.HashMap; import java.util.Map; import lombok.RequiredArgsConstructor; import org.onap.cps.events.EventsPublisher; -import org.onap.cps.ncmp.api.impl.events.NcmpEvent; import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc; import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent; import org.onap.cps.ncmp.events.avc.ncmp_to_client.Data; +import org.onap.cps.ncmp.utils.events.NcmpEvent; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor -public class AvcEventPublisher { +public class CmAvcEventPublisher { private final EventsPublisher<CloudEvent> eventsPublisher; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java index 248db9805c..67128bd159 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events; +package org.onap.cps.ncmp.utils.events; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/TopicValidator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java index f9fed8d437..a7ad86cda5 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/TopicValidator.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.utils; +package org.onap.cps.ncmp.utils.events; import java.util.regex.Pattern; import lombok.AccessLevel; diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DatastoreTypeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/DatastoreTypeSpec.groovy index 7e364c97c5..3a6737d3ca 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DatastoreTypeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/DatastoreTypeSpec.groovy @@ -18,9 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations +package org.onap.cps.ncmp.api.data.models -import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException +import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException import spock.lang.Specification class DatastoreTypeSpec extends Specification { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/OperationTypeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/OperationTypeSpec.groovy index d31b8d4fdf..efe67abef5 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/OperationTypeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/OperationTypeSpec.groovy @@ -18,9 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations +package org.onap.cps.ncmp.api.data.models -import org.onap.cps.ncmp.api.impl.exception.InvalidOperationException +import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException import spock.lang.Specification class OperationTypeSpec extends Specification { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy index 8dc3d223b6..6dcd022c0a 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy @@ -1,15 +1,15 @@ package org.onap.cps.ncmp.api.impl import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.data.models.OperationType import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation import org.onap.cps.ncmp.api.datajobs.models.ProducerKey import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse import org.onap.cps.ncmp.api.impl.client.DmiRestClient import org.onap.cps.ncmp.api.impl.config.DmiProperties -import org.onap.cps.ncmp.api.impl.operations.OperationType -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService import org.onap.cps.ncmp.impl.datajobs.DmiSubJobRequestHandler +import org.onap.cps.ncmp.impl.models.RequiredDmiService import org.onap.cps.utils.JsonObjectMapper import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity 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 bb73c6879e..a935d70ce6 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 @@ -26,12 +26,14 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.node.ObjectNode import org.onap.cps.ncmp.api.impl.config.DmiProperties import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException -import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus +import org.springframework.http.HttpStatusCode import org.springframework.http.ResponseEntity +import org.springframework.web.client.HttpServerErrorException import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.WebClientRequestException import org.springframework.web.reactive.function.client.WebClientResponseException @@ -41,17 +43,16 @@ import spock.lang.Specification import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR -import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE -import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH -import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL +import static org.onap.cps.ncmp.api.data.models.OperationType.READ +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL class DmiRestClientSpec extends Specification { static final NO_AUTH_HEADER = null static final BASIC_AUTH_HEADER = 'Basic c29tZSB1c2VyOnNvbWUgcGFzc3dvcmQ=' static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token' + static final urlTemplateParameters = new UrlTemplateParameters('/{pathParam1}/{pathParam2}', ['pathParam1': 'my', 'pathParam2': 'url']) def mockDataServicesWebClient = Mock(WebClient) def mockModelServicesWebClient = Mock(WebClient) @@ -67,7 +68,7 @@ class DmiRestClientSpec extends Specification { DmiRestClient objectUnderTest = new DmiRestClient(mockDmiProperties, jsonObjectMapper, mockDataServicesWebClient, mockModelServicesWebClient, mockHealthChecksWebClient) def setup() { - mockRequestBody.uri(_) >> mockRequestBody + mockRequestBody.uri(_,_) >> mockRequestBody mockRequestBody.headers(_) >> mockRequestBody mockRequestBody.body(_) >> mockRequestBody mockRequestBody.retrieve() >> mockResponse @@ -78,7 +79,7 @@ class DmiRestClientSpec extends Specification { mockDataServicesWebClient.post() >> mockRequestBody mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Data service', HttpStatus.I_AM_A_TEAPOT)) when: 'POST operation is invoked fro Data Service' - def response = objectUnderTest.synchronousPostOperationWithJsonData(DATA, '/my/url', 'some json', READ, NO_AUTH_HEADER) + def response = objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) then: 'the output of the method is equal to the output from the test template' assert response.statusCode == HttpStatus.I_AM_A_TEAPOT assert response.body == 'from Data service' @@ -89,30 +90,18 @@ class DmiRestClientSpec extends Specification { mockModelServicesWebClient.post() >> mockRequestBody mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Model service', HttpStatus.I_AM_A_TEAPOT)) when: 'POST operation is invoked for Model Service' - def response = objectUnderTest.synchronousPostOperationWithJsonData(MODEL, '/my/url', 'some json', READ, NO_AUTH_HEADER) + def response = objectUnderTest.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) then: 'the output of the method is equal to the output from the test template' assert response.statusCode == HttpStatus.I_AM_A_TEAPOT assert response.body == 'from Model service' } - def 'Failing DMI POST operation due to invalid dmi resource url.'() { - when: 'POST operation is invoked with invalid dmi resource url' - objectUnderTest.synchronousPostOperationWithJsonData(DATA, '/invalid dmi url', null, null, NO_AUTH_HEADER) - then: 'invalid dmi resource url exception is thrown' - def thrown = thrown(InvalidDmiResourceUrlException) - and: 'the exception has the relevant details from the error response' - thrown.httpStatus == 400 - thrown.message == 'Invalid dmi resource url: /invalid dmi url' - where: 'the following operations are executed' - operation << [CREATE, READ, PATCH] - } - def 'Dmi service sends client error response when #scenario'() { given: 'the web client unable to return response entity but error' mockDataServicesWebClient.post() >> mockRequestBody mockResponse.toEntity(Object.class) >> Mono.error(exceptionType) when: 'POST operation is invoked' - objectUnderTest.synchronousPostOperationWithJsonData(DATA, '/my/url', 'some json', READ, NO_AUTH_HEADER) + objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) then: 'a http client exception is thrown' def thrown = thrown(DmiClientRequestException) and: 'the exception has the relevant details from the error response' @@ -123,6 +112,7 @@ class DmiRestClientSpec extends Specification { 'dmi service unavailable' | 503 | new WebClientRequestException(new RuntimeException('some-error'), null, null, new HttpHeaders()) || DMI_SERVICE_NOT_RESPONDING 'dmi request timeout' | 408 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || DMI_SERVICE_NOT_RESPONDING 'dmi server error' | 500 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || UNABLE_TO_READ_RESOURCE_DATA + 'dmi service unavailable' | 503 | new HttpServerErrorException(HttpStatusCode.valueOf(503)) || DMI_SERVICE_NOT_RESPONDING 'unknown error' | 500 | new Throwable('message') || UNKNOWN_ERROR } @@ -132,25 +122,29 @@ class DmiRestClientSpec extends Specification { def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class) ((ObjectNode) jsonNode).put('status', 'my status') mockHealthChecksWebClient.get() >> mockRequestBody + mockResponse.onStatus(_,_)>> mockResponse mockResponse.bodyToMono(JsonNode.class) >> Mono.just(jsonNode) when: 'get trust level of the dmi plugin' - def result = objectUnderTest.getDmiHealthStatus('some/url') + def urlTemplateParameters = new UrlTemplateParameters('some url', [:]) + def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block() then: 'the status value from the json is returned' assert result == 'my status' } def 'Failing to get dmi plugin health status #scenario'() { - given: 'rest template with #scenario' + given: 'web client instance with #scenario' mockHealthChecksWebClient.get() >> mockRequestBody - mockResponse.bodyToMono(_) >> healthStatusResponse + mockResponse.onStatus(_, _) >> mockResponse + mockResponse.bodyToMono(_) >> Mono.error(exceptionType) when: 'attempt to get health status of the dmi plugin' - def result = objectUnderTest.getDmiHealthStatus('some url') + def urlTemplateParameters = new UrlTemplateParameters('some url', [:]) + def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block() then: 'result will be empty' assert result == '' where: 'the following responses are used' - scenario | healthStatusResponse - 'null' | null - 'exception' | { throw new Exception() } + scenario | exceptionType + 'dmi request timeout' | new WebClientResponseException('some-message', 408, 'some-text', null, null, null) + 'dmi service unavailable' | new HttpServerErrorException(HttpStatus.SERVICE_UNAVAILABLE) } def 'DMI auth header #scenario'() { 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 index 05ecaa11b1..fa995aa7c3 100644 --- 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 @@ -33,6 +33,13 @@ import spock.lang.Specification @EnableConfigurationProperties class DmiWebClientConfigurationSpec extends Specification { + def webClientBuilder = Mock(WebClient.Builder) { + defaultHeaders(_) >> it + clientConnector(_) >> it + codecs(_) >> it + build() >> Mock(WebClient) + } + def httpClientConfiguration = Spy(HttpClientConfiguration.class) def objectUnderTest = new DmiWebClientConfiguration(httpClientConfiguration) @@ -44,7 +51,7 @@ class DmiWebClientConfigurationSpec extends Specification { def 'Creating a web client instance data service.'() { given: 'Web client configuration is invoked' - def dataServicesWebClient = objectUnderTest.dataServicesWebClient() + def dataServicesWebClient = objectUnderTest.dataServicesWebClient(webClientBuilder) expect: 'the system can create an instance for data service' assert dataServicesWebClient != null assert dataServicesWebClient instanceof WebClient @@ -52,7 +59,7 @@ class DmiWebClientConfigurationSpec extends Specification { def 'Creating a web client instance model service.'() { given: 'Web client configuration invoked' - def modelServicesWebClient = objectUnderTest.modelServicesWebClient() + def modelServicesWebClient = objectUnderTest.modelServicesWebClient(webClientBuilder) expect: 'the system can create an instance for model service' assert modelServicesWebClient != null assert modelServicesWebClient instanceof WebClient @@ -60,7 +67,7 @@ class DmiWebClientConfigurationSpec extends Specification { def 'Creating a web client instance health service.'() { given: 'Web client configuration invoked' - def healthChecksWebClient = objectUnderTest.healthChecksWebClient() + def healthChecksWebClient = objectUnderTest.healthChecksWebClient(webClientBuilder) expect: 'the system can create an instance for health service' assert healthChecksWebClient != null assert healthChecksWebClient instanceof WebClient diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy index 07395cf5bc..07395cf5bc 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryConfigSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy deleted file mode 100644 index 75db0bfe51..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy +++ /dev/null @@ -1,60 +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.events.cmsubscription - -import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate -import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService -import org.onap.cps.ncmp.api.impl.operations.DatastoreType -import spock.lang.Specification - -class CmNotificationSubscriptionDeltaSpec extends Specification { - - def mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService) - def objectUnderTest = new CmNotificationSubscriptionDelta(mockCmNotificationSubscriptionPersistenceService) - - def 'Find Delta of given list of predicates'() { - given: 'A list of predicates' - def predicateList = [new DmiCmNotificationSubscriptionPredicate(['ch-1','ch-2'].toSet(), DatastoreType.PASSTHROUGH_OPERATIONAL, ['a/1/','b/2'].toSet())] - and: '3 positive responses and 1 negative.' - mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true - mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-1', 'b/2') >>> true - mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-2', 'a/1/') >>> true - mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-2', 'b/2') >>> false - when: 'getDelta is called' - def result = objectUnderTest.getDelta(predicateList) - then: 'verify correct delta is returned' - assert result.size() == 1 - assert result[0].targetCmHandleIds[0] == 'ch-2' - assert result[0].xpaths[0] == 'b/2' - - } - - def 'Find Delta of given list of predicates when it is an ongoing Cm Subscription'() { - given: 'A list of predicates' - def predicateList = [new DmiCmNotificationSubscriptionPredicate(['ch-1'].toSet(), DatastoreType.PASSTHROUGH_OPERATIONAL, ['a/1/'].toSet())] - and: 'its already present' - mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true - when: 'getDelta is called' - def result = objectUnderTest.getDelta(predicateList) - then: 'verify correct delta is returned' - assert result.size() == 0 - } - -} 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 deleted file mode 100644 index 788a7a7da5..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy +++ /dev/null @@ -1,58 +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.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 deleted file mode 100644 index bdc54bd1ee..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy +++ /dev/null @@ -1,64 +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.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/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy deleted file mode 100644 index 77bbe7ebc4..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy +++ /dev/null @@ -1,88 +0,0 @@ -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.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 -import org.onap.cps.utils.JsonObjectMapper -import spock.lang.Specification - -class CmNotificationSubscriptionNcmpOutEventProducerSpec extends Specification { - - def mockEventsPublisher = Mock(EventsPublisher) - def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler) - def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler) - - def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper, - mockCmNotificationSubscriptionMappersHandler, mockDmiCmNotificationSubscriptionCacheHandler) - - def 'Create and #scenario Cm Notification Subscription NCMP out event'() { - given: 'a cm subscription response for the client' - def subscriptionId = 'test-subscription-id-2' - def eventType = 'subscriptionCreateResponse' - def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-2', acceptedTargets: ['ch-1', 'ch-2'])) - and: 'also we have target topic for publishing to client' - objectUnderTest.cmNotificationSubscriptionNcmpOutEventTopic = 'client-test-topic' - and: 'a deadline to an event' - objectUnderTest.cmNotificationSubscriptionDmiOutEventTimeoutInMs = 1000 - when: 'the event is published' - objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent, eventPublishingTaskToBeScheduled) - then: 'we conditionally wait for a while' - Thread.sleep(delayInMs) - then: 'the event contains the required attributes' - 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { - args -> - { - assert args[0] == 'client-test-topic' - assert args[1] == subscriptionId - def cmNotificationSubscriptionNcmpOutEventAsCloudEvent = (args[2] as CloudEvent) - assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId - assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse' - assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.source.toString() == 'NCMP' - assert CloudEventMapper.toTargetEvent(cmNotificationSubscriptionNcmpOutEventAsCloudEvent, CmNotificationSubscriptionNcmpOutEvent) == cmNotificationSubscriptionNcmpOutEvent - } - } - where: 'following scenarios are considered' - scenario | delayInMs | eventPublishingTaskToBeScheduled - 'publish event now' | 0 | false - 'schedule and publish after the configured time ' | 1500 | true - } - - def 'Schedule Cm Notification Subscription NCMP out event but later publish it on demand'() { - given: 'a cm subscription response for the client' - def subscriptionId = 'test-subscription-id-3' - def eventType = 'subscriptionCreateResponse' - def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-3', acceptedTargets: ['ch-2', 'ch-3'])) - and: 'also we have target topic for publishing to client' - objectUnderTest.cmNotificationSubscriptionNcmpOutEventTopic = 'client-test-topic' - and: 'a deadline to an event' - objectUnderTest.cmNotificationSubscriptionDmiOutEventTimeoutInMs = 1000 - when: 'the event is scheduled to be published' - objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent, true) - then: 'we wait for 10ms and then we receive response from DMI' - Thread.sleep(10) - and: 'we receive response from DMI so we publish the message on demand' - objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent, false) - then: 'the event contains the required attributes' - 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { - args -> - { - assert args[0] == 'client-test-topic' - assert args[1] == subscriptionId - def cmNotificationSubscriptionNcmpOutEventAsCloudEvent = (args[2] as CloudEvent) - assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId - assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse' - assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.source.toString() == 'NCMP' - assert CloudEventMapper.toTargetEvent(cmNotificationSubscriptionNcmpOutEventAsCloudEvent, CmNotificationSubscriptionNcmpOutEvent) == cmNotificationSubscriptionNcmpOutEvent - } - } - then: 'the cache handler is called once to remove accepted and rejected entries in cache' - 1 * mockDmiCmNotificationSubscriptionCacheHandler.removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId) - } - - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy deleted file mode 100644 index f6bb24c2f2..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy +++ /dev/null @@ -1,64 +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.events.cmsubscription.mapper - -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.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate -import org.onap.cps.ncmp.api.impl.operations.DatastoreType -import spock.lang.Specification - -class CmNotificationSubscriptionNcmpOutEventMapperSpec extends Specification { - - static Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap - - def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventMapper() - - def setup() { - def dmiCmNotificationSubscriptionPredicateA = new DmiCmNotificationSubscriptionPredicate(['ch-A'] as Set, DatastoreType.PASSTHROUGH_RUNNING, ['/a'] as Set) - def dmiCmNotificationSubscriptionPredicateB = new DmiCmNotificationSubscriptionPredicate(['ch-B'] as Set, DatastoreType.PASSTHROUGH_OPERATIONAL, ['/b'] as Set) - def dmiCmNotificationSubscriptionPredicateC = new DmiCmNotificationSubscriptionPredicate(['ch-C'] as Set, DatastoreType.PASSTHROUGH_OPERATIONAL, ['/c'] as Set) - dmiCmNotificationSubscriptionDetailsMap = ['dmi-1': new DmiCmNotificationSubscriptionDetails([dmiCmNotificationSubscriptionPredicateA], CmNotificationSubscriptionStatus.PENDING), - 'dmi-2': new DmiCmNotificationSubscriptionDetails([dmiCmNotificationSubscriptionPredicateB], CmNotificationSubscriptionStatus.ACCEPTED), - 'dmi-3': new DmiCmNotificationSubscriptionDetails([dmiCmNotificationSubscriptionPredicateC], CmNotificationSubscriptionStatus.REJECTED) - ] - } - - def 'Check for Cm Notification Subscription Outgoing event mapping'() { - when: 'we try to map the event to send it to client' - def result = objectUnderTest.toCmNotificationSubscriptionNcmpOutEvent('test-subscription', dmiCmNotificationSubscriptionDetailsMap) - then: 'event is mapped correctly for the subscription' - result.data.subscriptionId == 'test-subscription' - and: 'the cm handle ids are part of correct list' - result.data.pendingTargets == ['ch-A'] - result.data.acceptedTargets == ['ch-B'] - result.data.rejectedTargets == ['ch-C'] - } - - def 'Check for Cm Notification Rejected Subscription Outgoing event mapping'() { - when: 'we try to map the event to send it to client' - def result = objectUnderTest.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest('test-subscription', ['ch-1', 'ch-2']) - then: 'event is mapped correctly for the subscription id' - result.data.subscriptionId == 'test-subscription' - and: 'the cm handle ids are part of correct list' - result.data.withRejectedTargets(['ch-1', 'ch-2']) - } -} 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 deleted file mode 100644 index 982150ec0a..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy +++ /dev/null @@ -1,147 +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.events.cmsubscription.service - -import com.fasterxml.jackson.databind.ObjectMapper -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.model.CmNotificationSubscriptionStatus -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.api.impl.operations.DatastoreType -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 - -class CmNotificationSubscriptionHandlerServiceImplSpec extends Specification{ - - def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - def mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService); - def mockCmNotificationSubscriptionDelta = Mock(CmNotificationSubscriptionDelta); - def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler); - def mockCmNotificationSubscriptionEventsHandler = Mock(CmNotificationSubscriptionEventsHandler); - def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler); - - def objectUnderTest = new CmNotificationSubscriptionHandlerServiceImpl(mockCmNotificationSubscriptionPersistenceService, - mockCmNotificationSubscriptionDelta, mockCmNotificationSubscriptionMappersHandler, - mockCmNotificationSubscriptionEventsHandler, mockDmiCmNotificationSubscriptionCacheHandler) - - def testSubscriptionDetailsMap = ["dmi-1":new DmiCmNotificationSubscriptionDetails([], CmNotificationSubscriptionStatus.PENDING)] - - def 'Consume valid and unique CmNotificationSubscriptionNcmpInEvent create message'() { - given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id' - def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') - def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class) - def testListOfDeltaPredicates = [new DmiCmNotificationSubscriptionPredicate(['ch1'].toSet(), DatastoreType.PASSTHROUGH_OPERATIONAL, ['/a/b'].toSet())] - mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true - and: 'relevant details is extracted from the event' - def subscriptionId = testEventConsumed.getData().getSubscriptionId() - def predicates = testEventConsumed.getData().getPredicates() - 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(subscriptionId, predicates) - then: 'the subscription cache handler is called once' - 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 Overlapping Cm Notification Subscription NcmpIn Event'() { - given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id' - def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') - def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class) - def noDeltaPredicates = [] - 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(_) >> noDeltaPredicates - when: 'the valid and unique event is consumed' - objectUnderTest.processSubscriptionCreateRequest('test-id', noDeltaPredicates) - then: 'the subscription cache handler is called once' - 1 * mockDmiCmNotificationSubscriptionCacheHandler.add('test-id', _) - and: 'the subscription details are updated in the cache' - 1 * mockDmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi('test-id', _, CmNotificationSubscriptionStatus.ACCEPTED) - 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('test-id') >> false - and: 'relevant details is extracted from the event' - def subscriptionId = testEventConsumed.getData().getSubscriptionId() - def predicates = testEventConsumed.getData().getPredicates() - 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(subscriptionId, predicates) - 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) - } - - def 'Consume valid CmNotificationSubscriptionNcmpInEvent delete message'() { - given: 'a cmNotificationSubscriptionNcmp in event for delete' - def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') - def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class) - and: 'relevant details is extracted from the event' - def subscriptionId = testEventConsumed.getData().getSubscriptionId() - def predicates = testEventConsumed.getData().getPredicates() - and: 'the cache handler returns for relevant subscription id' - 1 * mockDmiCmNotificationSubscriptionCacheHandler.get('test-id') >> testSubscriptionDetailsMap - when: 'the valid and unique event is consumed' - objectUnderTest.processSubscriptionDeleteRequest(subscriptionId, predicates) - then: 'the subscription cache handler is called once' - 1 * mockDmiCmNotificationSubscriptionCacheHandler.add('test-id', predicates) - and: 'the mapper handler to get DMI in event is called once' - 1 * mockCmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionDmiInEvent(_) - 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', 'subscriptionDeleteRequest', _) - and: 'we schedule to send the response after configured time from the cache' - 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent( - 'test-id', 'subscriptionDeleteResponse', null, true) - } -} 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 deleted file mode 100644 index 69d08e3de6..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-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.utils - -import spock.lang.Specification - -class DmiServiceUrlBuilderSpec extends Specification { - - def objectUnderTest = new DmiServiceUrlBuilder() - - def 'Build URI with (variable) path segments and parameters.'() { - given: 'the URI details are given to the builder' - objectUnderTest.pathSegment(segment1) - objectUnderTest.variablePathSegment('myVariableSegment','someValue') - objectUnderTest.pathSegment(segment2) - objectUnderTest.queryParameter('param1', paramValue1) - objectUnderTest.queryParameter('param2', paramValue2) - objectUnderTest.queryParameter('param3', null) - objectUnderTest.queryParameter('param4', '') - when: 'the URI (string) is build' - def result = objectUnderTest.build('myDmiServer', 'myBasePath') - then: 'the URI is correct (segments are in correct order) ' - assert result == expectedUri - where: 'following URI details are used' - segment1 | segment2 | paramValue1 | paramValue2 || expectedUri - 'segment1' | 'segment2' | '123' | 'abc' || 'myDmiServer/myBasePath/v1/segment1/someValue/segment2?param1=123¶m2=abc' - 'segment2' | 'segment1' | 'abc' | '123' || 'myDmiServer/myBasePath/v1/segment2/someValue/segment1?param1=abc¶m2=123' - } - - def 'Build URI with special characters in path segments.'() { - given: 'the path segments are given to the builder' - objectUnderTest.pathSegment(segment) - objectUnderTest.variablePathSegment('myVariableSegment', variableSegmentValue) - when: 'the URI (string) is build' - def result = objectUnderTest.build('myDmiServer', 'myBasePath') - then: 'Only teh characters that cause issues in path segments issues are encoded' - assert result == expectedUri - where: 'following variable path segments are used' - segment | variableSegmentValue || expectedUri - 'some/special?characters=are\\encoded' | 'my/variable/segment' || 'myDmiServer/myBasePath/v1/some%2Fspecial%3Fcharacters=are%5Cencoded/my%2Fvariable%2Fsegment' - 'but=some&are:not-!' | 'my&variable:segment' || 'myDmiServer/myBasePath/v1/but=some&are:not-!/my&variable:segment' - } - - def 'Build URI with special characters in query parameters.'() { - given: 'the query parameter is given to the builder' - objectUnderTest.queryParameter(paramName, value) - when: 'the URI (string) is build' - def result = objectUnderTest.build('myDmiServer', 'myBasePath') - then: 'Only the characters (in the name and value) that cause issues in query parameters are encoded' - assert result == expectedUri - where: 'the following query parameters are used' - paramName | value || expectedUri - 'my¶m' | 'some?special&characters=are\\encoded' || 'myDmiServer/myBasePath/v1?my%26param=some?special%26characters%3Dare%5Cencoded' - 'my-param' | 'but/some:are-not-!' || 'myDmiServer/myBasePath/v1?my-param=but/some:are-not-!' - } - - def 'Build URI with empty query parameters.'() { - when: 'the query parameter is given to the builder' - objectUnderTest.queryParameter('param', value) - and: 'the URI (string) is build' - def result = objectUnderTest.build('myDmiServer', 'myBasePath') - then: 'no parameter gets added' - assert result == 'myDmiServer/myBasePath/v1' - where: 'the following parameter values are used' - value << [ null, '', ' ' ] - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy new file mode 100644 index 0000000000..6d56f432d3 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-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.utils.url.builder + +import spock.lang.Specification + +class DmiServiceUrlTemplateBuilderSpec extends Specification { + + def objectUnderTest = new DmiServiceUrlTemplateBuilder() + + def 'Build URL template parameters with (variable) path segments and query parameters.'() { + given: 'the URL details are given to the builder' + objectUnderTest.fixedPathSegment('segment') + objectUnderTest.variablePathSegment('myVariableSegment','someValue') + objectUnderTest.fixedPathSegment('segment?with:special&characters') + objectUnderTest.queryParameter('param1', 'abc') + objectUnderTest.queryParameter('param2', 'value?with#special:characters') + when: 'the URL template parameters are created' + def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') + then: 'the URL template contains variable names instead of value and un-encoded fixed segment' + assert result.urlTemplate == 'myDmiServer/myBasePath/v1/segment/{myVariableSegment}/segment?with:special&characters?param1={param1}¶m2={param2}' + and: 'URL variables contains name and un-encoded value pairs' + assert result.urlVariables == ['myVariableSegment': 'someValue', 'param1': 'abc', 'param2': 'value?with#special:characters'] + } + + def 'Build URL template parameters with special characters in query parameters.'() { + given: 'the query parameter is given to the builder' + objectUnderTest.queryParameter('my¶m', 'special&characters=are?not\\encoded') + when: 'the URL template parameters are created' + def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') + then: 'Special characters are not encoded' + assert result.urlVariables == ['my¶m': 'special&characters=are?not\\encoded'] + } + + def 'Build URL template parameters with empty query parameters.'() { + when: 'the query parameter is given to the builder' + objectUnderTest.queryParameter('param', value) + and: 'the URL template parameters are create' + def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') + then: 'no parameter gets added' + assert result.urlVariables.isEmpty() + where: 'the following parameter values are used' + value << [ null, '', ' ' ] + } +} 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/impl/DmiOperationsBaseSpec.groovy index f224a5cc0e..050932f654 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/impl/DmiOperationsBaseSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations +package org.onap.cps.ncmp.impl import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.impl.client.DmiRestClient @@ -45,7 +45,7 @@ abstract class DmiOperationsBaseSpec extends Specification { ObjectMapper spyObjectMapper = Spy() def yangModelCmHandle = new YangModelCmHandle() - def static dmiServiceName = 'someServiceName' + def static dmiServiceName = 'myServiceName' def static cmHandleId = 'some-cm-handle' def static resourceIdentifier = 'parent/child' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfigSpec.groovy index e65011f715..915bccb53d 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfigSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfigSpec.groovy @@ -18,23 +18,23 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.config.embeddedcache +package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache import com.hazelcast.core.Hazelcast import com.hazelcast.map.IMap -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.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate -import org.onap.cps.ncmp.api.impl.operations.DatastoreType +import org.onap.cps.ncmp.api.data.models.DatastoreType +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import spock.lang.Specification -@SpringBootTest(classes = [CmNotificationSubscriptionCacheConfig]) -class CmNotificationSubscriptionCacheConfigSpec extends Specification { +@SpringBootTest(classes = [CmSubscriptionConfig]) +class CmSubscriptionConfigSpec extends Specification { @Autowired - IMap<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache; + IMap<String, Map<String, DmiCmSubscriptionDetails>> cmNotificationSubscriptionCache; def 'Embedded (hazelcast) cache for Cm Notification Subscription Cache.'() { expect: 'system is able to create an instance of the Cm Notification Subscription Cache' @@ -49,15 +49,15 @@ class CmNotificationSubscriptionCacheConfigSpec extends Specification { given: 'a cm subscription properties' def subscriptionId = 'sub123' def dmiPluginName = 'dummydmi' - def cmSubscriptionPredicate = new DmiCmNotificationSubscriptionPredicate(['cmhandle1', 'cmhandle2'].toSet(), DatastoreType.PASSTHROUGH_RUNNING, ['/a/b/c'].toSet()) - def cmSubscriptionCacheObject = new DmiCmNotificationSubscriptionDetails([cmSubscriptionPredicate], CmNotificationSubscriptionStatus.PENDING) + def cmSubscriptionPredicates = new DmiCmSubscriptionPredicate(['cmhandle1', 'cmhandle2'].toSet(), DatastoreType.PASSTHROUGH_RUNNING, ['/a/b/c'].toSet()) + def cmSubscriptionCacheObject = new DmiCmSubscriptionDetails([cmSubscriptionPredicates], CmSubscriptionStatus.PENDING) when: 'the cache is populated' cmNotificationSubscriptionCache.put(subscriptionId, [(dmiPluginName): cmSubscriptionCacheObject]) then: 'the values are present in memory' assert cmNotificationSubscriptionCache.get(subscriptionId) != null and: 'properties match' assert dmiPluginName == cmNotificationSubscriptionCache.get(subscriptionId).keySet()[0] - assert cmSubscriptionCacheObject.cmNotificationSubscriptionStatus == cmNotificationSubscriptionCache.get(subscriptionId).values().cmNotificationSubscriptionStatus[0] - assert cmSubscriptionCacheObject.dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds == cmNotificationSubscriptionCache.get(subscriptionId).values().dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds[0] + assert cmSubscriptionCacheObject.cmSubscriptionStatus == cmNotificationSubscriptionCache.get(subscriptionId).values().cmSubscriptionStatus[0] + assert cmSubscriptionCacheObject.dmiCmSubscriptionPredicates[0].targetCmHandleIds == cmNotificationSubscriptionCache.get(subscriptionId).values().dmiCmSubscriptionPredicates[0].targetCmHandleIds[0] } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy index 393432fc5e..b335843bb3 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy @@ -18,17 +18,17 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription +package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache 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.model.CmNotificationSubscriptionStatus -import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails -import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.onap.cps.ncmp.utils.TestUtils @@ -37,10 +37,10 @@ import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { +class DmiCacheHandlerSpec extends MessagingBaseSpec { @Autowired JsonObjectMapper jsonObjectMapper @@ -49,12 +49,12 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { @SpringBean InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence) @SpringBean - CmNotificationSubscriptionPersistenceService mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService) + CmSubscriptionPersistenceService mockCmSubscriptionPersistenceService = Mock(CmSubscriptionPersistenceService) def testCache = [:] - def objectUnderTest = new DmiCmNotificationSubscriptionCacheHandler(mockCmNotificationSubscriptionPersistenceService, testCache, mockInventoryPersistence) + def objectUnderTest = new DmiCacheHandler(mockCmSubscriptionPersistenceService, testCache, mockInventoryPersistence) - CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent + NcmpInEvent ncmpInEvent def yangModelCmHandle1 = new YangModelCmHandle(id:'ch1',dmiServiceName:'dmi-1') def yangModelCmHandle2 = new YangModelCmHandle(id:'ch2',dmiServiceName:'dmi-2') def yangModelCmHandle3 = new YangModelCmHandle(id:'ch3',dmiServiceName:'dmi-1') @@ -67,9 +67,9 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { def 'Load CM subscription event to cache'() { given: 'a valid subscription event with Id' - def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId() + def subscriptionId = ncmpInEvent.getData().getSubscriptionId() and: 'list of predicates' - def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates() + def predicates = ncmpInEvent.getData().getPredicates() when: 'a valid event object loaded in cache' objectUnderTest.add(subscriptionId, predicates) then: 'the cache contains the correct entry with #subscriptionId subscription ID' @@ -89,19 +89,19 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { given: 'a map as the value for cache entry for some-id' def testMap = [:] testMap.put("dmi-1", - new DmiCmNotificationSubscriptionDetails([],CmNotificationSubscriptionStatus.ACCEPTED)) + new DmiCmSubscriptionDetails([],CmSubscriptionStatus.ACCEPTED)) testMap.put("dmi-2", - new DmiCmNotificationSubscriptionDetails([],CmNotificationSubscriptionStatus.REJECTED)) + new DmiCmSubscriptionDetails([],CmSubscriptionStatus.REJECTED)) testMap.put("dmi-3", - new DmiCmNotificationSubscriptionDetails([],CmNotificationSubscriptionStatus.PENDING)) + new DmiCmSubscriptionDetails([],CmSubscriptionStatus.PENDING)) testCache.put("test-id", testMap) assert testCache.get("test-id").size() == 3 when: 'the method to remove accepted and rejected entries for test-id is called' - objectUnderTest.removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries("test-id") + objectUnderTest.removeAcceptedAndRejectedDmiSubscriptionEntries("test-id") then: 'all entries with status accepted/rejected are no longer present for test-id' testCache.get("test-id").each { key, testResultMap -> - assert testResultMap.cmNotificationSubscriptionStatus != CmNotificationSubscriptionStatus.ACCEPTED - || testResultMap.cmNotificationSubscriptionStatus != CmNotificationSubscriptionStatus.REJECTED + assert testResultMap.cmSubscriptionStatus != CmSubscriptionStatus.ACCEPTED + || testResultMap.cmSubscriptionStatus != CmSubscriptionStatus.REJECTED } and: 'the size of the map for cache entry test-id is as expected' assert testCache.get("test-id").size() == 1 @@ -109,9 +109,9 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { def 'Create map for DMI cm notification subscription per DMI service name'() { given: 'list of predicates from the create subscription event' - def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates() + def predicates = ncmpInEvent.getData().getPredicates() when: 'method to create map of DMI cm notification subscription per DMI service name is called' - def result = objectUnderTest.createDmiCmNotificationSubscriptionsPerDmi(predicates) + def result = objectUnderTest.createDmiSubscriptionsPerDmi(predicates) then: 'the result size of resulting map is correct to the number of DMIs' assert result.size() == 2 and: 'the cache objects per DMI exists' @@ -120,28 +120,28 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { assert resultMapForDmi1 != null assert resultMapForDmi2 != null and: 'the size of predicates in each object is correct' - assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates.size() == 2 - assert resultMapForDmi2.dmiCmNotificationSubscriptionPredicates.size() == 2 + assert resultMapForDmi1.dmiCmSubscriptionPredicates.size() == 2 + assert resultMapForDmi2.dmiCmSubscriptionPredicates.size() == 2 and: 'the subscription status in each object is correct' - assert resultMapForDmi1.cmNotificationSubscriptionStatus.toString() == 'PENDING' - assert resultMapForDmi2.cmNotificationSubscriptionStatus.toString() == 'PENDING' + assert resultMapForDmi1.cmSubscriptionStatus.toString() == 'PENDING' + assert resultMapForDmi2.cmSubscriptionStatus.toString() == 'PENDING' and: 'the target cmHandles for each predicate is correct' - assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds == ['ch1'].toSet() - assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[1].targetCmHandleIds == ['ch3'].toSet() + assert resultMapForDmi1.dmiCmSubscriptionPredicates[0].targetCmHandleIds == ['ch1'].toSet() + assert resultMapForDmi1.dmiCmSubscriptionPredicates[1].targetCmHandleIds == ['ch3'].toSet() - assert resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds == ['ch2'].toSet() - assert resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[1].targetCmHandleIds == ['ch4'].toSet() + assert resultMapForDmi2.dmiCmSubscriptionPredicates[0].targetCmHandleIds == ['ch2'].toSet() + assert resultMapForDmi2.dmiCmSubscriptionPredicates[1].targetCmHandleIds == ['ch4'].toSet() and: 'the list of xpath for each is correct' - assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[0].xpaths - && resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[0].xpaths == ['/x1/y1','x2/y2'].toSet() + assert resultMapForDmi1.dmiCmSubscriptionPredicates[0].xpaths + && resultMapForDmi2.dmiCmSubscriptionPredicates[0].xpaths == ['/x1/y1', 'x2/y2'].toSet() - assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[1].xpaths - && resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[1].xpaths == ['/x3/y3','x4/y4'].toSet() + assert resultMapForDmi1.dmiCmSubscriptionPredicates[1].xpaths + && resultMapForDmi2.dmiCmSubscriptionPredicates[1].xpaths == ['/x3/y3', 'x4/y4'].toSet() } def 'Get map for cm handle IDs by DMI service name'() { given: 'the predicate from the test request CM subscription event' - def targetFilter = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates().get(0).getTargetFilter() + def targetFilter = ncmpInEvent.getData().getPredicates().get(0).getTargetFilter() when: 'the method to group all target CM handles by DMI service name is called' def mapOfCMHandleIDsByDmi = objectUnderTest.groupTargetCmHandleIdsByDmi(targetFilter) then: 'the size of the resulting map is correct' @@ -153,41 +153,41 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { def 'Update subscription status in cache per DMI service name'() { given: 'populated cache' - def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates() - def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId() + def predicates = ncmpInEvent.getData().getPredicates() + def subscriptionId = ncmpInEvent.getData().getSubscriptionId() objectUnderTest.add(subscriptionId, predicates) when: 'subscription status per dmi is updated in cache' - objectUnderTest.updateDmiCmNotificationSubscriptionStatusPerDmi(subscriptionId,'dmi-1', CmNotificationSubscriptionStatus.ACCEPTED) + objectUnderTest.updateDmiSubscriptionStatusPerDmi(subscriptionId,'dmi-1', CmSubscriptionStatus.ACCEPTED) then: 'verify status has been updated in cache' def predicate = testCache.get(subscriptionId) - assert predicate.get('dmi-1').cmNotificationSubscriptionStatus == CmNotificationSubscriptionStatus.ACCEPTED + assert predicate.get('dmi-1').cmSubscriptionStatus == CmSubscriptionStatus.ACCEPTED } def 'Persist Cache into database per dmi'() { given: 'populated cache' - def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates() - def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId() + def predicates = ncmpInEvent.getData().getPredicates() + def subscriptionId = ncmpInEvent.getData().getSubscriptionId() objectUnderTest.add(subscriptionId, predicates) when: 'subscription is persisted in database' objectUnderTest.persistIntoDatabasePerDmi(subscriptionId,'dmi-1') then: 'persistence service is called the correct number of times per dmi' - 4 * mockCmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(_,_,_,subscriptionId) + 4 * mockCmSubscriptionPersistenceService.addCmSubscription(_,_,_,subscriptionId) } def 'Remove subscription from database per dmi'() { given: 'populated cache' - def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates() - def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId() + def predicates = ncmpInEvent.getData().getPredicates() + def subscriptionId = ncmpInEvent.getData().getSubscriptionId() objectUnderTest.add(subscriptionId, predicates) when: 'subscription is persisted in database' objectUnderTest.removeFromDatabasePerDmi(subscriptionId,'dmi-1') then: 'persistence service is called the correct number of times per dmi' - 4 * mockCmNotificationSubscriptionPersistenceService.removeCmNotificationSubscription(_,_,_,subscriptionId) + 4 * mockCmSubscriptionPersistenceService.removeCmSubscription(_,_,_,subscriptionId) } def setUpTestEvent(){ def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class) + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class) def testCloudEventSent = CloudEventBuilder.v1() .withData(objectMapper.writeValueAsBytes(testEventSent)) .withId('subscriptionCreated') @@ -197,7 +197,7 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec { def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent) def cloudEvent = consumerRecord.value() - cmNotificationSubscriptionNcmpInEvent = toTargetEvent(cloudEvent, CmNotificationSubscriptionNcmpInEvent.class); + ncmpInEvent = toTargetEvent(cloudEvent, NcmpInEvent.class); } def initialiseMockInventoryPersistenceResponses(){ diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy index a90fd9405f..98cc383e7f 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.avc +package org.onap.cps.ncmp.impl.cmnotificationsubscription.cmavc import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent @@ -37,20 +37,21 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers + import java.time.Duration -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent -@SpringBootTest(classes = [EventsPublisher, AvcEventConsumer, ObjectMapper, JsonObjectMapper]) +@SpringBootTest(classes = [EventsPublisher, CmAvcEventConsumer, ObjectMapper, JsonObjectMapper]) @Testcontainers @DirtiesContext -class AvcEventConsumerSpec extends MessagingBaseSpec { +class CmAvcEventConsumerSpec extends MessagingBaseSpec { @SpringBean EventsPublisher eventsPublisher = new EventsPublisher<CloudEvent>(legacyEventKafkaTemplate, cloudEventKafkaTemplate) @SpringBean - AvcEventConsumer acvEventConsumer = new AvcEventConsumer(eventsPublisher) + CmAvcEventConsumer acvEventConsumer = new CmAvcEventConsumer(eventsPublisher) @Autowired JsonObjectMapper jsonObjectMapper @@ -91,4 +92,4 @@ class AvcEventConsumerSpec extends MessagingBaseSpec { assert testEventSent == convertedAvcEvent } -}
\ No newline at end of file +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapperSpec.groovy index 0c9e3b6912..62d1572502 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapperSpec.groovy @@ -18,22 +18,22 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper +package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi -import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import spock.lang.Specification -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING -class CmNotificationSubscriptionDmiInEventMapperSpec extends Specification { +class DmiInEventMapperSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) - def objectUnderTest = new CmNotificationSubscriptionDmiInEventMapper(mockInventoryPersistence) + def objectUnderTest = new DmiInEventMapper(mockInventoryPersistence) def setup() { def yangModelCmHandles = [new YangModelCmHandle(id: 'ch-1', dmiProperties: [new YangModelCmHandle.Property('k1', 'v1')], publicProperties: []), @@ -43,10 +43,10 @@ class CmNotificationSubscriptionDmiInEventMapperSpec extends Specification { def 'Check for Cm Notification Subscription DMI In Event mapping'() { given: 'a collection of cm subscription predicates' - def dmiCmNotificationSubscriptionPredicates = [new DmiCmNotificationSubscriptionPredicate(['ch-1'].toSet(), PASSTHROUGH_RUNNING, ['/ch-1'].toSet()), - new DmiCmNotificationSubscriptionPredicate(['ch-2'].toSet(), PASSTHROUGH_OPERATIONAL, ['/ch-2'].toSet())] + def dmiSubscriptionPredicates = [new DmiCmSubscriptionPredicate(['ch-1'].toSet(), PASSTHROUGH_RUNNING, ['/ch-1'].toSet()), + new DmiCmSubscriptionPredicate(['ch-2'].toSet(), PASSTHROUGH_OPERATIONAL, ['/ch-2'].toSet())] when: 'we try to map the values' - def result = objectUnderTest.toCmNotificationSubscriptionDmiInEvent(dmiCmNotificationSubscriptionPredicates) + def result = objectUnderTest.toDmiInEvent(dmiSubscriptionPredicates) then: 'it contains correct cm notification subscription cmhandle object' assert result.data.cmHandles.cmhandleId.containsAll(['ch-1', 'ch-2']) assert result.data.cmHandles.privateProperties.containsAll([['k1': 'v1'], ['k2': 'v2']]) 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/impl/cmnotificationsubscription/dmi/DmiInEventProducerSpec.groovy index 039a189491..34fa4549f5 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/impl/cmnotificationsubscription/dmi/DmiInEventProducerSpec.groovy @@ -18,47 +18,46 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription +package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi 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.CmHandle -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.Data +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.CmHandle +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.Data +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent +import org.onap.cps.ncmp.utils.events.CloudEventMapper import org.onap.cps.utils.JsonObjectMapper import spock.lang.Specification -class CmNotificationSubscriptionDmiInEventProducerSpec extends Specification { +class DmiInEventProducerSpec extends Specification { def mockEventsPublisher = Mock(EventsPublisher) def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - def objectUnderTest = new CmNotificationSubscriptionDmiInEventProducer(mockEventsPublisher, jsonObjectMapper) + def objectUnderTest = new DmiInEventProducer(mockEventsPublisher, jsonObjectMapper) def 'Create and Publish Cm Notification Subscription DMI In Event'() { given: 'a cm subscription for a dmi plugin' def subscriptionId = 'test-subscription-id' def dmiPluginName = 'test-dmiplugin' def eventType = 'subscriptionCreateRequest' - def cmNotificationSubscriptionDmiInEvent = new CmNotificationSubscriptionDmiInEvent(data: new Data(cmHandles: [new CmHandle(cmhandleId: 'test-1', privateProperties: [:])])) + def dmiInEvent = new DmiInEvent(data: new Data(cmHandles: [new CmHandle(cmhandleId: 'test-1', privateProperties: [:])])) and: 'also we have target topic for dmiPlugin' - objectUnderTest.cmNotificationSubscriptionDmiInEventTopic = 'dmiplugin-test-topic' + objectUnderTest.dmiInEventTopic = 'dmiplugin-test-topic' when: 'the event is published' - objectUnderTest.publishCmNotificationSubscriptionDmiInEvent(subscriptionId, dmiPluginName, eventType, cmNotificationSubscriptionDmiInEvent) + objectUnderTest.publishDmiInEvent(subscriptionId, dmiPluginName, eventType, dmiInEvent) then: 'the event contains the required attributes' 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { args -> { assert args[0] == 'dmiplugin-test-topic' assert args[1] == subscriptionId - def cmNotificationSubscriptionDmiInEventAsCloudEvent = (args[2] as CloudEvent) - assert cmNotificationSubscriptionDmiInEventAsCloudEvent.getExtension('correlationid') == subscriptionId + '#' + dmiPluginName - assert cmNotificationSubscriptionDmiInEventAsCloudEvent.type == 'subscriptionCreateRequest' - assert cmNotificationSubscriptionDmiInEventAsCloudEvent.source.toString() == 'NCMP' - assert CloudEventMapper.toTargetEvent(cmNotificationSubscriptionDmiInEventAsCloudEvent, CmNotificationSubscriptionDmiInEvent) == cmNotificationSubscriptionDmiInEvent + def dmiInEventAsCloudEvent = (args[2] as CloudEvent) + assert dmiInEventAsCloudEvent.getExtension('correlationid') == subscriptionId + '#' + dmiPluginName + assert dmiInEventAsCloudEvent.type == 'subscriptionCreateRequest' + assert dmiInEventAsCloudEvent.source.toString() == 'NCMP' + assert CloudEventMapper.toTargetEvent(dmiInEventAsCloudEvent, DmiInEvent) == dmiInEvent } } } 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/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy index 9b0a48d93e..06003fdcb4 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/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription +package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger @@ -28,19 +28,23 @@ 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 -import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.Data +import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler +import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventMapper +import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.Data +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.ACCEPTED +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.REJECTED + @SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec { +class DmiOutEventConsumerSpec extends MessagingBaseSpec { @Autowired JsonObjectMapper jsonObjectMapper @@ -48,27 +52,27 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe @Autowired ObjectMapper objectMapper - def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler) - def mockCmNotificationSubscriptionEventsHandler = Mock(CmNotificationSubscriptionEventsHandler) - def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler) + def mockDmiCacheHandler = Mock(DmiCacheHandler) + def mockNcmpOutEventProducer = Mock(NcmpOutEventProducer) + def mockNcmpOutEventMapper = Mock(NcmpOutEventMapper) - def objectUnderTest = new CmNotificationSubscriptionDmiOutEventConsumer(mockDmiCmNotificationSubscriptionCacheHandler, mockCmNotificationSubscriptionEventsHandler, mockCmNotificationSubscriptionMappersHandler) + def objectUnderTest = new DmiOutEventConsumer(mockDmiCacheHandler, mockNcmpOutEventProducer, mockNcmpOutEventMapper) def logger = Spy(ListAppender<ILoggingEvent>) void setup() { - ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionDmiOutEventConsumer.class)).addAppender(logger) + ((Logger) LoggerFactory.getLogger(DmiOutEventConsumer.class)).addAppender(logger) logger.start() } void cleanup() { - ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionDmiOutEventConsumer.class)).detachAndStopAllAppenders() + ((Logger) LoggerFactory.getLogger(DmiOutEventConsumer.class)).detachAndStopAllAppenders() } def 'Consume valid CM Subscription response from DMI Plugin'() { given: 'a cmsubscription event' def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionDmiOutEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionDmiOutEvent.class) + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, DmiOutEvent.class) def testCloudEventSent = CloudEventBuilder.v1() .withData(objectMapper.writeValueAsBytes(testEventSent)) .withId('random-uuid') @@ -77,7 +81,7 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe .withExtension('correlationid', 'sub-1#test-dmi-plugin-name').build() def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent) when: 'the valid event is consumed' - objectUnderTest.consumeCmNotificationSubscriptionDmiOutEvent(consumerRecord) + objectUnderTest.consumeDmiOutEvent(consumerRecord) then: 'an event is logged with level INFO' def loggingEvent = getLoggingEvent() assert loggingEvent.level == Level.INFO @@ -88,28 +92,28 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe def 'Consume a valid CM Notification Subscription Event and perform correct actions base on status'() { given: 'a cmNotificationSubscription event' def dmiOutEventData = new Data(statusCode: statusCode, statusMessage: subscriptionStatus.toString()) - def cmNotificationSubscriptionDmiOutEvent = new CmNotificationSubscriptionDmiOutEvent().withData(dmiOutEventData) + def dmiOutEvent = new DmiOutEvent().withData(dmiOutEventData) def testCloudEventSent = CloudEventBuilder.v1() - .withData(objectMapper.writeValueAsBytes(cmNotificationSubscriptionDmiOutEvent)) + .withData(objectMapper.writeValueAsBytes(dmiOutEvent)) .withId('random-uuid') .withType('subscriptionCreateResponse') .withSource(URI.create('test-dmi-plugin-name')) .withExtension('correlationid', 'sub-1#test-dmi-plugin-name').build() def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent) when: 'the event is consumed' - objectUnderTest.consumeCmNotificationSubscriptionDmiOutEvent(consumerRecord) + objectUnderTest.consumeDmiOutEvent(consumerRecord) then: 'correct number of calls to cache' - expectedCacheCalls * mockDmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi('sub-1','test-dmi-plugin-name', subscriptionStatus) + expectedCacheCalls * mockDmiCacheHandler.updateDmiSubscriptionStatusPerDmi('sub-1','test-dmi-plugin-name', subscriptionStatus) and: 'correct number of calls to persist cache' - expectedPersistenceCalls * mockDmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi('sub-1','test-dmi-plugin-name') + expectedPersistenceCalls * mockDmiCacheHandler.persistIntoDatabasePerDmi('sub-1','test-dmi-plugin-name') and: 'correct number of calls to map the ncmp out event' - 1 * mockCmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent('sub-1', _) + 1 * mockNcmpOutEventMapper.toNcmpOutEvent('sub-1', _) and: 'correct number of calls to publish the ncmp out event to client' - 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent('sub-1', 'subscriptionCreateResponse', _, false) + 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('sub-1', 'subscriptionCreateResponse', _, false) where: 'the following parameters are used' - scenario | subscriptionStatus | statusCode || expectedCacheCalls | expectedPersistenceCalls - 'Accepted Status' | CmNotificationSubscriptionStatus.ACCEPTED | '1' || 1 | 1 - 'Rejected Status' | CmNotificationSubscriptionStatus.REJECTED | '104' || 1 | 0 + scenario | subscriptionStatus | statusCode || expectedCacheCalls | expectedPersistenceCalls + 'Accepted Status' | ACCEPTED | '1' || 1 | 1 + 'Rejected Status' | REJECTED | '104' || 1 | 0 } def getLoggingEvent() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy new file mode 100644 index 0000000000..0ebf9a6aed --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy @@ -0,0 +1,62 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp + + +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL + +class CmSubscriptionComparatorSpec extends Specification { + + def mockCmSubscriptionPersistenceService = Mock(CmSubscriptionPersistenceService) + def objectUnderTest = new CmSubscriptionComparator(mockCmSubscriptionPersistenceService) + + def 'Find Delta of given list of predicates'() { + given: 'A list of predicates' + def predicates = [new DmiCmSubscriptionPredicate(['ch-1', 'ch-2'].toSet(), PASSTHROUGH_OPERATIONAL, ['a/1/', 'b/2'].toSet())] + and: '3 positive responses and 1 negative.' + mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true + mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-1', 'b/2') >>> true + mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-2', 'a/1/') >>> true + mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-2', 'b/2') >>> false + when: 'getDelta is called' + def result = objectUnderTest.getNewDmiSubscriptionPredicates(predicates) + then: 'verify correct delta is returned' + assert result.size() == 1 + assert result[0].targetCmHandleIds[0] == 'ch-2' + assert result[0].xpaths[0] == 'b/2' + + } + + def 'Find Delta of given list of predicates when it is an ongoing Cm Subscription'() { + given: 'A list of predicates' + def predicates = [new DmiCmSubscriptionPredicate(['ch-1'].toSet(), PASSTHROUGH_OPERATIONAL, ['a/1/'].toSet())] + and: 'its already present' + mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true + when: 'getDelta is called' + def result = objectUnderTest.getNewDmiSubscriptionPredicates(predicates) + then: 'verify correct delta is returned' + assert result.size() == 0 + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy new file mode 100644 index 0000000000..3f6556d47e --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy @@ -0,0 +1,146 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler +import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventMapper +import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventProducer +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.ACCEPTED +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING + +class CmSubscriptionHandlerImplSpec extends Specification { + + def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + def mockCmSubscriptionPersistenceService = Mock(CmSubscriptionPersistenceService) + def mockCmSubscriptionComparator = Mock(CmSubscriptionComparator) + def mockNcmpOutEventMapper = Mock(NcmpOutEventMapper) + def mockDmiInEventMapper = Mock(DmiInEventMapper) + def mockNcmpOutEventProducer = Mock(NcmpOutEventProducer) + def mockDmiInEventProducer = Mock(DmiInEventProducer) + def mockDmiCacheHandler = Mock(DmiCacheHandler) + + def objectUnderTest = new CmSubscriptionHandlerImpl(mockCmSubscriptionPersistenceService, + mockCmSubscriptionComparator, mockNcmpOutEventMapper, mockDmiInEventMapper, + mockNcmpOutEventProducer, mockDmiInEventProducer, mockDmiCacheHandler) + + def testDmiSubscriptionsPerDmi = ["dmi-1": new DmiCmSubscriptionDetails([], PENDING)] + + def 'Consume valid and unique CmNotificationSubscriptionNcmpInEvent create message'() { + given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id' + def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') + def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class) + def testListOfDeltaPredicates = [new DmiCmSubscriptionPredicate(['ch1'].toSet(), PASSTHROUGH_OPERATIONAL, ['/a/b'].toSet())] + mockCmSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true + and: 'relevant details is extracted from the event' + def subscriptionId = testEventConsumed.getData().getSubscriptionId() + def predicates = testEventConsumed.getData().getPredicates() + and: 'the cache handler returns for relevant subscription id' + 1 * mockDmiCacheHandler.get("test-id") >> testDmiSubscriptionsPerDmi + and: 'the delta predicates is returned' + 1 * mockCmSubscriptionComparator.getNewDmiSubscriptionPredicates(_) >> testListOfDeltaPredicates + and: 'the DMI in event mapper returns cm notification subscription event' + def testDmiInEvent = new DmiInEvent() + 1 * mockDmiInEventMapper.toDmiInEvent(testListOfDeltaPredicates) >> testDmiInEvent + when: 'the valid and unique event is consumed' + objectUnderTest.processSubscriptionCreateRequest(subscriptionId, predicates) + then: 'the subscription cache handler is called once' + 1 * mockDmiCacheHandler.add('test-id', _) + and: 'the events handler method to publish DMI event is called correct number of times with the correct parameters' + testDmiSubscriptionsPerDmi.size() * mockDmiInEventProducer.publishDmiInEvent( + "test-id", "dmi-1", "subscriptionCreateRequest", testDmiInEvent) + and: 'we schedule to send the response after configured time from the cache' + 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('test-id', 'subscriptionCreateResponse', null, true) + } + + def 'Consume valid and Overlapping Cm Notification Subscription NcmpIn Event'() { + given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id' + def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') + def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class) + def noDeltaPredicates = [] + mockCmSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true + and: 'the cache handler returns for relevant subscription id' + 1 * mockDmiCacheHandler.get('test-id') >> testDmiSubscriptionsPerDmi + and: 'the delta predicates is returned' + 1 * mockCmSubscriptionComparator.getNewDmiSubscriptionPredicates(_) >> noDeltaPredicates + when: 'the valid and unique event is consumed' + objectUnderTest.processSubscriptionCreateRequest('test-id', noDeltaPredicates) + then: 'the subscription cache handler is called once' + 1 * mockDmiCacheHandler.add('test-id', _) + and: 'the subscription details are updated in the cache' + 1 * mockDmiCacheHandler.updateDmiSubscriptionStatusPerDmi('test-id', _, ACCEPTED) + and: 'we schedule to send the response after configured time from the cache' + 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('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, NcmpInEvent.class) + mockCmSubscriptionPersistenceService.isUniqueSubscriptionId('test-id') >> false + and: 'relevant details is extracted from the event' + def subscriptionId = testEventConsumed.getData().getSubscriptionId() + def predicates = testEventConsumed.getData().getPredicates() + and: 'the NCMP out in event mapper returns an event for rejected request' + def testNcmpOutEvent = new NcmpOutEvent() + 1 * mockNcmpOutEventMapper.toNcmpOutEventForRejectedRequest( + "test-id", _) >> testNcmpOutEvent + when: 'the valid but non-unique event is consumed' + objectUnderTest.processSubscriptionCreateRequest(subscriptionId, predicates) + then: 'the events handler method to publish DMI event is never called' + 0 * mockDmiInEventProducer.publishDmiInEvent(_, _, _, _) + and: 'the events handler method to publish NCMP out event is called once' + 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('test-id', 'subscriptionCreateResponse', testNcmpOutEvent, false) + } + + def 'Consume valid CmNotificationSubscriptionNcmpInEvent delete message'() { + given: 'a cmNotificationSubscriptionNcmp in event for delete' + def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') + def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class) + and: 'relevant details is extracted from the event' + def subscriptionId = testEventConsumed.getData().getSubscriptionId() + def predicates = testEventConsumed.getData().getPredicates() + and: 'the cache handler returns for relevant subscription id' + 1 * mockDmiCacheHandler.get('test-id') >> testDmiSubscriptionsPerDmi + when: 'the valid and unique event is consumed' + objectUnderTest.processSubscriptionDeleteRequest(subscriptionId, predicates) + then: 'the subscription cache handler is called once' + 1 * mockDmiCacheHandler.add('test-id', predicates) + and: 'the mapper handler to get DMI in event is called once' + 1 * mockDmiInEventMapper.toDmiInEvent(_) + and: 'the events handler method to publish DMI event is called correct number of times with the correct parameters' + testDmiSubscriptionsPerDmi.size() * mockDmiInEventProducer.publishDmiInEvent( + 'test-id', 'dmi-1', 'subscriptionDeleteRequest', _) + and: 'we schedule to send the response after configured time from the cache' + 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('test-id', 'subscriptionDeleteResponse', null, true) + } +} 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/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy index 01a92c02fa..637e9ebfec 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/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription +package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger @@ -28,10 +28,8 @@ 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 +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper import org.slf4j.LoggerFactory @@ -39,10 +37,10 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpec { +class NcmpInEventConsumerSpec extends MessagingBaseSpec { - def mockCmNotificationSubscriptionHandlerService = Mock(CmNotificationSubscriptionHandlerService) - def objectUnderTest = new CmNotificationSubscriptionNcmpInEventConsumer(mockCmNotificationSubscriptionHandlerService) + def mockCmSubscriptionHandler = Mock(CmSubscriptionHandler) + def objectUnderTest = new NcmpInEventConsumer(mockCmSubscriptionHandler) def logger = Spy(ListAppender<ILoggingEvent>) @Autowired @@ -52,19 +50,19 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe ObjectMapper objectMapper void setup() { - ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionNcmpInEventConsumer.class)).addAppender(logger) + ((Logger) LoggerFactory.getLogger(NcmpInEventConsumer.class)).addAppender(logger) logger.start() } void cleanup() { - ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionNcmpInEventConsumer.class)).detachAndStopAllAppenders() + ((Logger) LoggerFactory.getLogger(NcmpInEventConsumer.class)).detachAndStopAllAppenders() } def 'Consume valid CmNotificationSubscriptionNcmpInEvent create message'() { given: 'a cmNotificationSubscription event' def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class) + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class) def testCloudEventSent = CloudEventBuilder.v1() .withData(objectMapper.writeValueAsBytes(testEventSent)) .withId('subscriptionCreated') @@ -80,13 +78,13 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe and: 'the log indicates the task completed successfully' assert loggingEvent.formattedMessage == 'Subscription create request for source some-resource with subscription id test-id ...' and: 'the subscription handler service is called once' - 1 * mockCmNotificationSubscriptionHandlerService.processSubscriptionCreateRequest('test-id',_) + 1 * mockCmSubscriptionHandler.processSubscriptionCreateRequest('test-id',_) } def 'Consume valid CmNotificationSubscriptionNcmpInEvent delete message'() { given: 'a cmNotificationSubscription event' def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json') - def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class) + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class) def testCloudEventSent = CloudEventBuilder.v1() .withData(objectMapper.writeValueAsBytes(testEventSent)) .withId('sub-id') @@ -102,7 +100,7 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe and: 'the log indicates the task completed successfully' assert loggingEvent.formattedMessage == 'Subscription delete request for source some-resource with subscription id test-id ...' and: 'the subscription handler service is called once' - 1 * mockCmNotificationSubscriptionHandlerService.processSubscriptionDeleteRequest('test-id',_) + 1 * mockCmSubscriptionHandler.processSubscriptionDeleteRequest('test-id',_) } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy new file mode 100644 index 0000000000..2251a33466 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy @@ -0,0 +1,69 @@ +/* + * ============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.impl.cmnotificationsubscription.ncmp + + +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails +import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.ACCEPTED +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING +import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.REJECTED + +class NcmpOutEventMapperSpec extends Specification { + + static Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi + + def objectUnderTest = new NcmpOutEventMapper() + + def setup() { + def dmiSubscriptionPredicateA = new DmiCmSubscriptionPredicate(['ch-A'] as Set, PASSTHROUGH_RUNNING, ['/a'] as Set) + def dmiSubscriptionPredicateB = new DmiCmSubscriptionPredicate(['ch-B'] as Set, PASSTHROUGH_OPERATIONAL, ['/b'] as Set) + def dmiSubscriptionPredicateC = new DmiCmSubscriptionPredicate(['ch-C'] as Set, PASSTHROUGH_OPERATIONAL, ['/c'] as Set) + dmiSubscriptionsPerDmi = ['dmi-1': new DmiCmSubscriptionDetails([dmiSubscriptionPredicateA], PENDING), + 'dmi-2': new DmiCmSubscriptionDetails([dmiSubscriptionPredicateB], ACCEPTED), + 'dmi-3': new DmiCmSubscriptionDetails([dmiSubscriptionPredicateC], REJECTED) + ] + } + + def 'Check for Cm Notification Subscription Outgoing event mapping'() { + when: 'we try to map the event to send it to client' + def result = objectUnderTest.toNcmpOutEvent('test-subscription', dmiSubscriptionsPerDmi) + then: 'event is mapped correctly for the subscription' + result.data.subscriptionId == 'test-subscription' + and: 'the cm handle ids are part of correct list' + result.data.pendingTargets == ['ch-A'] + result.data.acceptedTargets == ['ch-B'] + result.data.rejectedTargets == ['ch-C'] + } + + def 'Check for Cm Notification Rejected Subscription Outgoing event mapping'() { + when: 'we try to map the event to send it to client' + def result = objectUnderTest.toNcmpOutEventForRejectedRequest('test-subscription', ['ch-1', 'ch-2']) + then: 'event is mapped correctly for the subscription id' + result.data.subscriptionId == 'test-subscription' + and: 'the cm handle ids are part of correct list' + result.data.withRejectedTargets(['ch-1', 'ch-2']) + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy new file mode 100644 index 0000000000..e03682d8c9 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy @@ -0,0 +1,87 @@ +package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.Data +import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent +import org.onap.cps.ncmp.utils.events.CloudEventMapper +import org.onap.cps.utils.JsonObjectMapper +import spock.lang.Specification + +class NcmpOutEventProducerSpec extends Specification { + + def mockEventsPublisher = Mock(EventsPublisher) + def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + def mockNcmpOutEventMapper = Mock(NcmpOutEventMapper) + def mockDmiCacheHandler = Mock(DmiCacheHandler) + + def objectUnderTest = new NcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper, mockNcmpOutEventMapper, mockDmiCacheHandler) + + def 'Create and #scenario Cm Notification Subscription NCMP out event'() { + given: 'a cm subscription response for the client' + def subscriptionId = 'test-subscription-id-2' + def eventType = 'subscriptionCreateResponse' + def ncmpOutEvent = new NcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-2', acceptedTargets: ['ch-1', 'ch-2'])) + and: 'also we have target topic for publishing to client' + objectUnderTest.ncmpOutEventTopic = 'client-test-topic' + and: 'a deadline to an event' + objectUnderTest.dmiOutEventTimeoutInMs = 1000 + when: 'the event is published' + objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, eventPublishingTaskToBeScheduled) + then: 'we conditionally wait for a while' + Thread.sleep(delayInMs) + then: 'the event contains the required attributes' + 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { + args -> + { + assert args[0] == 'client-test-topic' + assert args[1] == subscriptionId + def ncmpOutEventAsCloudEvent = (args[2] as CloudEvent) + assert ncmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId + assert ncmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse' + assert ncmpOutEventAsCloudEvent.source.toString() == 'NCMP' + assert CloudEventMapper.toTargetEvent(ncmpOutEventAsCloudEvent, NcmpOutEvent) == ncmpOutEvent + } + } + where: 'following scenarios are considered' + scenario | delayInMs | eventPublishingTaskToBeScheduled + 'publish event now' | 0 | false + 'schedule and publish after the configured time ' | 1500 | true + } + + def 'Schedule Cm Notification Subscription NCMP out event but later publish it on demand'() { + given: 'a cm subscription response for the client' + def subscriptionId = 'test-subscription-id-3' + def eventType = 'subscriptionCreateResponse' + def ncmpOutEvent = new NcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-3', acceptedTargets: ['ch-2', 'ch-3'])) + and: 'also we have target topic for publishing to client' + objectUnderTest.ncmpOutEventTopic = 'client-test-topic' + and: 'a deadline to an event' + objectUnderTest.dmiOutEventTimeoutInMs = 1000 + when: 'the event is scheduled to be published' + objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, true) + then: 'we wait for 10ms and then we receive response from DMI' + Thread.sleep(10) + and: 'we receive response from DMI so we publish the message on demand' + objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, false) + then: 'the event contains the required attributes' + 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { + args -> + { + assert args[0] == 'client-test-topic' + assert args[1] == subscriptionId + def ncmpOutEventAsCloudEvent = (args[2] as CloudEvent) + assert ncmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId + assert ncmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse' + assert ncmpOutEventAsCloudEvent.source.toString() == 'NCMP' + assert CloudEventMapper.toTargetEvent(ncmpOutEventAsCloudEvent, NcmpOutEvent) == ncmpOutEvent + } + } + then: 'the cache handler is called once to remove accepted and rejected entries in cache' + 1 * mockDmiCacheHandler.removeAcceptedAndRejectedDmiSubscriptionEntries(subscriptionId) + } + + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceServiceSpec.groovy index 281ec4f7e4..d32d143ade 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceServiceSpec.groovy @@ -19,38 +19,40 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.cmsubscription.service +package org.onap.cps.ncmp.impl.cmnotificationsubscription.utils -import org.onap.cps.utils.ContentType - -import static org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceServiceImpl.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID; -import static org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceServiceImpl.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE; -import static org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceServiceImpl.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH; +import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsQueryService -import org.onap.cps.ncmp.api.impl.operations.DatastoreType -import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.DataNode +import org.onap.cps.utils.ContentType import org.onap.cps.utils.JsonObjectMapper -import com.fasterxml.jackson.databind.ObjectMapper import spock.lang.Specification -class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification { +import static CmSubscriptionPersistenceService.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE +import static CmSubscriptionPersistenceService.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH +import static CmSubscriptionPersistenceService.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING +import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY +import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS + +class CmSubscriptionPersistenceServiceSpec extends Specification { def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) def mockCpsQueryService = Mock(CpsQueryService) def mockCpsDataService = Mock(CpsDataService) - def objectUnderTest = new CmNotificationSubscriptionPersistenceServiceImpl(jsonObjectMapper, mockCpsQueryService, mockCpsDataService) + def objectUnderTest = new CmSubscriptionPersistenceService(jsonObjectMapper, mockCpsQueryService, mockCpsDataService) def 'Check ongoing cm subscription #scenario'() { given: 'a valid cm subscription query' - def cpsPathQuery = "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-1']/filters/filter[@xpath='/cps/path']"; + def cpsPathQuery = "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-1']/filters/filter[@xpath='/cps/path']" and: 'datanodes optionally returned' 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', - cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> dataNode + cpsPathQuery, OMIT_DESCENDANTS) >> dataNode when: 'we check for an ongoing cm subscription' - def response = objectUnderTest.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1', '/cps/path') + def response = objectUnderTest.isOngoingCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/cps/path') then: 'we get expected response' assert response == isOngoingCmSubscription where: 'following scenarios are used' @@ -63,7 +65,7 @@ class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification given: 'a cps path with a subscription ID for querying' def cpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID.formatted('some-sub') and: 'relevant datanodes are returned' - 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> + 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', cpsPathQuery, OMIT_DESCENDANTS) >> dataNodes when: 'a subscription ID is tested for uniqueness' def result = objectUnderTest.isUniqueSubscriptionId('some-sub') @@ -77,18 +79,18 @@ class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification def 'Add new subscriber to an ongoing cm notification subscription'() { given: 'a valid cm subscription path query' - def cpsPathQuery =CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y') + def cpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y') and: 'a dataNode exists for the given cps path query' mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', - cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y','subscriptionIds': ['sub-1']])] + cpsPathQuery, OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y', 'subscriptionIds': ['sub-1']])] when: 'the method to add/update cm notification subscription is called' - objectUnderTest.addCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1','/x/y', 'newSubId') + objectUnderTest.addCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'newSubId') then: 'data service method to update list of subscribers is called once' 1 * mockCpsDataService.updateNodeLeaves( 'NCMP-Admin', 'cm-data-subscriptions', '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters', - objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['sub-1','newSubId']), _,ContentType.JSON) + objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['sub-1', 'newSubId']), _, ContentType.JSON) } def 'Add new cm notification subscription for #datastoreType'() { @@ -100,25 +102,25 @@ class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification and: 'a datanode does not exist for cm subscription path query' mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', cmSubscriptionCpsPathQuery, - FetchDescendantsOption.OMIT_DESCENDANTS) >> [] + OMIT_DESCENDANTS) >> [] and: 'a datanode does not exist for the given cm handle subscription path query' mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', - cmHandleForSubscriptionPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [] + cmHandleForSubscriptionPathQuery, OMIT_DESCENDANTS) >> [] and: 'subscription is mapped as JSON' def subscriptionAsJson = '{"cm-handle":[{"id":"ch-1","filters":' + objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['newSubId']) + '}]}' when: 'the method to add/update cm notification subscription is called' - objectUnderTest.addCmNotificationSubscription(datastoreType, 'ch-1','/x/y', 'newSubId') + objectUnderTest.addCmSubscription(datastoreType, 'ch-1', '/x/y', 'newSubId') then: 'data service method to create new subscription for given subscriber is called once with the correct parameters' 1 * mockCpsDataService.saveData( 'NCMP-Admin', 'cm-data-subscriptions', parentNodeXpath.formatted(datastoreName), - subscriptionAsJson,_, ContentType.JSON) + subscriptionAsJson, _, ContentType.JSON) where: - scenario | datastoreType || datastoreName - 'passthrough_running' | DatastoreType.PASSTHROUGH_RUNNING || "ncmp-datastore:passthrough-running" - 'passthrough_operational' | DatastoreType.PASSTHROUGH_OPERATIONAL || "ncmp-datastore:passthrough-operational" + scenario | datastoreType || datastoreName + 'passthrough_running' | PASSTHROUGH_RUNNING || 'ncmp-datastore:passthrough-running' + 'passthrough_operational' | PASSTHROUGH_OPERATIONAL || 'ncmp-datastore:passthrough-operational' } def 'Add new cm notification subscription when xpath does not exist for existing subscription cm handle'() { @@ -129,52 +131,49 @@ class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification def parentNodeXpath = '/datastores/datastore[@name=\'%s\']/cm-handles/cm-handle[@id=\'%s\']/filters' and: 'a datanode does not exist for cm subscription path query' mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', - cmSubscriptionCpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [] + cmSubscriptionCpsPathQuery, OMIT_DESCENDANTS) >> [] and: 'a datanode exists for the given cm handle subscription path query' mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', - cmHandleForSubscriptionPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode()] + cmHandleForSubscriptionPathQuery, OMIT_DESCENDANTS) >> [new DataNode()] when: 'the method to add/update cm notification subscription is called' - objectUnderTest.addCmNotificationSubscription(datastoreType, 'ch-1','/x/y', 'newSubId') + objectUnderTest.addCmSubscription(datastoreType, 'ch-1', '/x/y', 'newSubId') then: 'data service method to create new subscription for given subscriber is called once with the correct parameters' 1 * mockCpsDataService.saveListElements( 'NCMP-Admin', 'cm-data-subscriptions', parentNodeXpath.formatted(datastoreName, 'ch-1'), - objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['newSubId']),_) + objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['newSubId']), _) where: - scenario | datastoreType || datastoreName - 'passthrough_running' | DatastoreType.PASSTHROUGH_RUNNING || "ncmp-datastore:passthrough-running" - 'passthrough_operational' | DatastoreType.PASSTHROUGH_OPERATIONAL || "ncmp-datastore:passthrough-operational" + scenario | datastoreType || datastoreName + 'passthrough_running' | PASSTHROUGH_RUNNING || 'ncmp-datastore:passthrough-running' + 'passthrough_operational' | PASSTHROUGH_OPERATIONAL || 'ncmp-datastore:passthrough-operational' } def 'Remove subscriber from a list of an ongoing cm notification subscription'() { given: 'a subscription exists when queried' def cpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y') mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', - cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y','subscriptionIds': ['sub-1', 'sub-2']])] + cpsPathQuery, OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y', 'subscriptionIds': ['sub-1', 'sub-2']])] when: 'the subscriber is removed' - objectUnderTest.removeCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1') + objectUnderTest.removeCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1') then: 'the list of subscribers is updated' 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'cm-data-subscriptions', '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters', objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['sub-2']), _, ContentType.JSON) } - def 'Removing last ongoing subscription for datastore and cmhandle and xpath'(){ + def 'Removing last ongoing subscription for datastore and cmhandle and xpath'() { given: 'a subscription exists when queried but has only 1 subscriber' mockCpsQueryService.queryDataNodes( - 'NCMP-Admin', - 'cm-data-subscriptions', + 'NCMP-Admin', 'cm-data-subscriptions', CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y'), - FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(leaves: ['xpath': '/x/y','subscriptionIds': ['sub-1']])] + OMIT_DESCENDANTS) >> [new DataNode(leaves: ['xpath': '/x/y', 'subscriptionIds': ['sub-1']])] and: 'the #scenario' - mockCpsQueryService.queryDataNodes( - 'NCMP-Admin', - 'cm-data-subscriptions', + mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted('ncmp-datastore:passthrough-running', 'ch-1'), - FetchDescendantsOption.DIRECT_CHILDREN_ONLY) >> [new DataNode(childDataNodes: listOfChildNodes)] + DIRECT_CHILDREN_ONLY) >> [new DataNode(childDataNodes: listOfChildNodes)] when: 'that last ongoing subscription is removed' - objectUnderTest.removeCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1') + objectUnderTest.removeCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1') then: 'the subscription with empty subscriber list is removed' 1 * mockCpsDataService.deleteDataNode('NCMP-Admin', 'cm-data-subscriptions', '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters/filter[@xpath=\'/x/y\']', @@ -184,9 +183,9 @@ class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']', _) where: - scenario | listOfChildNodes || numberOfCallsToDeleteCmHandle - 'cm handle in same datastore is used for other subscriptions' | [new DataNode()] || 0 - 'cm handle in same datastore is NOT used for other subscriptions' | [] || 1 + scenario | listOfChildNodes || numberOfCallsToDeleteCmHandle + 'cm handle in same datastore is used for other subscriptions' | [new DataNode()] || 0 + 'cm handle in same datastore is NOT used for other subscriptions' | [] || 1 } -}
\ No newline at end of file +} 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/impl/data/DmiDataOperationsSpec.groovy index 1e877f4a88..3a199ff417 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/impl/data/DmiDataOperationsSpec.groovy @@ -19,16 +19,18 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations +package org.onap.cps.ncmp.impl.data import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.api.data.models.CmResourceAddress +import org.onap.cps.ncmp.api.data.models.DataOperationRequest import org.onap.cps.ncmp.api.impl.config.DmiProperties import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext -import org.onap.cps.ncmp.api.models.CmResourceAddress -import org.onap.cps.ncmp.api.models.DataOperationRequest +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent +import org.onap.cps.ncmp.impl.DmiOperationsBaseSpec import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper @@ -42,19 +44,18 @@ import reactor.core.publisher.Mono import spock.lang.Shared import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING -import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE -import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ -import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE +import static org.onap.cps.ncmp.api.data.models.OperationType.READ +import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @SpringBootTest @ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, DmiProperties, DmiDataOperations]) class DmiDataOperationsSpec extends DmiOperationsBaseSpec { - def dmiServiceBaseUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:" def NO_TOPIC = null def NO_REQUEST_ID = null def NO_AUTH_HEADER = null @@ -71,28 +72,28 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { @SpringBean EventsPublisher eventsPublisher = Stub() - def 'call get resource data for #expectedDatastoreInUrl from DMI without topic #scenario.'() { + def 'call get resource data for #expectedDataStore from DMI without topic #scenario.'() { given: 'a cm handle for #cmHandleId' mockYangModelCmHandleRetrieval(dmiProperties) and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = Mono.just(new ResponseEntity<Object>('{some-key:some-value}', HttpStatus.OK)) - def expectedUrl = "${dmiServiceBaseUrl}${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}" + def expectedUrlTemplateWithVariables = getExpectedUrlTemplateWithVariables(expectedOptions, expectedDataStore) def expectedJson = '{"operation":"read","cmHandleProperties":' + expectedProperties + ',"moduleSetTag":""}' - mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrl, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi + mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get resource data is invoked' - def cmResourceAddress = new CmResourceAddress(dataStore.datastoreName, cmHandleId, resourceIdentifier) - def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, options, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER).block() + def cmResourceAddress = new CmResourceAddress(expectedDataStore.datastoreName, cmHandleId, resourceIdentifier) + def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, expectedOptions, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER).block() then: 'the result is the response from the DMI service' assert result.body == '{some-key:some-value}' assert result.statusCode.'2xxSuccessful' where: 'the following parameters are used' - scenario | dmiProperties | dataStore | options || expectedProperties | expectedDatastoreInUrl | expectedOptionsInUrl - 'without properties' | [] | PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM || '{}' | 'passthrough-operational' | '&options=(a%3D1,b%3D2)' - 'with properties' | [yangModelCmHandleProperty] | PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM || '{"prop1":"val1"}' | 'passthrough-operational' | '&options=(a%3D1,b%3D2)' - 'null options' | [yangModelCmHandleProperty] | PASSTHROUGH_OPERATIONAL | null || '{"prop1":"val1"}' | 'passthrough-operational' | '' - 'empty options' | [yangModelCmHandleProperty] | PASSTHROUGH_OPERATIONAL | '' || '{"prop1":"val1"}' | 'passthrough-operational' | '' - 'datastore running without properties' | [] | PASSTHROUGH_RUNNING | OPTIONS_PARAM || '{}' | 'passthrough-running' | '&options=(a%3D1,b%3D2)' - 'datastore running with properties' | [yangModelCmHandleProperty] | PASSTHROUGH_RUNNING | OPTIONS_PARAM || '{"prop1":"val1"}' | 'passthrough-running' | '&options=(a%3D1,b%3D2)' + scenario | dmiProperties || expectedDataStore | expectedOptions | expectedProperties + 'without properties' | [] || PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM | '{}' + 'with properties' | [yangModelCmHandleProperty] || PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM | '{"prop1":"val1"}' + 'null options' | [yangModelCmHandleProperty] || PASSTHROUGH_OPERATIONAL | null | '{"prop1":"val1"}' + 'empty options' | [yangModelCmHandleProperty] || PASSTHROUGH_OPERATIONAL | '' | '{"prop1":"val1"}' + 'datastore running without properties' | [] || PASSTHROUGH_RUNNING | OPTIONS_PARAM | '{}' + 'datastore running with properties' | [yangModelCmHandleProperty] || PASSTHROUGH_RUNNING | OPTIONS_PARAM | '{"prop1":"val1"}' } def 'Execute (async) data operation from DMI service.'() { @@ -103,13 +104,13 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { dataOperationRequest.dataOperationDefinitions[0].cmHandleIds = [cmHandleId] and: 'a positive response from DMI service when it is called with valid request parameters' def responseFromDmi = Mono.just(new ResponseEntity<Object>(HttpStatus.ACCEPTED)) - def expectedDmiBatchResourceDataUrl = "someServiceName/dmi/v1/data?requestId=requestId&topic=my-topic-name" + def expectedUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/data?requestId={requestId}&topic={topic}', ['requestId': 'requestId', 'topic': 'my-topic-name']) def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","moduleSetTag":"","cmHandleProperties":{"prop1":"val1"}}]}]}' - mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedDmiBatchResourceDataUrl, _, READ, NO_AUTH_HEADER) >> responseFromDmi + mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, _, READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get resource data for group of cm handles is invoked' objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'the post operation was called with the expected URL and JSON request body' - 1 * mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER) + 1 * mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER) } def 'Execute (async) data operation from DMI service with Exception.'() { @@ -139,9 +140,9 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { mockYangModelCmHandleRetrieval([yangModelCmHandleProperty], 'my-module-set-tag') and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK) - def expectedUrl = dmiServiceBaseUrl + "passthrough-operational?resourceIdentifier=/" + def expectedTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}', ['resourceIdentifier': '/', 'datastore': 'ncmp-datastore:passthrough-operational', 'cmHandleId': cmHandleId]) def expectedJson = '{"operation":"read","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":"my-module-set-tag"}' - mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedUrl, expectedJson, READ, null) >> responseFromDmi + mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedTemplateWithVariables, expectedJson, READ, null) >> responseFromDmi when: 'get resource data is invoked' def result = objectUnderTest.getAllResourceDataFromDmi(cmHandleId, NO_REQUEST_ID) then: 'the result is the response from the DMI service' @@ -152,10 +153,10 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { given: 'a cm handle for #cmHandleId' mockYangModelCmHandleRetrieval([yangModelCmHandleProperty]) and: 'a positive response from DMI service when it is called with the expected parameters' - def expectedUrl = "${dmiServiceBaseUrl}passthrough-running?resourceIdentifier=${resourceIdentifier}" + def expectedUrlTemplateParameters = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}', ['resourceIdentifier': resourceIdentifier, 'datastore': 'ncmp-datastore:passthrough-running', 'cmHandleId': cmHandleId]) def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":""}' def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK) - mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedUrl, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi + mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedUrlTemplateParameters, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi when: 'write resource method is invoked' def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER) then: 'the result is the response from the DMI service' @@ -167,7 +168,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { } def 'State Ready validation'() { - given: ' a yang model cm handle' + given: 'a yang model cm handle' populateYangModelCmHandle([] ,'') when: 'Validating State of #cmHandleState' def caughtException = null @@ -176,13 +177,13 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { } catch (Exception e) { caughtException = e } - then: 'only when not ready a exception is thrown' + then: 'only when not ready a exception is thrown' if (expecteException) { assert caughtException.details.contains('not in READY state') } else { assert caughtException == null } - where: ' the following states are used' + where: 'the following states are used' cmHandleState || expecteException CmHandleState.READY || false CmHandleState.ADVISED || true @@ -191,4 +192,11 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def extractDataValue(actualDataOperationCloudEvent) { return toTargetEvent(actualDataOperationCloudEvent, DataOperationEvent).data.responses[0] } + + def getExpectedUrlTemplateWithVariables(expectedOptions, expectedDataStore) { + def includeOptions = !(expectedOptions == null || expectedOptions.trim().isEmpty()) + def expectedUrlTemplate = 'myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}' + (includeOptions ? '&options={options}' : '') + def urlVariables = ['resourceIdentifier': resourceIdentifier, 'datastore': expectedDataStore.datastoreName, 'cmHandleId': cmHandleId] + (includeOptions ? ['options': expectedOptions] : [:]) + return new UrlTemplateParameters(expectedUrlTemplate, urlVariables) + } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NcmpCachedResourceRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy index 781b6204a9..9c696dcc7a 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NcmpCachedResourceRequestHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy @@ -18,11 +18,10 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl +package org.onap.cps.ncmp.impl.data import org.onap.cps.api.CpsDataService -import org.onap.cps.ncmp.api.NetworkCmProxyQueryService -import org.onap.cps.ncmp.api.models.CmResourceAddress +import org.onap.cps.ncmp.api.data.models.CmResourceAddress import org.onap.cps.spi.model.DataNode import reactor.core.publisher.Mono import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy index 9a845c0ba9..39701d8e70 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NcmpDatastoreRequestHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy @@ -18,15 +18,14 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl +package org.onap.cps.ncmp.impl.data -import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException -import org.onap.cps.ncmp.api.impl.exception.InvalidOperationException -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations -import org.onap.cps.ncmp.api.models.CmResourceAddress -import org.onap.cps.ncmp.api.models.DataOperationDefinition -import org.onap.cps.ncmp.api.models.DataOperationRequest -import org.onap.cps.ncmp.exceptions.OperationNotSupportedException +import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException +import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException +import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException +import org.onap.cps.ncmp.api.data.models.CmResourceAddress +import org.onap.cps.ncmp.api.data.models.DataOperationDefinition +import org.onap.cps.ncmp.api.data.models.DataOperationRequest import org.onap.cps.ncmp.exceptions.PayloadTooLargeException import org.springframework.http.ResponseEntity import reactor.core.publisher.Mono diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy index f79e0ee2ef..f4e449904b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyFacadeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy @@ -21,20 +21,20 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl +package org.onap.cps.ncmp.impl.data -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations -import org.onap.cps.ncmp.api.models.CmResourceAddress -import org.onap.cps.ncmp.api.models.DataOperationRequest + +import org.onap.cps.ncmp.api.data.models.CmResourceAddress +import org.onap.cps.ncmp.api.data.models.DataOperationRequest import org.onap.cps.spi.model.DataNode import reactor.core.publisher.Mono import spock.lang.Specification -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING -import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE -import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE +import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE +import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE class NetworkCmProxyFacadeSpec extends Specification { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyQueryServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImplSpec.groovy index d8bb559bf9..6d0cf84e20 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyQueryServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImplSpec.groovy @@ -18,10 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.impl.inventory +package org.onap.cps.ncmp.impl.data import org.onap.cps.api.CpsQueryService -import org.onap.cps.ncmp.api.impl.NetworkCmProxyQueryServiceImpl import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.DataNode import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy index f646ee5bfe..ad7d741ae2 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async +package org.onap.cps.ncmp.impl.data.async import com.fasterxml.jackson.databind.ObjectMapper import org.apache.kafka.clients.consumer.KafkaConsumer @@ -35,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers + import java.time.Duration @SpringBootTest(classes = [EventsPublisher, AsyncRestRequestResponseEventConsumer, ObjectMapper, JsonObjectMapper]) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy index b095f904a3..7e9f5089b7 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy @@ -18,16 +18,14 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async - -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent +package org.onap.cps.ncmp.impl.data.async import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder import io.cloudevents.kafka.CloudEventDeserializer import io.cloudevents.kafka.CloudEventSerializer import io.cloudevents.kafka.impl.KafkaHeaders -import io.cloudevents.core.builder.CloudEventBuilder import org.apache.kafka.clients.consumer.ConsumerRecord import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.common.header.internals.RecordHeaders @@ -42,8 +40,11 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.kafka.listener.adapter.RecordFilterStrategy import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers + import java.time.Duration +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent + @SpringBootTest(classes = [EventsPublisher, DataOperationEventConsumer, RecordFilterStrategies, JsonObjectMapper, ObjectMapper]) @Testcontainers @DirtiesContext diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/FilterStrategiesIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy index fba1f953f4..0643dbcf17 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/FilterStrategiesIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async +package org.onap.cps.ncmp.impl.data.async import io.cloudevents.core.builder.CloudEventBuilder import org.onap.cps.events.EventsPublisher @@ -32,6 +32,7 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.DirtiesContext import org.testcontainers.spock.Testcontainers import spock.util.concurrent.PollingConditions + import java.util.concurrent.TimeUnit @SpringBootTest(classes =[DataOperationEventConsumer, AsyncRestRequestResponseEventConsumer, RecordFilterStrategies, KafkaConfig]) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapperSpec.groovy index 07e9b49ff6..c7f094b1eb 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapperSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async +package org.onap.cps.ncmp.impl.data.async import org.mapstruct.factory.Mappers import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategiesSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategiesSpec.groovy index 4189a8b381..5ff2a3b55d 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategiesSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategiesSpec.groovy @@ -1,8 +1,8 @@ -package org.onap.cps.ncmp.api.impl.async +package org.onap.cps.ncmp.impl.data.async -import spock.lang.Specification import org.apache.kafka.common.header.Header import org.apache.kafka.common.header.Headers +import spock.lang.Specification import java.nio.charset.Charset diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/SerializationIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy index ee89333006..94ebc38a48 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/SerializationIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.async +package org.onap.cps.ncmp.impl.data.async import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.core.builder.CloudEventBuilder diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy index d8d04d44aa..cdf9eae40b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.utils.data.operation +package org.onap.cps.ncmp.impl.data.utils import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent @@ -26,13 +26,13 @@ import io.cloudevents.kafka.CloudEventDeserializer import io.cloudevents.kafka.impl.KafkaHeaders import org.apache.kafka.clients.consumer.KafkaConsumer import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation -import org.onap.cps.ncmp.api.impl.operations.OperationType +import org.onap.cps.ncmp.api.data.models.DataOperationRequest +import org.onap.cps.ncmp.api.data.models.OperationType import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec -import org.onap.cps.ncmp.api.models.DataOperationRequest import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent +import org.onap.cps.ncmp.impl.data.models.DmiDataOperation import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper @@ -42,12 +42,12 @@ import org.springframework.util.LinkedMultiValueMap import java.time.Duration -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY +import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent @ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext]) -class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec { +class DmiDataOperationsHelperSpec extends MessagingBaseSpec { def static clientTopic = 'my-topic-name' def static dataOperationType = 'org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent' @@ -65,7 +65,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec { and: '4 known cm handles: ch1-dmi1, ch2-dmi1, ch3-dmi2, ch4-dmi2' def yangModelCmHandles = getYangModelCmHandles() when: 'data operation request is processed' - def operationsOutPerDmiServiceName = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles) + def operationsOutPerDmiServiceName = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles) and: 'converted to a json node' def dmiDataOperationRequestBody = jsonObjectMapper.asJsonString(operationsOutPerDmiServiceName.get(serviceName)) def dmiDataOperationRequestBodyAsJsonNode = jsonObjectMapper.convertToJsonNode(dmiDataOperationRequestBody).get(operationIndex) @@ -95,7 +95,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec { and: '1 known cm handles: ch1-dmi1' def yangModelCmHandles = getYangModelCmHandlesForOneCmHandle() when: 'data operation request is processed' - def operationsOutPerDmiServiceName = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles) + def operationsOutPerDmiServiceName = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles) and: 'converted to a json node' def dmiDataOperationRequestBody = operationsOutPerDmiServiceName['dmi1'] def cmHandlesInRequestBody = dmiDataOperationRequestBody[0].cmHandles @@ -113,7 +113,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec { def dataOperationRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json') def dataOperationRequest = jsonObjectMapper.convertJsonString(dataOperationRequestJsonData, DataOperationRequest.class) when: 'data operation request is processed' - ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic, 'request-id', dataOperationRequest, yangModelCmHandles) + DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(clientTopic, 'request-id', dataOperationRequest, yangModelCmHandles) and: 'subscribed client specified topic is polled and first record is selected' def consumerRecordOut = cloudEventKafkaConsumer.poll(Duration.ofMillis(1500)).last() then: 'verify cloud compliant headers' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/AlternateIdCheckerSpec.groovy index 5be966b0fc..b086e58de8 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/AlternateIdCheckerSpec.groovy @@ -18,10 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.utils +package org.onap.cps.ncmp.impl.inventory import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.onap.cps.spi.exceptions.DataNodeNotFoundException import org.onap.cps.spi.model.DataNode diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy index 0a5b4f4ecc..1beab20def 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy @@ -28,7 +28,6 @@ import ch.qos.logback.classic.spi.ILoggingEvent import ch.qos.logback.core.read.ListAppender import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.api.CpsDataService -import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.spi.exceptions.DataNodeNotFoundException import org.onap.cps.spi.exceptions.DataValidationException diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy index 9d4d9565e3..4ff56312a1 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy @@ -24,9 +24,7 @@ package org.onap.cps.ncmp.impl.inventory import com.hazelcast.map.IMap import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.exception.DmiRequestException -import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration @@ -35,6 +33,7 @@ import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.CpsException diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy index 3f379b0b8b..4908379a4e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy @@ -26,8 +26,8 @@ import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState import spock.lang.Specification -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL class YangModelCmHandleSpec extends Specification { 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/impl/inventory/sync/DmiModelOperationsSpec.groovy index 9ab52b9467..17352977b8 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/impl/inventory/sync/DmiModelOperationsSpec.groovy @@ -19,16 +19,15 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.operations - -import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL +package org.onap.cps.ncmp.impl.inventory.sync import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.impl.config.DmiProperties +import org.onap.cps.ncmp.impl.DmiOperationsBaseSpec import org.onap.cps.spi.model.ModuleReference import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -37,10 +36,16 @@ import org.springframework.http.ResponseEntity import org.springframework.test.context.ContextConfiguration import spock.lang.Shared +import static org.onap.cps.ncmp.api.data.models.OperationType.READ +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL + @SpringBootTest @ContextConfiguration(classes = [DmiProperties, DmiModelOperations]) class DmiModelOperationsSpec extends DmiOperationsBaseSpec { + def expectedModulesUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/modules', ['cmHandleId': cmHandleId]) + def expectedModuleResourcesUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/moduleResources', ['cmHandleId': cmHandleId]) + @Shared def newModuleReferences = [new ModuleReference('mod1','A'), new ModuleReference('mod2','X')] @@ -57,9 +62,8 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { mockYangModelCmHandleRetrieval([]) and: 'a positive response from DMI service when it is called with the expected parameters' 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.synchronousPostOperationWithJsonData(MODEL, expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi + mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) then: 'the result consists of expected module references' @@ -90,7 +94,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { mockYangModelCmHandleRetrieval(dmiProperties) and: 'a positive response from DMI service when it is called with tha expected parameters' def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK) - mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules", + mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'a get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) @@ -109,7 +113,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'], [moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK) def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}' - mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", + mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables, '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) @@ -141,7 +145,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { mockYangModelCmHandleRetrieval(dmiProperties) 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.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", + mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables, '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' @@ -159,17 +163,17 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { 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.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}', - READ, NO_AUTH_HEADER) >> responseFromDmi + mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables, + '{' + 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",' + scenario | moduleSetTag || expectedModuleSetTagInRequest + 'Without module set tag' | '' || '' + 'With module set tag' | 'moduleSetTag1' || '"moduleSetTag":"moduleSetTag1",' + 'Special characters in module set tag' | 'module:set#tag$2' || '"moduleSetTag":"module:set#tag$2",' } def 'Retrieving yang resources from DMI with no module references.'() { @@ -204,5 +208,4 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'the message indicates a parsing error' exceptionThrown.message.toLowerCase().contains('parsing error') } - } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy index 52b48a366a..babe8101dd 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy @@ -26,9 +26,9 @@ import ch.qos.logback.classic.Logger import ch.qos.logback.core.read.ListAppender import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder +import org.onap.cps.ncmp.impl.data.DmiDataOperations import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState import org.onap.cps.ncmp.impl.inventory.models.CmHandleState diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy index 685a65b15a..c3a01a7393 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy @@ -23,7 +23,6 @@ package org.onap.cps.ncmp.impl.inventory.sync 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.operations.DmiModelOperations import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy index a9dbf07e2b..ee49f2f901 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy @@ -28,13 +28,13 @@ import ch.qos.logback.core.read.ListAppender import com.hazelcast.config.Config import com.hazelcast.instance.impl.HazelcastInstanceFactory import com.hazelcast.map.IMap -import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.spi.model.DataNode import org.slf4j.LoggerFactory import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy index 1adf01c551..bd7c321bc7 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm +package org.onap.cps.ncmp.impl.inventory.sync.lcm import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy index 36024b74ec..e0a552ea99 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm +package org.onap.cps.ncmp.impl.inventory.sync.lcm import org.mapstruct.factory.Mappers import org.onap.cps.ncmp.api.inventory.models.CompositeState diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy index e2bdc5d1f6..e7674761c8 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm +package org.onap.cps.ncmp.impl.inventory.sync.lcm import com.fasterxml.jackson.databind.ObjectMapper import org.apache.kafka.clients.consumer.KafkaConsumer diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy index 0b6b5a7b9f..b745734f0b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.lcm +package org.onap.cps.ncmp.impl.inventory.sync.lcm import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.events.lcm.v1.LcmEvent diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy index 7fa8b2cce9..f975d23ba2 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -21,8 +21,10 @@ package org.onap.cps.ncmp.impl.inventory.trustlevel import org.onap.cps.ncmp.api.impl.client.DmiRestClient +import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService +import reactor.core.publisher.Mono import spock.lang.Specification class DmiPluginTrustLevelWatchDogSpec extends Specification { @@ -39,7 +41,8 @@ class DmiPluginTrustLevelWatchDogSpec extends Specification { given: 'the cache has been initialised and "knows" about dmi-1' trustLevelPerDmiPlugin.put('dmi-1', dmiOldTrustLevel) and: 'dmi client returns health status #dmiHealhStatus' - mockDmiRestClient.getDmiHealthStatus('dmi-1') >> dmiHealhStatus + def urlTemplateParameters = new UrlTemplateParameters('dmi-1/actuator/health', [:]) + mockDmiRestClient.getDmiHealthStatus(urlTemplateParameters) >> Mono.just(dmiHealhStatus) when: 'dmi watch dog method runs' objectUnderTest.checkDmiAvailability() then: 'the update delegated to manager' @@ -52,5 +55,4 @@ class DmiPluginTrustLevelWatchDogSpec extends Specification { 'UP' | TrustLevel.NONE | TrustLevel.COMPLETE || 1 '' | TrustLevel.COMPLETE | TrustLevel.NONE || 1 } - } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy index 4c22dbaed9..b5bfbc165c 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy @@ -20,10 +20,10 @@ package org.onap.cps.ncmp.impl.inventory.trustlevel -import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher import spock.lang.Specification class TrustLevelManagerSpec extends Specification { @@ -32,7 +32,7 @@ class TrustLevelManagerSpec extends Specification { def trustLevelPerDmiPlugin = [:] def mockInventoryPersistence = Mock(InventoryPersistence) - def mockAttributeValueChangeEventPublisher = Mock(AvcEventPublisher) + def mockAttributeValueChangeEventPublisher = Mock(CmAvcEventPublisher) def objectUnderTest = new TrustLevelManager(trustLevelPerCmHandle, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher) def 'Initial cm handle registration'() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy index 101a29b29e..247f321834 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient +package org.onap.cps.ncmp.utils.events import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent @@ -30,13 +30,11 @@ import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent import org.onap.cps.utils.JsonObjectMapper import org.springframework.test.context.ContextConfiguration -import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent - @ContextConfiguration(classes = [CpsApplicationContext, ObjectMapper, JsonObjectMapper]) -class AvcEventPublisherSpec extends MessagingBaseSpec { +class CmAvcEventPublisherSpec extends MessagingBaseSpec { def mockEventsPublisher = Mock(EventsPublisher<CloudEvent>) - def objectUnderTest = new AvcEventPublisher(mockEventsPublisher) + def objectUnderTest = new CmAvcEventPublisher(mockEventsPublisher) def 'Publish an attribute value change event'() { given: 'the event key' @@ -52,7 +50,7 @@ class AvcEventPublisherSpec extends MessagingBaseSpec { then: 'the cloud event publisher is invoked with the correct data' 1 * mockEventsPublisher.publishCloudEvent(_, someEventKey, cloudEvent -> { - def actualAvcs = toTargetEvent(cloudEvent, AvcEvent.class).data.attributeValueChange + def actualAvcs = CloudEventMapper.toTargetEvent(cloudEvent, AvcEvent.class).data.attributeValueChange def expectedAvc = new Avc(attributeName: someAttributeName, oldAttributeValue: someOldAttributeValue, newAttributeValue: someNewAttributeValue) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/TopicValidatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy index f96502984d..26148f8709 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/TopicValidatorSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy @@ -18,10 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.utils +package org.onap.cps.ncmp.utils.events import org.onap.cps.ncmp.exceptions.InvalidTopicException -import org.onap.cps.ncmp.utils.TopicValidator import spock.lang.Specification class TopicValidatorSpec extends Specification { diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java index 56a046496e..13710dbec0 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java @@ -107,6 +107,12 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic } @Override + public Anchor getAnchor(final String dataspaceName, final String anchorName) { + final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName); + return toAnchor(anchorEntity); + } + + @Override public Collection<Anchor> getAnchors(final String dataspaceName) { final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final Collection<AnchorEntity> anchorEntities = anchorRepository.findAllByDataspace(dataspaceEntity); @@ -114,7 +120,14 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic } @Override - public Collection<Anchor> getAnchors(final String dataspaceName, final String schemaSetName) { + public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> anchorNames) { + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + return anchorRepository.findAllByDataspaceAndNameIn(dataspaceEntity, anchorNames) + .stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet()); + } + + @Override + public Collection<Anchor> getAnchorsBySchemaSetName(final String dataspaceName, final String schemaSetName) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final SchemaSetEntity schemaSetEntity = schemaSetRepository.getByDataspaceAndName( dataspaceEntity, schemaSetName); @@ -124,7 +137,8 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic } @Override - public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) { + public Collection<Anchor> getAnchorsBySchemaSetNames(final String dataspaceName, + final Collection<String> schemaSetNames) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); return anchorRepository.findAllByDataspaceAndSchemaSetNameIn(dataspaceEntity, schemaSetNames) .stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet()); @@ -137,11 +151,6 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic inputModuleNames.size()); } - @Override - public Anchor getAnchor(final String dataspaceName, final String anchorName) { - return toAnchor(getAnchorEntity(dataspaceName, anchorName)); - } - @Transactional @Override public void deleteAnchor(final String dataspaceName, final String anchorName) { diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java index a247150c15..fcb969ba30 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -37,6 +37,15 @@ public interface CpsAnchorService { void createAnchor(String dataspaceName, String schemaSetName, String anchorName); /** + * Get an anchor in the given dataspace using the anchor name. + * + * @param dataspaceName dataspace name + * @param anchorName anchor name + * @return an anchor + */ + Anchor getAnchor(String dataspaceName, String anchorName); + + /** * Read all anchors in the given dataspace. * * @param dataspaceName dataspace name @@ -45,13 +54,22 @@ public interface CpsAnchorService { Collection<Anchor> getAnchors(String dataspaceName); /** + * Read all anchors in the given dataspace with the anchor names. + * + * @param dataspaceName dataspace name + * @param anchorNames anchor names + * @return a collection of anchors + */ + Collection<Anchor> getAnchors(String dataspaceName, Collection<String> anchorNames); + + /** * Read all anchors associated with the given schema-set in the given dataspace. * * @param dataspaceName dataspace name * @param schemaSetName schema-set name * @return a collection of anchors */ - Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName); + Collection<Anchor> getAnchorsBySchemaSetName(String dataspaceName, String schemaSetName); /** * Read all anchors associated with the given schema-sets in the given dataspace. @@ -60,16 +78,7 @@ public interface CpsAnchorService { * @param schemaSetNames schema-set names * @return a collection of anchors */ - Collection<Anchor> getAnchors(String dataspaceName, Collection<String> schemaSetNames); - - /** - * Get an anchor in the given dataspace using the anchor name. - * - * @param dataspaceName dataspace name - * @param anchorName anchor name - * @return an anchor - */ - Anchor getAnchor(String dataspaceName, String anchorName); + Collection<Anchor> getAnchorsBySchemaSetNames(String dataspaceName, Collection<String> schemaSetNames); /** * Delete anchor by name in given dataspace. diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java index aa9c45d09a..c31e51b174 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -44,28 +44,36 @@ public class CpsAnchorServiceImpl implements CpsAnchorService { } @Override + public Anchor getAnchor(final String dataspaceName, final String anchorName) { + cpsValidator.validateNameCharacters(dataspaceName, anchorName); + return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName); + } + + @Override public Collection<Anchor> getAnchors(final String dataspaceName) { cpsValidator.validateNameCharacters(dataspaceName); return cpsAdminPersistenceService.getAnchors(dataspaceName); } @Override - public Collection<Anchor> getAnchors(final String dataspaceName, final String schemaSetName) { - cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); - return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetName); + public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> anchorNames) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(anchorNames); + return cpsAdminPersistenceService.getAnchors(dataspaceName, anchorNames); } @Override - public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) { - cpsValidator.validateNameCharacters(dataspaceName); - cpsValidator.validateNameCharacters(schemaSetNames); - return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetNames); + public Collection<Anchor> getAnchorsBySchemaSetName(final String dataspaceName, final String schemaSetName) { + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + return cpsAdminPersistenceService.getAnchorsBySchemaSetName(dataspaceName, schemaSetName); } @Override - public Anchor getAnchor(final String dataspaceName, final String anchorName) { - cpsValidator.validateNameCharacters(dataspaceName, anchorName); - return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName); + public Collection<Anchor> getAnchorsBySchemaSetNames(final String dataspaceName, + final Collection<String> schemaSetNames) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(schemaSetNames); + return cpsAdminPersistenceService.getAnchorsBySchemaSetNames(dataspaceName, schemaSetNames); } @Override diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java index 14b949e5ae..e6ad9a8bb8 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java @@ -97,7 +97,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { public void deleteSchemaSet(final String dataspaceName, final String schemaSetName, final CascadeDeleteAllowed cascadeDeleteAllowed) { cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); - final Collection<Anchor> anchors = cpsAnchorService.getAnchors(dataspaceName, schemaSetName); + final Collection<Anchor> anchors = cpsAnchorService.getAnchorsBySchemaSetName(dataspaceName, schemaSetName); if (!anchors.isEmpty() && isCascadeDeleteProhibited(cascadeDeleteAllowed)) { throw new SchemaSetInUseException(dataspaceName, schemaSetName); } @@ -114,8 +114,9 @@ public class CpsModuleServiceImpl implements CpsModuleService { public void deleteSchemaSetsWithCascade(final String dataspaceName, final Collection<String> schemaSetNames) { cpsValidator.validateNameCharacters(dataspaceName); cpsValidator.validateNameCharacters(schemaSetNames); - final Collection<String> anchorNames = cpsAnchorService.getAnchors(dataspaceName, schemaSetNames) - .stream().map(Anchor::getName).collect(Collectors.toSet()); + final Collection<String> anchorNames = + cpsAnchorService.getAnchorsBySchemaSetNames(dataspaceName, schemaSetNames) + .stream().map(Anchor::getName).collect(Collectors.toSet()); cpsAnchorService.deleteAnchors(dataspaceName, anchorNames); cpsModulePersistenceService.deleteSchemaSets(dataspaceName, schemaSetNames); cpsModulePersistenceService.deleteUnusedYangResourceModules(); diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java index 2b21619cb7..25830a55de 100755 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2022 Nordix Foundation. + * Copyright (C) 2020-2024 Nordix Foundation. * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -73,30 +73,48 @@ public interface CpsAdminPersistenceService { void createAnchor(String dataspaceName, String schemaSetName, String anchorName); /** - * Read all anchors associated with the given schema-set in the given dataspace. + * Get an anchor in the given dataspace using the anchor name. + * + * @param dataspaceName dataspace name + * @param anchorName anchor name + * @return an anchor + */ + Anchor getAnchor(String dataspaceName, String anchorName); + + /** + * Read all anchors in the given a dataspace. * * @param dataspaceName dataspace name - * @param schemaSetName schema-set name * @return a collection of anchors */ - Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName); + Collection<Anchor> getAnchors(String dataspaceName); /** - * Read all anchors associated with multiple schema-sets in the given dataspace. + * Read all anchors in the given dataspace with the anchor names. * - * @param dataspaceName dataspace name - * @param schemaSetNames schema-set names + * @param dataspaceName dataspace name + * @param anchorNames anchor names * @return a collection of anchors */ - Collection<Anchor> getAnchors(String dataspaceName, Collection<String> schemaSetNames); + Collection<Anchor> getAnchors(String dataspaceName, Collection<String> anchorNames); /** - * Read all anchors in the given a dataspace. + * Read all anchors associated with the given schema-set in the given dataspace. * * @param dataspaceName dataspace name + * @param schemaSetName schema-set name * @return a collection of anchors */ - Collection<Anchor> getAnchors(String dataspaceName); + Collection<Anchor> getAnchorsBySchemaSetName(String dataspaceName, String schemaSetName); + + /** + * Read all anchors associated with multiple schema-sets in the given dataspace. + * + * @param dataspaceName dataspace name + * @param schemaSetNames schema-set names + * @return a collection of anchors + */ + Collection<Anchor> getAnchorsBySchemaSetNames(String dataspaceName, Collection<String> schemaSetNames); /** * Query anchor names for the given module names in the provided dataspace. @@ -110,15 +128,6 @@ public interface CpsAdminPersistenceService { Collection<String> queryAnchorNames(String dataspaceName, Collection<String> moduleNames); /** - * Get an anchor in the given dataspace using the anchor name. - * - * @param dataspaceName dataspace name - * @param anchorName anchor name - * @return an anchor - */ - Anchor getAnchor(String dataspaceName, String anchorName); - - /** * Delete anchor by name in given dataspace. * * @param dataspaceName dataspace name diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy index c7865386bc..e58a5024b5 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -59,9 +59,9 @@ class CpsAnchorServiceImplSpec extends Specification { def 'Retrieve all anchors for schema-set.'() { given: 'that anchor is associated with the dataspace and schemaset' def anchors = [new Anchor()] - mockCpsAdminPersistenceService.getAnchors('someDataspace', 'someSchemaSet') >> anchors + mockCpsAdminPersistenceService.getAnchorsBySchemaSetName('someDataspace', 'someSchemaSet') >> anchors when: 'get anchors is called for a dataspace name and schema set name' - def result = objectUnderTest.getAnchors('someDataspace', 'someSchemaSet') + def result = objectUnderTest.getAnchorsBySchemaSetName('someDataspace', 'someSchemaSet') then: 'the collection provided by persistence service is returned as result' result == anchors and: 'the CpsValidator is called on the dataspaceName, schemaSetName' @@ -71,9 +71,9 @@ class CpsAnchorServiceImplSpec extends Specification { def 'Retrieve all anchors for multiple schema-sets.'() { given: 'that anchor is associated with the dataspace and schemasets' def anchors = [new Anchor(), new Anchor()] - mockCpsAdminPersistenceService.getAnchors('someDataspace', _ as Collection<String>) >> anchors + mockCpsAdminPersistenceService.getAnchorsBySchemaSetNames('someDataspace', _ as Collection<String>) >> anchors when: 'get anchors is called for a dataspace name and schema set names' - def result = objectUnderTest.getAnchors('someDataspace', ['schemaSet1', 'schemaSet2']) + def result = objectUnderTest.getAnchorsBySchemaSetNames('someDataspace', ['schemaSet1', 'schemaSet2']) then: 'the collection provided by persistence service is returned as result' result == anchors and: 'the CpsValidator is called on the dataspace name and schema-set names' @@ -93,6 +93,21 @@ class CpsAnchorServiceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someAnchor') } + def 'Retrieve multiple anchors for dataspace and provided anchor names.'() { + given: 'multiple anchors names to get' + def anchorNames = ['anchor1', 'anchor2'] + and: 'that anchors are associated with the dataspace and anchor names' + def anchors = [new Anchor(), new Anchor()] + mockCpsAdminPersistenceService.getAnchors('someDataspace', anchorNames) >> anchors + when: 'get anchors is called for a dataspace name and anchor names' + def result = objectUnderTest.getAnchors('someDataspace', anchorNames) + then: 'the collection provided by persistence service is returned as result' + result == anchors + and: 'the CpsValidator is called on the dataspace name and anchor names' + 1 * mockCpsValidator.validateNameCharacters('someDataspace') + 1 * mockCpsValidator.validateNameCharacters(anchorNames) + } + def 'Delete anchor.'() { when: 'delete anchor is invoked' objectUnderTest.deleteAnchor('someDataspace','someAnchor') @@ -105,15 +120,17 @@ class CpsAnchorServiceImplSpec extends Specification { } def 'Delete multiple anchors.'() { + given: 'multiple anchors to delete' + def anchorNames = ['anchor1', 'anchor2'] when: 'delete anchors is invoked' - objectUnderTest.deleteAnchors('someDataspace', ['anchor1', 'anchor2']) + objectUnderTest.deleteAnchors('someDataspace', anchorNames) then: 'delete data nodes is invoked on the data service with expected parameters' - 1 * mockCpsDataPersistenceService.deleteDataNodes('someDataspace', _ as Collection<String>) + 1 * mockCpsDataPersistenceService.deleteDataNodes('someDataspace', anchorNames) and: 'the persistence service method is invoked with same parameters to delete anchor' - 1 * mockCpsAdminPersistenceService.deleteAnchors('someDataspace',_ as Collection<String>) + 1 * mockCpsAdminPersistenceService.deleteAnchors('someDataspace', anchorNames) and: 'the CpsValidator is called on the dataspace name and anchor names' 1 * mockCpsValidator.validateNameCharacters('someDataspace') - 1 * mockCpsValidator.validateNameCharacters(_) + 1 * mockCpsValidator.validateNameCharacters(anchorNames) } def 'Query all anchor identifiers for a dataspace and module names.'() { 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 edf25715b3..4e5807ec84 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 @@ -55,6 +55,8 @@ import spock.lang.Shared import spock.lang.Specification import java.time.OffsetDateTime +import static org.onap.cps.events.model.Data.Operation.DELETE + class CpsDataServiceImplSpec extends Specification { def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) def mockCpsAnchorService = Mock(CpsAnchorService) @@ -489,15 +491,19 @@ class CpsDataServiceImplSpec extends Specification { def 'Delete all data nodes for given dataspace and multiple anchors.'() { given: 'schema set for given anchors and dataspace references test tree model' setupSchemaSetMocks('test-tree.yang') - mockCpsAnchorService.getAnchors(dataspaceName, ['anchor1', 'anchor2']) >> - [new Anchor(name: 'anchor1', dataspaceName: dataspaceName), - new Anchor(name: 'anchor2', dataspaceName: dataspaceName)] + def anchor1 = new Anchor(name: 'anchor1', dataspaceName: dataspaceName) + def anchor2 = new Anchor(name: 'anchor2', dataspaceName: dataspaceName) + mockCpsAnchorService.getAnchors(dataspaceName, ['anchor1', 'anchor2']) >> [anchor1, anchor2] when: 'delete data node method is invoked with correct parameters' objectUnderTest.deleteDataNodes(dataspaceName, ['anchor1', 'anchor2'], observedTimestamp) then: 'the CpsValidator is called on the dataspace name and the anchor names' - 2 * mockCpsValidator.validateNameCharacters(_) + 1 * mockCpsValidator.validateNameCharacters(dataspaceName) + 1 * mockCpsValidator.validateNameCharacters(['anchor1', 'anchor2']) and: 'the persistence service method is invoked with the correct parameters' 1 * mockCpsDataPersistenceService.deleteDataNodes(dataspaceName, _ as Collection<String>) + and: 'a data update event is sent for each anchor' + 1 * mockDataUpdateEventsService.publishCpsDataUpdateEvent(anchor1, '/', DELETE, observedTimestamp) + 1 * mockDataUpdateEventsService.publishCpsDataUpdateEvent(anchor2, '/', DELETE, observedTimestamp) } def 'Start session.'() { diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy index 0bad0de6ac..ad8c54bf27 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy @@ -134,7 +134,7 @@ class CpsModuleServiceImplSpec extends Specification { def 'Delete schema-set when cascade is allowed.'() { given: '#numberOfAnchors anchors are associated with schemaset' def associatedAnchors = createAnchors(numberOfAnchors) - mockCpsAnchorService.getAnchors('my-dataspace', 'my-schemaset') >> associatedAnchors + mockCpsAnchorService.getAnchorsBySchemaSetName('my-dataspace', 'my-schemaset') >> associatedAnchors when: 'schema set deletion is requested with cascade allowed' objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_ALLOWED) then: 'anchor deletion is called #numberOfAnchors times' @@ -153,7 +153,7 @@ class CpsModuleServiceImplSpec extends Specification { def 'Delete schema-set when cascade is prohibited.'() { given: 'no anchors are associated with schemaset' - mockCpsAnchorService.getAnchors('my-dataspace', 'my-schemaset') >> Collections.emptyList() + mockCpsAnchorService.getAnchorsBySchemaSetName('my-dataspace', 'my-schemaset') >> Collections.emptyList() when: 'schema set deletion is requested with cascade allowed' objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_PROHIBITED) then: 'no anchors are deleted' @@ -170,7 +170,7 @@ class CpsModuleServiceImplSpec extends Specification { def 'Delete schema-set when cascade is prohibited and schema-set has anchors.'() { given: '2 anchors are associated with schemaset' - mockCpsAnchorService.getAnchors('my-dataspace', 'my-schemaset') >> createAnchors(2) + mockCpsAnchorService.getAnchorsBySchemaSetName('my-dataspace', 'my-schemaset') >> createAnchors(2) when: 'schema set deletion is requested with cascade allowed' objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_PROHIBITED) then: 'Schema-Set in Use exception is thrown' @@ -179,7 +179,7 @@ class CpsModuleServiceImplSpec extends Specification { def 'Delete multiple schema-sets when cascade is allowed.'() { given: '#numberOfAnchors anchors are associated with each schemaset' - mockCpsAnchorService.getAnchors('my-dataspace', ['my-schemaset1', 'my-schemaset2']) >> createAnchors(numberOfAnchors * 2) + mockCpsAnchorService.getAnchorsBySchemaSetNames('my-dataspace', ['my-schemaset1', 'my-schemaset2']) >> createAnchors(numberOfAnchors * 2) when: 'schema set deletion is requested with cascade allowed' objectUnderTest.deleteSchemaSetsWithCascade('my-dataspace', ['my-schemaset1', 'my-schemaset2']) then: 'anchor deletion is called #numberOfAnchors times' diff --git a/docs/api/swagger/policy-executor/openapi.yaml b/docs/api/swagger/policy-executor/openapi.yaml new file mode 100644 index 0000000000..868f2da810 --- /dev/null +++ b/docs/api/swagger/policy-executor/openapi.yaml @@ -0,0 +1,214 @@ +# ============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========================================================= + +openapi: 3.0.3 +info: + title: Policy Executor + description: "Allows NCMP to execute a policy defined by a third party implementation before proceeding with an operation" + version: 1.0.0 +servers: + - url: /policy-executor +tags: + - name: policy-executor + description: "Execute all your policies" +paths: + /policy-executor/api/v1/{action}: + post: + description: "Fire a Policy action" + operationId: executePolicyAction + parameters: + - $ref: '#/components/parameters/actionInPath' + requestBody: + required: true + description: "The action request body" + content: + application/3gpp-json-patch+json: + schema: + $ref: '#/components/schemas/PolicyExecutionRequest' + tags: + - policy-executor + responses: + '200': + description: "Successful policy execution" + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyExecutionResponse' + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + +components: + securitySchemes: + bearerAuth: + type: http + description: "Bearer token (from client that called CPS-NCMP),used by policies to identify the client" + scheme: bearer + schemas: + ErrorMessage: + type: object + title: Error + properties: + status: + type: string + message: + type: string + details: + type: string + + Payload: + type: object + properties: + targetFdn: + type: string + description: "The complete FDN (Fully Distinguished Name) for the element to be changed" + example: "/Subnetwork=Ireland/MeContext=Athlone/ManagedElement=Athlone/SomeFunction=1/Cell=12" + cmHandleId: + type: string + description: "The CM handle ID (optional)" + example: "F811AF64F5146DFC545EC60B73DE948E" + resourceIdentifier: + type: string + description: "The resource identifier (optional)" + example: "ManagedElement=Athlone/SomeFunction=1/Cell=12" + cmChangeRequest: + type: object + description: "The content of the change to be made" + example: '{"Cell":[{"id":"Cell-id","attributes":{"administrativeState":"UNLOCKED"}}]}' + required: + - targetFdn + - cmChangeRequest + + PolicyExecutionRequest: + type: object + properties: + payloadType: + type: string + description: "The type of payload. Currently supported options: 'CM_Write'" + example: "CM_Write" + decisionType: + type: string + description: "The type of decision. Currently supported options: 'Allow'" + example: "Allow" + payload: + type: array + items: + $ref: '#/components/schemas/Payload' + required: + - payloadType + - decisionType + - payload + + PolicyExecutionResponse: + type: object + properties: + decisionId: + type: string + description: "Unique ID for the decision (for auditing purposes)" + example: "550e8400-e29b-41d4-a716-446655440000" + decision: + type: string + description: "The decision outcome. Currently supported values: 'Allow','Deny'" + example: "Deny" + message: + type: string + description: "Additional information regarding the decision outcome" + example: "Object locked due to recent change" + required: + - decisionId + - decision + - message + + responses: + NotFound: + description: "The specified resource was not found" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 404 + message: "Resource Not Found" + details: "The requested resource is not found" + Unauthorized: + description: "Unauthorized request" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: "Unauthorized request" + details: "This request is unauthorized" + Forbidden: + description: "Request forbidden" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: "Request Forbidden" + details: "This request is forbidden" + BadRequest: + description: "Bad request" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 400 + message: "Bad Request" + details: "The provided request is not valid" + + InternalServerError: + description: "Internal server error" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 500 + message: "Internal Server Error" + details: "Internal server error occurred" + + NotImplemented: + description: "Method not (yet) implemented" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 501 + message: "Not Implemented" + details: "Method not implemented" + + parameters: + actionInPath: + name: action + in: path + description: "The policy action. Currently supported options: 'Execute'" + required: true + schema: + type: string + example: "Execute" +security: + - bearerAuth: [] diff --git a/docs/design.rst b/docs/design.rst index af1f5abd4a..52f977a99a 100644 --- a/docs/design.rst +++ b/docs/design.rst @@ -60,11 +60,20 @@ and CPS-NCMP-Inventory using the drop down table in the top right: Consumed APIs ============= -CPS Core uses API's from the following ONAP components +DMI-Plugin +---------- -* DMI-Plugin: REST based interface which is used to provide integration - and allow the DMI registry API's have access to the corresponding NCMP API's within CPS Core. - More information on the DMI-Plugins offered APIs can be found on the :ref:`DMI-Plugin's Design Page <onap-cps-ncmp-dmi-plugin:design>`. +DMI-Plugin is a REST based interface which is used to provide integration +and allow the DMI registry API's have access to the corresponding NCMP API's within CPS Core. +More information on the DMI-Plugins offered APIs can be found on the :ref:`DMI-Plugin's Design Page <onap-cps-ncmp-dmi-plugin:design>`. + +Policy-Executor +--------------- + +.. toctree:: + :maxdepth: 1 + + policy-executor.rst CPS Path ======== diff --git a/docs/policy-executor.rst b/docs/policy-executor.rst new file mode 100644 index 0000000000..b934a579b1 --- /dev/null +++ b/docs/policy-executor.rst @@ -0,0 +1,23 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. http://creativecommons.org/licenses/by/4.0 +.. Copyright (C) 2024 Nordix Foundation + +.. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING +.. _policy_executor: + + +Policy Executor +############### + +.. toctree:: + :maxdepth: 1 + +Introduction +============ + +Work In Progress: This feature is not yet completed and does not affect current NCMP functionality. + +Consumed APIs +------------- + +:download:`Policy Executor OpenApi Specification <api/swagger/policy-executor/openapi.yaml>` diff --git a/docs/release-notes.rst b/docs/release-notes.rst index e14a725f72..ce2c028076 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -39,10 +39,12 @@ Release Data Bug Fixes --------- 3.5.1 + - `CPS-2302 <https://jira.onap.org/browse/CPS-2302>`_ Fix handling of special characters in moduleSetTag. Features -------- 3.5.1 + - `CPS-2121 <https://jira.onap.org/browse/CPS-2121>`_ Enabled http client prometheus metrics and manage high cardinality using URL template. Version: 3.5.0 ============== 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 34df33357e..6b38936200 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 @@ -29,11 +29,11 @@ import org.onap.cps.api.CpsModuleService import org.onap.cps.api.CpsQueryService import org.onap.cps.integration.DatabaseTestContainer import org.onap.cps.integration.KafkaTestContainer -import org.onap.cps.ncmp.api.NetworkCmProxyQueryService -import org.onap.cps.ncmp.api.impl.NetworkCmProxyFacade import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade +import org.onap.cps.ncmp.impl.data.NetworkCmProxyQueryService import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService import org.onap.cps.ncmp.impl.inventory.models.CmHandleState @@ -133,8 +133,9 @@ abstract class CpsIntegrationSpecBase extends Specification { static NO_MODULE_SET_TAG = '' static GENERAL_TEST_DATASPACE = 'generalTestDataspace' static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet' + static MODULE_SYNC_WAIT_TIME_IN_SECONDS = 2 - def static initialized = false + static initialized = false def now = OffsetDateTime.now() def setup() { @@ -218,8 +219,7 @@ abstract class CpsIntegrationSpecBase extends Specification { def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag) { def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag) networkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate])) - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - new PollingConditions().within(3, () -> { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { CmHandleState.READY == networkCmProxyInventoryFacade.getCmHandleCompositeState(cmHandleId).cmHandleState }) } 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 index 6676cb74c2..e77815f5ec 100644 --- 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 @@ -22,11 +22,11 @@ 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.HttpHeaders import org.springframework.http.HttpStatus import org.springframework.http.MediaType @@ -53,25 +53,40 @@ class DmiDispatcher extends Dispatcher { static final MODULE_RESOURCES_RESPONSE_TEMPLATE = readResourceDataFile('mock-dmi-responses/moduleResourcesTemplate.json') def isAvailable = true - Map<String, List<String>> moduleNamesPerCmHandleId = [:] + def lastAuthHeaderReceived @Override MockResponse dispatch(RecordedRequest request) { if (!isAvailable) { - return new MockResponse().setResponseCode(HttpStatus.SERVICE_UNAVAILABLE.value()) + return mockResponse(HttpStatus.SERVICE_UNAVAILABLE) } + if (request.path == '/actuator/health') { + return mockResponseWithBody(HttpStatus.OK, '{"status":"UP"}') + } + + lastAuthHeaderReceived = request.getHeader('Authorization') switch (request.path) { - case ~/^\/dmi\/v1\/ch\/(.*)\/modules$/: + // get module references for a CM-handle + case ~'^/dmi/v1/ch/(.*)/modules$': def cmHandleId = Matcher.lastMatcher[0][1] return getModuleReferencesResponse(cmHandleId) - case ~/^\/dmi\/v1\/ch\/(.*)\/moduleResources$/: + // get module resources for a CM-handle + case ~'^/dmi/v1/ch/(.*)/moduleResources$': def cmHandleId = Matcher.lastMatcher[0][1] return getModuleResourcesResponse(cmHandleId) + // pass-through data operation for a CM-handle + case ~'^/dmi/v1/ch/(.*)/data/ds/(.*)$': + return mockResponseWithBody(HttpStatus.OK, '{}') + + // legacy pass-through batch data operation + case ~'^/dmi/v1/data$': + return mockResponseWithBody(HttpStatus.ACCEPTED, '{}') + default: - throw new IllegalArgumentException('Mock DMI does not handle path ' + request.path) + throw new IllegalArgumentException('Mock DMI does not implement endpoint ' + request.path) } } @@ -79,14 +94,14 @@ class DmiDispatcher extends Dispatcher { def moduleReferences = '{"schemas":[' + getModuleNamesForCmHandle(cmHandleId).collect { MODULE_REFERENCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it) }.join(',') + ']}' - return mockOkResponseWithBody(moduleReferences) + return mockResponseWithBody(HttpStatus.OK, moduleReferences) } private getModuleResourcesResponse(cmHandleId) { def moduleResources = '[' + getModuleNamesForCmHandle(cmHandleId).collect { MODULE_RESOURCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it) }.join(',') + ']' - return mockOkResponseWithBody(moduleResources) + return mockResponseWithBody(HttpStatus.OK, moduleResources) } private getModuleNamesForCmHandle(cmHandleId) { @@ -96,9 +111,13 @@ class DmiDispatcher extends Dispatcher { return moduleNamesPerCmHandleId.get(cmHandleId) } - private static mockOkResponseWithBody(responseBody) { + private static mockResponse(status) { + return new MockResponse().setResponseCode(status.value()) + } + + private static mockResponseWithBody(status, responseBody) { return new MockResponse() - .setResponseCode(HttpStatus.OK.value()) + .setResponseCode(status.value()) .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) .setBody(responseBody) } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy index 3013e6ff94..26857799a1 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy @@ -63,9 +63,9 @@ class CpsAnchorServiceIntegrationSpec extends CpsIntegrationSpecBase { then: 'there are 3 anchors in the general test database' assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE).size() == 3 and: 'there are 2 anchors associated with bookstore schema set' - assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 2 + assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 2 and: 'there is 1 anchor associated with other schema set' - assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE, 'otherSchemaSet').size() == 1 + assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, 'otherSchemaSet').size() == 1 } def 'Querying anchor(name)s (depends on previous test!).'() { 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 2a35313f74..664fca82e5 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,13 +20,8 @@ package org.onap.cps.integration.functional -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 @@ -40,25 +35,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase { - def lastAuthHeaderReceived = null - def setup() { dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2'] registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG) - - 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() { @@ -75,7 +54,7 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase { .andExpect(status().is2xxSuccessful()) then: 'DMI has received request with bearer token' - lastAuthHeaderReceived == 'Bearer some-bearer-token' + assert dmiDispatcher.lastAuthHeaderReceived == 'Bearer some-bearer-token' where: 'all HTTP operations are applied' httpMethod << [GET, POST, PUT, PATCH, DELETE] @@ -91,7 +70,7 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase { .andExpect(status().is2xxSuccessful()) then: 'DMI has received request with no authorization header' - lastAuthHeaderReceived == null + assert dmiDispatcher.lastAuthHeaderReceived == null where: 'all HTTP operations are applied' httpMethod << [GET, POST, PUT, PATCH, DELETE] @@ -115,7 +94,7 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase { then: 'DMI will receive the async request with bearer token' new PollingConditions().within(3, () -> { - assert lastAuthHeaderReceived == 'Bearer some-bearer-token' + assert dmiDispatcher.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 0f442a82f1..26782708a5 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 @@ -64,11 +64,8 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase { and: 'CM-handle is initially in ADVISED state' assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState - when: 'module sync runs' - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - - then: 'CM-handle goes to READY state' - new PollingConditions().within(3, () -> { + and: 'CM-handle goes to READY state after module sync' + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState }) @@ -96,11 +93,8 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase { def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate]) objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - and: 'module sync runs' - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - then: 'CM-handle goes to LOCKED state with reason MODULE_SYNC_FAILED' - new PollingConditions().within(3, () -> { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1') assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED @@ -124,9 +118,8 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase { def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-3', moduleSetTag: 'B') objectUnderTest.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])) - then: 'the CM-handle goes to READY state after module sync' - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - new PollingConditions().within(3, () -> { + then: 'the CM-handle goes to READY state' + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState }) @@ -148,10 +141,8 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase { def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'ch-1'), new NcmpServiceCmHandle(cmHandleId: 'ch-2')] def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate) objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - and: 'module sync runs' - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'CM-handles go to LOCKED state' - new PollingConditions().within(3, () -> { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.LOCKED assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.LOCKED }) @@ -159,20 +150,18 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase { when: 'we wait for LOCKED CM handle retry time (actually just subtract 3 minutes from handles lastUpdateTime)' overrideCmHandleLastUpdateTime('ch-1', OffsetDateTime.now().minusMinutes(3)) overrideCmHandleLastUpdateTime('ch-2', OffsetDateTime.now().minusMinutes(3)) - and: 'failed CM handles are reset' - moduleSyncWatchdog.resetPreviouslyFailedCmHandles() - then: 'CM-handles are ADVISED state' - assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.ADVISED - assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.ADVISED + then: 'CM-handles go to ADVISED state' + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { + assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.ADVISED + assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.ADVISED + }) - when: 'DMI is available for retry' - dmiDispatcher.isAvailable = true - and: 'DMI will return expected modules' + when: 'DMI will return expected modules' dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']] - and: 'module sync runs' - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() + and: 'DMI is available for retry' + dmiDispatcher.isAvailable = true then: 'CM-handles go to READY state' - new PollingConditions().within(3, () -> { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.READY assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.READY }) 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 72e798335a..3a08cfd0c6 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 @@ -62,14 +62,11 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase { 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().eventually { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState - } + }) and: 'the CM-handle has expected moduleSetTag' assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag @@ -107,14 +104,10 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase { then: 'registration gives successful response' assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)] - when: 'module sync runs' - moduleSyncWatchdog.resetPreviouslyFailedCmHandles() - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - - then: 'CM-handle goes to READY state' - new PollingConditions().eventually { + and: 'CM-handle goes to READY state' + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState - } + }) and: 'the CM-handle has expected moduleSetTag' assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag @@ -167,16 +160,12 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase { objectUnderTest.updateDmiRegistrationAndSyncModule( new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade)) - and: 'module sync runs' - moduleSyncWatchdog.resetPreviouslyFailedCmHandles() - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED' - new PollingConditions(timeout: 3).eventually { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { 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 1f0032ac66..49a4b4d60b 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 @@ -20,31 +20,31 @@ 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; +import org.onap.cps.integration.base.CpsIntegrationSpecBase +import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService +import org.springframework.beans.factory.annotation.Autowired + +import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase { @Autowired - CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService; + CmSubscriptionPersistenceService cmSubscriptionPersistenceService def 'Adding a new cm notification subscription'() { given: 'there is no ongoing cm subscription for the following' def datastoreType = PASSTHROUGH_RUNNING def cmHandleId = 'ch-1' def xpath = '/x/y' - assert cmNotificationSubscriptionPersistenceService. - getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() == 0 + assert cmSubscriptionPersistenceService. + getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() == 0 when: 'we add a new cm notification subscription' - cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType,cmHandleId,xpath, + cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandleId, xpath, 'subId-1') then: 'there is an ongoing cm subscription for that CM handle and xpath' - assert cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType,cmHandleId,xpath) + assert cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, xpath) and: 'only one subscription id is related to now ongoing cm subscription' - assert cmNotificationSubscriptionPersistenceService. - getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() == 1 + assert cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() == 1 } def 'Adding a cm notification subscription to the already existing cm handle but non existing xpath'() { @@ -52,18 +52,17 @@ class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase { def datastoreType = PASSTHROUGH_RUNNING def cmHandleId = 'ch-1' def existingXpath = '/x/y' - assert cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType,cmHandleId,existingXpath) + assert cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, existingXpath) and: 'a non existing cm subscription with same datastore name and cm handle but different xpath' def nonExistingXpath = '/x2/y2' - assert !cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType,cmHandleId,nonExistingXpath) + assert !cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, nonExistingXpath) when: 'a new cm notification subscription is made for the existing cm handle and non existing xpath' - cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType,cmHandleId, nonExistingXpath, + cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandleId, nonExistingXpath, 'subId-2') then: 'there is an ongoing cm subscription for that CM handle and xpath' - assert cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType,cmHandleId,nonExistingXpath) + assert cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, nonExistingXpath) and: 'only one subscription id is related to now ongoing cm subscription' - assert cmNotificationSubscriptionPersistenceService. - getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,nonExistingXpath).size() == 1 + assert cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, nonExistingXpath).size() == 1 } def 'Adding a cm notification subscription to the already existing cm handle and xpath'() { @@ -72,10 +71,10 @@ class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase { def cmHandleId = 'ch-1' def xpath = '/x/y' when: 'a new cm notification subscription is made for the SAME CM handle and xpath' - cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType,cmHandleId,xpath, + cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandleId, xpath, 'subId-3') then: 'it is added to the ongoing list of subscription ids' - def subscriptionIds = cmNotificationSubscriptionPersistenceService.getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath) + def subscriptionIds = cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath) assert subscriptionIds.size() == 2 and: 'both subscription ids exists for the CM handle and xpath' assert subscriptionIds.contains("subId-1") && subscriptionIds.contains("subId-3") @@ -88,13 +87,12 @@ class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase { def xpath = '/x/y' and: 'the number of subscribers is as follows' def originalNumberOfSubscribers = - cmNotificationSubscriptionPersistenceService.getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() + cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() when: 'a subscriber is removed' - cmNotificationSubscriptionPersistenceService.removeCmNotificationSubscription(datastoreType,cmHandleId,xpath,'subId-3') + cmSubscriptionPersistenceService.removeCmSubscription(datastoreType, cmHandleId, xpath, 'subId-3') then: 'the number of subscribers is reduced by 1' - def updatedNumberOfSubscribers = - cmNotificationSubscriptionPersistenceService.getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() - assert updatedNumberOfSubscribers == originalNumberOfSubscribers-1 + def updatedNumberOfSubscribers = cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() + assert updatedNumberOfSubscribers == originalNumberOfSubscribers - 1 } def 'Removing the LAST cm notification subscriber for a given cm handle, datastore and xpath'() { @@ -103,12 +101,12 @@ class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase { def cmHandleId = 'ch-1' def xpath = '/x/y' and: 'there is only one subscriber' - assert cmNotificationSubscriptionPersistenceService - .getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() == 1 + assert cmSubscriptionPersistenceService + .getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() == 1 when: 'only subscriber is removed' - cmNotificationSubscriptionPersistenceService.removeCmNotificationSubscription(datastoreType,cmHandleId,xpath,'subId-1') + cmSubscriptionPersistenceService.removeCmSubscription(datastoreType, cmHandleId, xpath, 'subId-1') then: 'there are no longer any subscriptions for the cm handle, datastore and xpath' - assert !cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType, cmHandleId, xpath) + assert !cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, xpath) } } 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 5325f1a86e..fbfebabd7f 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 @@ -40,20 +40,18 @@ class NcmpRestApiSpec extends CpsIntegrationSpecBase { 'ch-2': ['M1', 'M2'], 'ch-3': ['M1', 'M3'] ] - and: 'a POST request is made to register the CM Handles' + when: '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)) .andExpect(status().is2xxSuccessful()) - when: 'module sync runs' - moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'CM-handles go to READY state' - new PollingConditions().eventually { + new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { (1..3).each { mvc.perform(get('/ncmp/v1/ch/ch-'+it)) .andExpect(status().isOk()) .andExpect(jsonPath('$.state.cmHandleState').value('READY')) } - } + }) } def 'Search for CM Handles by module using REST API.'() { diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy index e1235272fe..ab8ffe7c76 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -33,7 +33,7 @@ class CpsDataspaceServiceLimitsPerfTest extends CpsPerfTestBase { given: 'more than 32,766 schema set names' def schemaSetNames = (0..40_000).collect { "size-of-this-name-does-not-matter-for-limit-" + it } when: 'single get is executed to get all the anchors' - objectUnderTest.getAnchors(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetNames) + objectUnderTest.getAnchorsBySchemaSetNames(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetNames) then: 'a database exception is not thrown' noExceptionThrown() } diff --git a/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java b/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java index f8a2ecb4df..46bfcf69e6 100644 --- a/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java +++ b/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-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. @@ -20,6 +20,8 @@ package org.onap.cps.integration; +import static org.awaitility.Awaitility.await; + import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; @@ -71,7 +73,7 @@ public class ResourceMeter { static void performGcAndWait() { final long gcCountBefore = getGcCount(); System.gc(); - while (getGcCount() == gcCountBefore) {} + await().until(() -> getGcCount() > gcCountBefore); } private static long getGcCount() { @@ -94,4 +96,3 @@ public class ResourceMeter { .forEach(MemoryPoolMXBean::resetPeakUsage); } } - diff --git a/integration-test/src/test/resources/application.yml b/integration-test/src/test/resources/application.yml index 58e6287955..fefae345e6 100644 --- a/integration-test/src/test/resources/application.yml +++ b/integration-test/src/test/resources/application.yml @@ -179,9 +179,9 @@ ncmp: timers: advised-modules-sync: - sleep-time-ms: 100000 + sleep-time-ms: 1000 locked-modules-sync: - sleep-time-ms: 300000 + sleep-time-ms: 1000 cm-handle-data-sync: sleep-time-ms: 30000 subscription-forwarding: diff --git a/k6-tests/README.md b/k6-tests/README.md index e26b18609c..0fdebcfe9d 100644 --- a/k6-tests/README.md +++ b/k6-tests/README.md @@ -21,5 +21,5 @@ docker-compose -f docker-compose/docker-compose.yml --profile dmi-stub up To run an individual test from command line, use ```shell -k6 run ncmp/1-create-cmhandles.js +k6 run ncmp/ncmp-kpi.js ``` diff --git a/k6-tests/ncmp/1-create-cmhandles.js b/k6-tests/ncmp/1-create-cmhandles.js deleted file mode 100644 index 1c64ab011c..0000000000 --- a/k6-tests/ncmp/1-create-cmhandles.js +++ /dev/null @@ -1,44 +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========================================================= - */ - -import exec from 'k6/execution'; -import { TOTAL_CM_HANDLES, REGISTRATION_BATCH_SIZE, makeBatchOfCmHandleIds, makeCustomSummaryReport } from './common/utils.js'; -import { createCmHandles } from './common/cmhandle-crud.js'; - -export const options = { - vus: 1, - iterations: Math.ceil(TOTAL_CM_HANDLES / REGISTRATION_BATCH_SIZE), - thresholds: { - http_req_failed: ['rate == 0'], - http_req_duration: ['avg <= 850'], - }, -}; - -export default function () { - const batchNumber = exec.scenario.iterationInTest; - const nextBatchOfCmHandleIds = makeBatchOfCmHandleIds(REGISTRATION_BATCH_SIZE, batchNumber); - createCmHandles(nextBatchOfCmHandleIds); -} - -export function handleSummary(data) { - return { - stdout: makeCustomSummaryReport(data, options), - }; -} diff --git a/k6-tests/ncmp/11-delete-cmhandles.js b/k6-tests/ncmp/11-delete-cmhandles.js deleted file mode 100644 index 542754b5f9..0000000000 --- a/k6-tests/ncmp/11-delete-cmhandles.js +++ /dev/null @@ -1,44 +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========================================================= - */ - -import exec from 'k6/execution'; -import { TOTAL_CM_HANDLES, REGISTRATION_BATCH_SIZE, makeBatchOfCmHandleIds, makeCustomSummaryReport } from './common/utils.js'; -import { deleteCmHandles } from './common/cmhandle-crud.js'; - -export const options = { - vus: 1, - iterations: Math.ceil(TOTAL_CM_HANDLES / REGISTRATION_BATCH_SIZE), - thresholds: { - http_req_failed: ['rate == 0'], - http_req_duration: ['avg <= 1050'], - }, -}; - -export default function () { - const batchNumber = exec.scenario.iterationInTest; - const nextBatchOfCmHandleIds = makeBatchOfCmHandleIds(REGISTRATION_BATCH_SIZE, batchNumber); - deleteCmHandles(nextBatchOfCmHandleIds); -} - -export function handleSummary(data) { - return { - stdout: makeCustomSummaryReport(data, options), - }; -} diff --git a/k6-tests/ncmp/common/cmhandle-crud.js b/k6-tests/ncmp/common/cmhandle-crud.js index 0c3e116a19..6d5aff7fca 100644 --- a/k6-tests/ncmp/common/cmhandle-crud.js +++ b/k6-tests/ncmp/common/cmhandle-crud.js @@ -19,10 +19,28 @@ */ import http from 'k6/http'; -import { check, sleep, fail } from 'k6'; -import { NCMP_BASE_URL, DMI_PLUGIN_URL, TOTAL_CM_HANDLES } from './utils.js'; +import { check, sleep } from 'k6'; +import { NCMP_BASE_URL, DMI_PLUGIN_URL, TOTAL_CM_HANDLES, REGISTRATION_BATCH_SIZE, CONTENT_TYPE_JSON_PARAM, makeBatchOfCmHandleIds } from './utils.js'; +import { executeCmHandleIdSearch } from './search-base.js'; -export function createCmHandles(cmHandleIds) { +export function registerAllCmHandles() { + forEachBatchOfCmHandles(createCmHandles); + waitForAllCmHandlesToBeReady(); +} + +export function deregisterAllCmHandles() { + forEachBatchOfCmHandles(deleteCmHandles); +} + +function forEachBatchOfCmHandles(functionToExecute) { + const TOTAL_BATCHES = Math.ceil(TOTAL_CM_HANDLES / REGISTRATION_BATCH_SIZE); + for (let batchNumber = 0; batchNumber < TOTAL_BATCHES; batchNumber++) { + const nextBatchOfCmHandleIds = makeBatchOfCmHandleIds(REGISTRATION_BATCH_SIZE, batchNumber); + functionToExecute(nextBatchOfCmHandleIds); + } +} + +function createCmHandles(cmHandleIds) { const url = `${NCMP_BASE_URL}/ncmpInventory/v1/ch`; const payload = { "dmiPlugin": DMI_PLUGIN_URL, @@ -36,55 +54,34 @@ export function createCmHandles(cmHandleIds) { } })), }; - const params = { - headers: {'Content-Type': 'application/json'} - }; - const response = http.post(url, JSON.stringify(payload), params); - check(response, { - 'status equals 200': (r) => r.status === 200, - }); + const response = http.post(url, JSON.stringify(payload), CONTENT_TYPE_JSON_PARAM); + check(response, { 'create CM-handles status equals 200': (r) => r.status === 200 }); return response; } -export function deleteCmHandles(cmHandleIds) { +function deleteCmHandles(cmHandleIds) { const url = `${NCMP_BASE_URL}/ncmpInventory/v1/ch`; const payload = { "dmiPlugin": DMI_PLUGIN_URL, "removedCmHandles": cmHandleIds, }; - const params = { - headers: {'Content-Type': 'application/json'} - }; - const response = http.post(url, JSON.stringify(payload), params); - check(response, { - 'status equals 200': (r) => r.status === 200, - }); + const response = http.post(url, JSON.stringify(payload), CONTENT_TYPE_JSON_PARAM); + check(response, { 'delete CM-handles status equals 200': (r) => r.status === 200 }); return response; } -export function waitForCmHandlesToBeReady(timeOutInSeconds) { - const pollingIntervalInSeconds = 10; - const maxRetries = Math.ceil(timeOutInSeconds / pollingIntervalInSeconds); +function waitForAllCmHandlesToBeReady() { + const POLLING_INTERVAL_SECONDS = 5; let cmHandlesReady = 0; - for (let currentTry = 0; currentTry <= maxRetries; currentTry++) { - sleep(pollingIntervalInSeconds); - try { - cmHandlesReady = getNumberOfReadyCmHandles(); - } catch (error) { - console.error(`Attempt ${currentTry + 1} - Error fetching CM handles: ${error.message}`); - } - console.log(`Attempt ${currentTry + 1} - ${cmHandlesReady}/${TOTAL_CM_HANDLES} CM handles are READY`); - if (cmHandlesReady === TOTAL_CM_HANDLES) { - console.log(`All ${TOTAL_CM_HANDLES} CM handles are READY`); - return; - } - } - fail(`Timed out after ${timeOutInSeconds} seconds waiting for ${TOTAL_CM_HANDLES} CM handles to be READY`); + do { + sleep(POLLING_INTERVAL_SECONDS); + cmHandlesReady = getNumberOfReadyCmHandles(); + console.log(`${cmHandlesReady}/${TOTAL_CM_HANDLES} CM handles are READY`); + } while (cmHandlesReady < TOTAL_CM_HANDLES); } function getNumberOfReadyCmHandles() { - const endpointUrl = `${NCMP_BASE_URL}/cps/api/v2/dataspaces/NCMP-Admin/anchors/ncmp-dmi-registry/node?xpath=/dmi-registry&descendants=all`; - const jsonData = http.get(endpointUrl).json(); - const cmHandles = jsonData[0]["dmi-reg:dmi-registry"]["cm-handles"]; - return cmHandles.filter(cmhandle => cmhandle['state']['cm-handle-state'] === 'READY').length; + const response = executeCmHandleIdSearch('readyCmHandles'); + const arrayOfCmHandleIds = JSON.parse(response.body); + return arrayOfCmHandleIds.length; } diff --git a/k6-tests/ncmp/common/passthrough-read.js b/k6-tests/ncmp/common/passthrough-read.js index e4e937c9c0..89ed15af79 100644 --- a/k6-tests/ncmp/common/passthrough-read.js +++ b/k6-tests/ncmp/common/passthrough-read.js @@ -19,7 +19,6 @@ */ import http from 'k6/http'; -import { check } from 'k6'; import { NCMP_BASE_URL, getRandomCmHandleId } from './utils.js'; export function passthroughRead() { @@ -29,8 +28,5 @@ export function passthroughRead() { const datastoreName = 'ncmp-datastore:passthrough-operational'; const url = `${NCMP_BASE_URL}/ncmp/v1/ch/${cmHandleId}/data/ds/${datastoreName}?resourceIdentifier=${resourceIdentifier}&include-descendants=${includeDescendants}` const response = http.get(url); - check(response, { - 'status equals 200': (r) => r.status === 200, - }); return response; } diff --git a/k6-tests/ncmp/common/search-base.js b/k6-tests/ncmp/common/search-base.js index 816bacac56..bc964856af 100644 --- a/k6-tests/ncmp/common/search-base.js +++ b/k6-tests/ncmp/common/search-base.js @@ -19,8 +19,7 @@ */ import http from 'k6/http'; -import { check } from 'k6'; -import { NCMP_BASE_URL, TOTAL_CM_HANDLES } from './utils.js'; +import { NCMP_BASE_URL, CONTENT_TYPE_JSON_PARAM } from './utils.js'; const SEARCH_PARAMETERS_PER_SCENARIO = { 'module': { @@ -30,30 +29,29 @@ const SEARCH_PARAMETERS_PER_SCENARIO = { 'conditionParameters': [{'moduleName': 'ietf-yang-types-1'}] } ] + }, + 'readyCmHandles': { + 'cmHandleQueryParameters': [ + { + 'conditionName': 'cmHandleWithCpsPath', + 'conditionParameters': [{'cpsPath': '//state[@cm-handle-state="READY"]'}] + } + ] } }; export function executeCmHandleSearch(scenario) { - executeSearchRequest('searches', scenario); + return executeSearchRequest('searches', scenario); } export function executeCmHandleIdSearch(scenario) { - executeSearchRequest('id-searches', scenario); + return executeSearchRequest('id-searches', scenario); } function executeSearchRequest(searchType, scenario) { const searchParameters = SEARCH_PARAMETERS_PER_SCENARIO[scenario]; const payload = JSON.stringify(searchParameters); const url = `${NCMP_BASE_URL}/ncmp/v1/ch/${searchType}`; - const params = { - headers: {'Content-Type': 'application/json'} - }; - const response = http.post(url, payload, params); - check(response, { - 'status equals 200': (r) => r.status === 200, - }); - const responseData = JSON.parse(response.body); - check(responseData, { - 'returned list has expected CM-handles': (arr) => arr.length === TOTAL_CM_HANDLES, - }); + const response = http.post(url, payload, CONTENT_TYPE_JSON_PARAM); + return response; } diff --git a/k6-tests/ncmp/common/utils.js b/k6-tests/ncmp/common/utils.js index 55ef60a2e7..54b4c3a099 100644 --- a/k6-tests/ncmp/common/utils.js +++ b/k6-tests/ncmp/common/utils.js @@ -20,8 +20,17 @@ export const NCMP_BASE_URL = 'http://localhost:8883'; export const DMI_PLUGIN_URL = 'http://ncmp-dmi-plugin-demo-and-csit-stub:8092'; -export const TOTAL_CM_HANDLES = Number(__ENV.TOTAL_CM_HANDLES) || 20000; -export const REGISTRATION_BATCH_SIZE = Number(__ENV.REGISTRATION_BATCH_SIZE) || 100; +export const TOTAL_CM_HANDLES = 20000; +export const REGISTRATION_BATCH_SIZE = 100; +export const CONTENT_TYPE_JSON_PARAM = { headers: {'Content-Type': 'application/json'} }; + +export function recordTimeInSeconds(functionToExecute) { + const startTimeInMillis = Date.now(); + functionToExecute(); + const endTimeInMillis = Date.now(); + const totalTimeInSeconds = (endTimeInMillis - startTimeInMillis) / 1000.0; + return totalTimeInSeconds; +} /** * Generates a batch of CM-handle IDs based on batch size and number. @@ -33,7 +42,7 @@ export function makeBatchOfCmHandleIds(batchSize, batchNumber) { const batchOfIds = []; const startIndex = 1 + batchNumber * batchSize; for (let i = 0; i < batchSize; i++) { - let cmHandleId = 'ch-' + (startIndex + i); + let cmHandleId = `ch-${startIndex + i}`; batchOfIds.push(cmHandleId); } return batchOfIds; @@ -43,22 +52,20 @@ export function getRandomCmHandleId() { return `ch-${Math.floor(Math.random() * TOTAL_CM_HANDLES) + 1}`; } -function removeBracketsAndQuotes(str) { - return str.replace(/\[|\]|"/g, ''); -} - export function makeCustomSummaryReport(data, options) { - const moduleName = `${__ENV.K6_MODULE_NAME}`; - let body = ``; - for (const condition in options.thresholds) { - let limit = JSON.stringify(options.thresholds[condition]) - limit = removeBracketsAndQuotes(limit) - let limitKey = limit.split(' ')[0] - const actual = Math.ceil(data.metrics[condition].values[limitKey]) - const result = data.metrics[condition].thresholds[limit].ok ? 'PASS' : 'FAIL' - const row = `${moduleName}\t${condition}\t${limit}\t${actual}\t${result}\n`; - body += row; - } - return body; + let summaryCsv = '#,Test Name,Unit,Limit,Actual\n'; + summaryCsv += makeSummaryCsvLine(1, 'Registration of CM-handles', 'CM-handles/second', 'cmhandles_created_per_second', data, options); + summaryCsv += makeSummaryCsvLine(2, 'De-registration of CM-handles', 'CM-handles/second', 'cmhandles_deleted_per_second', data, options); + summaryCsv += makeSummaryCsvLine(3, 'CM-handle ID search with Module filter', 'milliseconds', 'http_req_duration{scenario:id_search_module}', data, options); + summaryCsv += makeSummaryCsvLine(4, 'CM-handle search with Module filter', 'milliseconds', 'http_req_duration{scenario:cm_search_module}', data, options); + summaryCsv += makeSummaryCsvLine(5, 'Synchronous single CM-handle pass-through read', 'milliseconds', 'http_req_duration{scenario:passthrough_read}', data, options); + return summaryCsv; } +function makeSummaryCsvLine(testCase, testName, unit, thresholdInK6, data, options) { + const thresholdArray = JSON.parse(JSON.stringify(options.thresholds[thresholdInK6])); + const thresholdString = thresholdArray[0]; + const [thresholdKey, thresholdOperator, thresholdValue] = thresholdString.split(/\s+/); + const actualValue = data.metrics[thresholdInK6].values[thresholdKey].toFixed(3); + return `${testCase},${testName},${unit},${thresholdValue},${actualValue}\n`; +} diff --git a/k6-tests/ncmp/10-mixed-load-test.js b/k6-tests/ncmp/ncmp-kpi.js index a6b5b01e22..91a38d99ce 100644 --- a/k6-tests/ncmp/10-mixed-load-test.js +++ b/k6-tests/ncmp/ncmp-kpi.js @@ -18,13 +18,21 @@ * ============LICENSE_END========================================================= */ -import { makeCustomSummaryReport } from './common/utils.js' +import { check } from 'k6'; +import { Gauge } from 'k6/metrics'; +import { TOTAL_CM_HANDLES, makeCustomSummaryReport, recordTimeInSeconds } from './common/utils.js'; +import { registerAllCmHandles, deregisterAllCmHandles } from './common/cmhandle-crud.js'; import { executeCmHandleSearch, executeCmHandleIdSearch } from './common/search-base.js'; import { passthroughRead } from './common/passthrough-read.js'; +let cmHandlesCreatedPerSecondGauge = new Gauge('cmhandles_created_per_second'); +let cmHandlesDeletedPerSecondGauge = new Gauge('cmhandles_deleted_per_second'); + const DURATION = '15m'; export const options = { + setupTimeout: '6m', + teardownTimeout: '6m', scenarios: { passthrough_read: { executor: 'constant-vus', @@ -45,8 +53,9 @@ export const options = { duration: DURATION, }, }, - thresholds: { + 'cmhandles_created_per_second': ['value >= 22'], + 'cmhandles_deleted_per_second': ['value >= 22'], 'http_req_failed{scenario:passthrough_read}': ['rate == 0'], 'http_req_failed{scenario:id_search_module}': ['rate == 0'], 'http_req_failed{scenario:cm_search_module}': ['rate == 0'], @@ -56,16 +65,31 @@ export const options = { }, }; +export function setup() { + const totalRegistrationTimeInSeconds = recordTimeInSeconds(registerAllCmHandles); + cmHandlesCreatedPerSecondGauge.add(TOTAL_CM_HANDLES / totalRegistrationTimeInSeconds); +} + +export function teardown() { + const totalDeregistrationTimeInSeconds = recordTimeInSeconds(deregisterAllCmHandles); + cmHandlesDeletedPerSecondGauge.add(TOTAL_CM_HANDLES / totalDeregistrationTimeInSeconds); +} + export function passthrough_read() { - passthroughRead(); + const response = passthroughRead(); + check(response, { 'passthrough read status equals 200': (r) => r.status === 200 }); } export function id_search_module() { - executeCmHandleIdSearch('module'); + const response = executeCmHandleIdSearch('module'); + check(response, { 'module ID search status equals 200': (r) => r.status === 200 }); + check(JSON.parse(response.body), { 'module ID search returned expected CM-handles': (arr) => arr.length === TOTAL_CM_HANDLES }); } export function cm_search_module() { - executeCmHandleSearch('module'); + const response = executeCmHandleSearch('module'); + check(response, { 'module search status equals 200': (r) => r.status === 200 }); + check(JSON.parse(response.body), { 'module search returned expected CM-handles': (arr) => arr.length === TOTAL_CM_HANDLES }); } export function handleSummary(data) { diff --git a/k6-tests/ncmp/run-all-tests.sh b/k6-tests/ncmp/run-all-tests.sh index bf6370901f..2db32ecd76 100755 --- a/k6-tests/ncmp/run-all-tests.sh +++ b/k6-tests/ncmp/run-all-tests.sh @@ -15,29 +15,36 @@ # limitations under the License. # -ALL_TEST_SCRIPTS=( \ -1-create-cmhandles.js \ -2-wait-for-cmhandles-to-be-ready.js \ -10-mixed-load-test.js \ -11-delete-cmhandles.js \ -) +pushd "$(dirname "$0")" >/dev/null || exit 1 -pushd "$(dirname "$0")" || exit 1 +number_of_failures=0 +echo "Running K6 performance tests..." +k6 --quiet run ncmp-kpi.js > summary.csv || ((number_of_failures++)) -printf "Test Case\tCondition\tLimit\tActual\tResult\n" > summary.log +if [ -f summary.csv ]; then -number_of_failures=0 -for test_script in "${ALL_TEST_SCRIPTS[@]}"; do - echo "k6 run $test_script" - k6 --quiet run -e K6_MODULE_NAME="$test_script" "$test_script" >> summary.log || ((number_of_failures++)) -done + # Output raw CSV for plotting job + echo '-- BEGIN CSV REPORT' + cat summary.csv + echo '-- END CSV REPORT' + echo + + # Output human-readable report + echo '####################################################################################################' + echo '## K 6 P E R F O R M A N C E T E S T R E S U L T S ##' + echo '####################################################################################################' + column -t -s, summary.csv + echo + + # Clean up + rm -f summary.csv -echo '##############################################################################################################################' -echo '## K 6 P E R F O R M A N C E T E S T R E S U L T S ##' -echo '##############################################################################################################################' -awk -F$'\t' '{printf "%-40s%-50s%-20s%-10s%-6s\n", $1, $2, $3, $4, $5}' summary.log +else + echo "Error: Failed to generate summary.csv" >&2 + ((number_of_failures++)) +fi -popd || exit 1 +popd >/dev/null || exit 1 echo "NCMP TEST FAILURES: $number_of_failures" exit $number_of_failures |